Double string formatting with ostringstream

I want to convert a double to a string by rounding to two decimal digits after the dot. I want 1.009 to display as "1.01" and 1.0 as "1". This is what I tried:

std::ostringstream oss;
oss << std::fixed << std::setprecision(2) << std::noshowpoint  << 1.0;

      

It outputs "1.00" even though I never set the width or even did it std::noshowpoint

. How do you achieve the desired performance?

+3


source to share


2 answers


The best decision:

inline double twodec(double n) { return floor(n * 100 + 0.5) / 100; }

oss << twodec(1.0) << ' ' << twodec(1.009);

      

Discussion

From http://www.cplusplus.com/reference/ios/fixed/ (emphasis mine)



When floatfield is set to a fixed value, float values ​​are written using fixed point notation, which means that the value is represented by exactly as many digits in the fractional part as defined by the precision field, and no exponential part.

So, "fixed" won't work.

However, the only ways I can think of to do what you want:

  • first round the number to the desired precision (i.e. floor(n * 100 + 0.5) / 100

    ), then use the default presentation (i.e., do not specify fixed or scientific or precision - if fixed

    either does scientific

    , clear them with first std::cout.unsetf(std::ios::floatfield)

    ).
  • dynamically adjusting the precision based on the maximum total number of numeric digits you want to see before and after the point (this is what the precision indicates); for this you could determine how many digits the part takes up to the decimal point (perhaps using a database of 10) and add 2
  • streaming the result to ostringstream

    , and then removing the trailing 0s and any '.' (pretty disgusting).
+5


source


This is my final solution based on Tony's answer:



template <typename T>
std::string stringForNumber( T f, int precision /* = 0 */, bool fixedWidth /*= false*/ )
{
    std::ostringstream ss;
    ss.setf(std::ios_base::fixed);
    if (precision > 0)
        ss << std::setprecision(precision);

    ss << f;
    std::string str(ss.str());
    if (!fixedWidth) // Removing trailing 0
    {
        const auto pointLocation = str.find_first_of(".,");
        if (pointLocation != std::string::npos)
        {
            const auto lastZeroPos = str.find_last_of('0');
            const auto lastNotZeroPos = str.find_last_not_of('0');
            if (lastNotZeroPos == pointLocation) // Integer number
                str.erase(pointLocation);
            else if (lastZeroPos != std::string::npos && lastNotZeroPos != std::string::npos && pointLocation < lastZeroPos && lastNotZeroPos < lastZeroPos)
            {
                str.erase(lastNotZeroPos+1);
            }
        }
    }

    return str;
}

      

+1


source







All Articles