Shah Shishir
Shah Shishir

Reputation: 191

How to avoid precision problems in C++ while using double and long double variables?

I have a C++ code below,

#include <iostream>
#include <cstdio>
#include <math.h>
using namespace std;

int main ()
{
    unsigned long long dec,len;
    long double dbl;

    while (cin >> dec)
    {
        len = log10(dec)+1;
        dbl = (long double) (dec);

        while (len--)
            dbl /= 10.0;

        dbl += 1e-9;

        printf ("%llu in int = %.20Lf in long double. :)\n",dec,dbl);
    }

    return 0;
}

In this code I wanted to convert an integer to a floating-point number. But for some inputs it gave some precision errors. So I added 1e-9 before printing the result. But still it is showing errors for all the inputs, actually I got some extra digits in the result. Some of them are given below,

stdin
1 
12 
123 
1234 
12345 
123456 
1234567 
12345678 
123456789 
1234567890

stdout
1 in int = 0.10000000100000000000 in long double. :) 
12 in int = 0.12000000100000000001 in long double. :) 
123 in int = 0.12300000100000000000 in long double. :) 
1234 in int = 0.12340000100000000000 in long double. :) 
12345 in int = 0.12345000099999999999 in long double. :) 
123456 in int = 0.12345600100000000000 in long double. :) 
1234567 in int = 0.12345670100000000000 in long double. :) 
12345678 in int = 0.12345678099999999998 in long double. :) 
123456789 in int = 0.12345679000000000001 in long double. :) 
1234567890 in int = 0.12345679000000000001 in long double. :)

Is there any way to avoid or get rid of these errors? :)

Upvotes: 0

Views: 2541

Answers (1)

cnettel
cnettel

Reputation: 1024

No, there is no way around it. A floating point number is basically a fraction with a power of 2 as the denominator. This means that the only non-integers that can be represented exactly are multiples of a (negative) power of 2, i.e. a multiple of 1/2, or of 1/16, or of 1/1048576, or...

Now, 10 has two prime factors; 2 and 5. Thus 1/10 cannot be expressed as a fractional number with a power of 2 as the denominator. You will always end up with a rounding error. By repeatedly dividing by 10, you even make this slightly worse, so one "solution" would be to rather than dividing dbl by 10 repeatedly keeping a separate counter multiplier:

double multiplier = 1;
while (len--)
   multiplier *= 10.;

dbl /= multiplier;

Note that I don't say this will solve the problem, but it might make things slightly more stable. Assuming that you can represent a decimal number exactly in floating point remains wrong.

Upvotes: 3

Related Questions