我下面有一个C ++代码,
#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;
}
在这段代码中,我想将整数转换为浮点数。但是对于某些输入,它给出了一些精度误差。所以我在打印结果之前添加了1e-9
。但是它仍然显示所有输入的错误,实际上我在结果中得到了一些额外的数字。其中一些在下面给出,
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. :)
有没有办法避免或摆脱这些错误? :)
答案 0 :(得分:2)
不,没有办法绕过它。浮点数基本上是功率为2的分数作为分母。这意味着唯一可以精确表示的非整数是(负)幂的2的倍数,即1/2的倍数,或1/16,或1/1048576的倍数,或......
现在,10有两个主要因素;因此,1/10不能表示为分数,功率为2作为分母。您将始终以舍入错误结束。通过重复除以10,你甚至会使这个稍微差一点,所以一个“解决方案”就是反复将dbl
除以10,重复保持一个单独的计数器multiplier
:
double multiplier = 1;
while (len--)
multiplier *= 10.;
dbl /= multiplier;
请注意,我并未说这会解决问题,但它可能会使事情稍微稳定一些。假设您可以精确地表示浮点数的十进制数仍然是错误的。