我正在编写一个用于计算几何变换的应用程序,当我测试程序时,我发现了一些奇怪的东西:我在两台不同的机器上启动了测试,Z400工作站配备了英特尔®至强®处理器W3550和Z800工作站使用英特尔®至强®处理器X5560,我在一次操作中获得了不同的结果:
double x = 24.169408798217777 * sin(0.59420877837561048) / sin(0.97658754841928608)
使用Z400我得到x=16.330508228047432
Z800抛出此值x=16.330508228047435
最后一位数的值不同,我用该值进行了很多计算,因此结果不方便。
我尝试使用sinl
以获得更多精确度,但每个工作站的所有时间都得到相同的值。它出什么问题了?我怎么解决它?
答案 0 :(得分:2)
2个计算的结果相差1个十进制数字,如下所示,1个二进制数字如下所示。 Z400更接近正确的答案。 sin()
计算没有义务精确到最后一个二进制位,而是在1位以内。好的sin()
实现对最后一位是正确的**。你的Z800不太好。
printf("%a\n", 16.330508228047432);
printf("%a\n", 16.330508228047435);
printf("%a\n", 24.169408798217777 * sin(0.59420877837561048) / sin(0.97658754841928608)); // my PC eclipse
0x1.0549c2fee85cbp + 4
0x1.0549c2fee85ccp + 4
0x1.0549c2fee85cbp + 4
**准确度要求不是C ++要求,而是IEEE浮点要求。 Trig函数s / b精确到1 ulp(单位最后一个位置)。 好的 trig库在0.5 ulp内是准确的(单位最后一位) - 最好的答案。
答案 1 :(得分:1)
作为猜测,我将建议这与某些处理器计算80位寄存器(而不是64位)中的浮点值有关,并且只会尽可能晚地降低精度。
在GCC上,您可以使用-ffloat-store
禁用此功能(这将导致所有数学运算以64位完成,并且还可能导致它稍慢)。
如果80位寄存器是实际问题,this answer还有一些额外的建议也可以提供帮助。