Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I format a floating point value so that it never uses exponent notation nor has trailing zeros?

According to ios_base manipulators, I basically have the choice between defaultfloat and fixed when formatting floating point numbers without exponent notation (with decimal numbers).

However, I want to choose the maximum precision which would produce a lot trailing zeros for fixed for many numbers (e.g. 1.) but avoid ever using the exponent notation. If set to defaultfloat, it will look right most of the time, unless the value is really really small, yet not 0.. In that case, the default representation switches to scientific notation on its own, which breaks the receiver of the formatted output (since it has no clue what 2.22045e-16 means.

So, how can I have my pie and eat it, too? That is, non-exponent notation without unnecessary trailing zeroes.


Note: I did not test the effect of the defaultfloat flag, since my gcc doesn't seem to implement that flag (yet), but I assume it is the default setting which applies without using any flag. I did check the fixed flag, which does behave as expected.

like image 471
bitmask Avatar asked Feb 19 '13 19:02

bitmask


1 Answers

A simple method would be something like this:

std::string float2string(double f)
{
    std::stringstream ss;

    ss << std::fixed << std::setprecision(122) << f;   // 122 is LARGE, but you may find that really tiny or really large numbers still don't work out... 

    std::string s = ss.str();

    std::string::size_type len = s.length();

    int zeros = 0;
    while(len > 1 && s[--len] == '0')
        zeros++;
    if (s[len] == '.')  // remove final '.' if number ends with '.'
        zeros++;
    s.resize(s.length()-zeros);


    return s;
}

I have given it some testing. The biggest problem is that it gives a huge number of decimals for some numbers, and things like 0.05 comes out as 0.05000000000000000277555756156289135105907917022705078125 and 0.7 becomes: 0.05000000000000000277555756156289135105907917022705078125

That's because it's not an "exact" number in binary form.

I think the solution is to calculate roughly how many digits you want in the result, by taking the number of integer digits (or floor(log(f)/log(10)+1)) and then subtracting that number from a constant, such as 17, which is the number of digits you can expect from a double. Then remove surplus zeros.

I'll leave that for the moment, as I've got some other stuff to do that I should have started on a little while ago... ;)

like image 85
Mats Petersson Avatar answered Sep 27 '22 20:09

Mats Petersson