ontrolling the number of fractional digits after the decimal point is a common requirement in various application domains?including dialog boxes, relational databases, financial applications, SMS messages, and when processing data files. This solution shows you how to control the number of fractional digits by using familiar design techniques presented in previous 10-Minute Solutions. Along the way, I will dispel a few common myths about strings and precision.
How can you control the number of fractional digits of floating point values?
Convert the floating-point value to a string and format its textual representation.
Presenting the Problem
The inspiration for writing this article comes from a question that was recently posted on the DevX C++ Forum. The poster asked how to write a function that accepts a long double argument and converts it to a string. The resulting string should contain up to two decimal digits in the fraction part. For example, the floating-point value 123.45678 should yield the string “123.45.” Seemingly, this is a trivial programming task. However, to make this function truly useful, the design has to be flexible enough toallow the caller to specify a different number of fractional digits. In addition, the same function must handle various exceptions gracefully. For example, it should be able to cope with integral values such as 123.0 or 123.
Before we tackle this task, it’s important to remember two design maxims that hold true for every state of the art C++ code base:
- Maxim #1: Whenever you need to format a numeric value, convert the value to a string. This way, you guarantee that each digit occupies exactly one character.
- Maxim #2: When you need to convert something to a string, use the
library.
The interface of the conversion function is straightforward: the first parameter is the value that needs to be formatted. The second parameter represents the number of decimal digits that should appear after the decimal point. The latter will have a default value. The return value is of type string:
string do_fraction(long double value, int decplaces=3);
Note: The number of decimal places includes the decimal point, therefore a default value of 3 is needed for two fractional digits.
Precision and Order
Naturally, your first step is to convert the long double value to a string. Using the standard C++
To obtain the maximum number of digits that long double can represent, use the
string do_fraction(long double value, int decplaces=3){ int prec= numeric_limits::digits10; // 18 ostringstream out; out.precision(prec);//override the default out
The numeric value is now stored in str, waiting to be formatted.
Going Dotty
The formatting operation consists of locating the decimal point's position. If the number of fractional digits is higher than decplaces, do_fraction() will remove the remaining digits.
To locate the decimal point, use string::find(). Remember that STL algorithms use an agreed-upon constant to report a "value not found" condition. In the case of string, this constant is called string::npos:
char DECIMAL_POINT='.'; // use ',' in European localessize_t n=str.find(DECIMAL_POINT);if ((n!=string::npos)// is there a decimal point?{ //check the number of fractional digits}
If there's no decimal point, do_format() returns the string as is. Otherwise, do_format() checks whether the number of fractional digits is higher than decplaces. If it is, the fractional part is truncated:
size_t n=str.find(DECIMAL_POINT);if ((n!=string::npos)// is there a decimal point? &&(str.size()> n+decplaces))//is it followed by at //least decplaces digits?//write nul instead of the first digit after decplaces str[n+decplaces]=' ';
The last line of code overwrites the first superfluous fractional digit. It uses the