我只能假设这是一个错误.第一个断言在第二个失败时通过:
double sum_1 = 4.0 + 6.3;
assert(sum_1 == 4.0 + 6.3);
double t1 = 4.0, t2 = 6.3;
double sum_2 = t1 + t2;
assert(sum_2 == t1 + t2);
Run Code Online (Sandbox Code Playgroud)
如果不是错误,为什么?
Ed *_* S. 13
您正在比较浮点数.不要这样做,浮点数在某些情况下具有固有的精度误差.相反,取两个值的差值的绝对值,并断言该值小于某个小数字(epsilon).
void CompareFloats( double d1, double d2, double epsilon )
{
assert( abs( d1 - d2 ) < epsilon );
}
Run Code Online (Sandbox Code Playgroud)
这与编译器无关,也与浮点数的实现方式有关.这是IEEE规范:
http://www.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF
Mar*_*n B 12
这也是困扰我的事情.
是的,由于舍入错误,永远不应该对浮点数进行相等性比较,你可能知道这一点.
但在这种情况下,你是计算t1+t2,然后再计算它.当然,必须产生相同的结果?
这是可能发生的事情.我敢打赌你在x86 CPU上运行它,对吗?x86 FPU的内部寄存器使用80位,但存储器中的值存储为64位双精度数.
所以t1+t2首先使用80位精度计算,然后 - 我推测 - sum_2以64位精度存储到存储器中- 并且发生一些舍入.对于断言,它被加载回浮点寄存器,并t1+t2再次以80位精度计算.所以现在你要进行比较sum_2,先前舍入到64位浮点值,t1+t2用更高的精度(80位)计算 - 这就是值不完全相同的原因.
编辑为什么第一次测试通过?在这种情况下,编译器可能4.0+6.3在编译时进行求值并将其存储为64位数量 - 用于赋值和断言.因此,正在比较相同的值,并且断言通过.
Second Edit这是为代码的第二部分(gcc,x86)生成的汇编代码,带有注释 - 几乎遵循上面概述的场景:
// t1 = 4.0
fldl LC3
fstpl -16(%ebp)
// t2 = 6.3
fldl LC4
fstpl -24(%ebp)
// sum_2 = t1+t2
fldl -16(%ebp)
faddl -24(%ebp)
fstpl -32(%ebp)
// Compute t1+t2 again
fldl -16(%ebp)
faddl -24(%ebp)
// Load sum_2 from memory and compare
fldl -32(%ebp)
fxch %st(1)
fucompp
Run Code Online (Sandbox Code Playgroud)
有趣的旁注:这是在没有优化的情况下编译的.编译时-O3,编译器会优化所有代码.