版本之间的gcc舍入差异
gcc rounding difference between versions
我正在调查测试用例失败的原因
有问题的测试可以简化为(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
这又不同了。
也许更简单的问题是,对于这个单元测试来说,有多少重要的数字是真正重要的?
- C++将浮点指针值舍入为小数位数
- Boost::posix_time::ptime舍入到给定的分钟数
- 浮点定向舍入和优化
- 为什么输出精度没有正确舍入?
- 使用设置精度时如何阻止数字向上舍入?
- 如何在使用 MPFR 时在提升多精度中设置舍入模式
- OpenCV 细分一致的 Rect2f 到 Rect2i 舍入
- C++ 中的舍入函数
- 舍入 QDecDouble 值,精度最多为两个字符
- 将大 int 转换为浮点数,而不舍入 c++
- 舍入错误检测
- 根据浮点符号对浮点进行舍入的最简单方法是什么
- 将整数舍入到另一个整数的最接近的倍数
- Sizeof 舍入到对齐方式,但编译器仍将对象放在剩余的字节中
- 避免将 Int 转换为双重类型转换舍入
- 浮点数学运算后舍入不一致
- 浮动到绳子而无需舍入
- 版本之间的gcc舍入差异
- 为什么在浮点数的末尾加上0会改变它的舍入方式(可能的GCC bug)
- GCC '-M32' 选项在不运行 Valgrind 时更改浮点舍入