如何在使用double和long double变量时避免C ++中的精度问题?

时间:2017-06-26 19:53:12

标签: precision

我下面有一个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. :)

有没有办法避免或摆脱这些错误? :)

1 个答案:

答案 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;

请注意,我并未说这会解决问题,但它可能会使事情稍微稳定一些。假设您可以精确地表示浮点数的十进制数仍然是错误的。