Reputation: 191
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
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