版本之间的gcc舍入差异

gcc rounding difference between versions

本文关键字:舍入 gcc 之间 版本      更新时间:2023-10-16

我正在调查测试用例失败的原因

有问题的测试可以简化为(4.0/9.0) ** (1.0/2.6),将其四舍五入到6位,并根据已知值(作为字符串)进行检查:

#include<stdio.h>
#include<math.h>
int main(){
    printf("%.06fn", powf(4.0/9.0, (1.0/2.6)));
}

如果我在Linux上的gcc 4.1.2中编译并运行它,我会得到:

0.732057

Python同意,Wolfram|Alpha:也同意

$ python2.7 -c 'print "%.06f" % (4.0/9.0)**(1/2.6)'
0.732057

然而,我在Linux上的gcc 4.4.0和OS X上的4.2.1上得到了以下结果:

0.732058

double的作用相同(尽管我没有广泛测试)

我不知道如何进一步缩小范围。。这是gcc回归吗?舍入算法的变化?我在做傻事?

编辑:将结果打印到12位,第7位的数字是4对5,这解释了舍入差异,但不是数值差异:

gcc 4.1.2:

0.732057452202

gcc 4.4.0:

0.732057511806

以下是两个版本的gcc -S输出:https://gist.github.com/1588729

最近的gcc版本能够使用mfpr进行编译时浮点计算。我的猜测是,您最近的gcc做到了这一点,并且在编译时版本中使用了更高的精度。这至少是C99标准允许的(如果它被修改了,我还没有看过其他标准)

C99 中的6.3.1.8/2

浮动操作数的值和浮动表达式的结果的值可以是以比该类型所要求的更高的精度和范围来表示;类型不是从而改变。

编辑:你的gcc-S结果证实了这一点。我还没有检查计算结果,但旧的计算结果(在用内存代替恒定内容后)有

movss 1053092943, %xmm1
movss 1055100473, %xmm0
call powf

使用4/9.0和1/2.6的预计算值调用powf,然后在升级为double后打印结果,而新的powf只打印升级为double的浮点0x3b681f。

我认为旧的gcc在引擎盖下使用了double。在Haskell中进行计算并将结果打印到全精度,我得到了

Prelude Text.FShow.RealFloat> FD ((4/9) ** (1/2.6))
0.73205748476369969512944635425810702145099639892578125
Prelude Text.FShow.RealFloat> FF ((4/9) ** (1/2.6))
0.732057511806488037109375

因此double的结果与gcc-4.1.2的结果一致,float的结果与gcc-4.4.0的结果一致。gcc-4.5.1分别对float产生了结果。CCD_ 8与Haskell结果一致。

正如一位程序员所说,编译器被允许使用更高的精度,旧的gcc做到了,而新的显然没有。

这里有很多玩家。Gcc很可能只是将计算转发到浮点处理器;你可以检查拆卸情况。

您可以使用二进制表示(来自相同的wolfram/alpha)检查二进制结果:

float q=powf(4.0/9.0, (1.0/2.6));
unsigned long long hex=*reinterpret_cast<unsigned long long*>(&q);
unsigned long long reference=0x1f683b3f;
assert( hex==reference );

printf也可能是罪魁祸首:这个数字的十进制表示也可能是问题所在。您可以尝试编写printf("%0.06f", 0.73205748 );来测试这一点。

您应该能够通过打印更多(所有)有效数字来区分不同的格式舍入和给出不同答案的数学。

如果在不进行舍入时看起来相同,则printf("%0.6f"只是舍入不同。


好吧,有了旧的Linux+python环境,我得到了:

Python 2.4.3 (#1, Jun 11 2009, 14:09:37)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> (4.0/9.0)**(1.0/2.6)
0.7320574847636997

这又不同了。

也许更简单的问题是,对于这个单元测试来说,有多少重要的数字是真正重要的?