在C中用pow()处理大数计算

在C中用pow()处理大数计算,c,C,我试图用C语言计算功率(.1,-120),得到: 99999999999933861949473759386053005587311993970572806430445302254169059598080806805361692384514358883569728192512.000000 而不是10^120。有什么原因吗?提前感谢您的回复 这是由于浮点的不精确性造成的。由于数字是以二进制形式存储在内部的,double中没有足够的有效数字来准确表示该数字 例如,如果运行以下命令: printf(

我试图用C语言计算功率(.1,-120),得到:

99999999999933861949473759386053005587311993970572806430445302254169059598080806805361692384514358883569728192512.000000


而不是
10^120
。有什么原因吗?提前感谢您的回复

这是由于浮点的不精确性造成的。由于数字是以二进制形式存储在内部的,
double
中没有足够的有效数字来准确表示该数字

例如,如果运行以下命令:

printf("result=%.10e\n", pow(.1, -120));
printf("result=%.20e\n", pow(.1, -120));
printf("result=%f\n", pow(.1, -120));
printf("10^120=%.10e\n", 1e120);
printf("10^120=%.20e\n", 1e120);
printf("10^120=%f\n", 1e120);
您将得到以下结果:

result=1.0000000000 E+120
结果=9.9999999999386195E+119
结果=99999999999338619494737593860530055873119939705372806430445302254169059595488061526805362384514358883569728192512.000000
10^120=1.0000000000 E+120
10^120=9.99999999980003E+119
10^120=999999999999999980003468347394201181668805192897008518188648311830772414627428725464789434929992439754776075181077037056.000000
pow(.1,-120)
1e120
稍有不同的原因是
.1
也不能精确表示,因此误差随着每次幂次迭代而放大


另一方面,如果您打印了
pow(2350)
的结果,您将得到一个准确的答案。

0.1通常不能准确地表示为
双精度
。典型的
double
()可以准确地表示大约2^64个不同的数字。0.1不是其中之一。最接近的
double
0.10000000000000055551…

因此,问题是对
pow(0.10000000000000055551…,-120)
的期望是什么

使用,这将是

pow(exact_one_tenth, -120) 
    - 120*pow(exact_one_tenth, -119)*(0.100000000000000005551... - exact_one_tenth)
    + other smaller terms

1e120 - 120*1e119*(0.000000000000000005551...) + other smaller terms

9.99999999999993_3386...e119

// OP result
9.99999999999993_3861...e119
看起来是一个非常准确的答案(与16个重要的数字匹配)。OP答案中的下一个较小的
double
如下所示。由于正确答案受OP的结果和下一个可表示数字的限制,并且更接近OP的答案,因此我断言计算结果是正确的,在0.5以内


查看浮点错误
pow
不是很准确。关于这个问题,浮点运算也不是很多,请看。@WeatherVane:“不是很精确”
pow
的关闭时间可能不超过几个ULP。但是,当然,你从一个近似值开始,把它提高到一个大的幂,误差系数会增加一点。尽管如此,最终结果还是在(欧洲)十亿分之一以内。。。如果将该值与10^12进行比较,则该值的偏移量远大于几个ULP。但如果你把它和实际用来近似0.1的120次方的倒数相比较,它在几秒钟之内。这种差异很重要,因为它提供了如何处理问题的线索。例如,在这种情况下,将
pow
调用替换为一系列乘法可能会增加错误,而不是减少错误,尽管人们的直觉可能是乘法“更精确”。@rudy:yes,这正是我一直以来的观点。我认为打印计算中使用的.1的近似值也会有所帮助。这并不是说pow(x,120)不准确(尽管它当然不准确),而是说
x
一开始就不准确。
9.99999999999993_2429...e+119