题
我有一个小。目前这个早晨。部份你可以概括:
float x = 0.2f;
float y = 0.1f;
float z = x + y;
assert(z == x + y); //This assert is triggered! (Atleast with visual studio 2008)
原因似乎是表达 x + y
是晋升到的双重和相比,截版本中的 z
.(如果我改变 z
要 double
的断言是不是触发)。
我可以看到,对精密的原因将是有意义的执行的所有浮点运算在双精度在转换之前的结果以单的精确度。我发现了以下段落中的标准(其中我想我已经知道但不在这个上下文):
4.6.1.
"Rvalue的类型 float
可转换到右值的类型 double
.值不变"
我的问题是,是 x + y
保证是促进双重或是在编译器的自由裁量权?
更新: 由于许多人声称,一个不应该使用 ==
对于浮点,我只是想状态是,在特定情况下,我的工作,一个确切的比较是有道理的。
浮点比较 是 棘手,这是一个有趣的 链接 在问题,我认为还没有被提及。
解决方案
您不能承担普遍预期为浮点类型==
会工作。比较圆润的值,或使用结构,如abs(a-b) < tolerance
代替。
促进完全由编译器的判断(并且将取决于目标硬件,优化级,等等)。
这是怎么回事在这个特定的情况下,几乎可以肯定的是值存储在FPU比在内存更高的精度寄存器 - 一般来说,现代FPU硬件可与内部两倍或更高的精度无论精度程序员要求,与编译器生成的代码进行适当的转换时的值存储到存储器中;在一个未优化的构建,x+y
的结果仍然在寄存器中的比较时的点,但将z
已经存储了对存储器及取出背面,从而截断浮动精度。
其他提示
使用GCC 4.3.2,断言是的不的触发,而事实上,右值从x + y
返回是一个float
,而不是double
。
所以,它是由编译器。这就是为什么它从来没有明智的依赖于两个浮点值之间的精确平等。
C++常见问题的精简了一些进一步的讨论主题:
这是自浮点数到二进制的转换问题不给出精确的精度。
和内sizeof(float)
字节它不能容纳的浮点数和算术运算精确值可能导致近似值,并且因此平等失败。
请参阅下面e.g。
float x = 0.25f; //both fits within 4 bytes with precision
float y = 0.50f;
float z = x + y;
assert(z == x + y); // it would work fine and no assert
我想这将是在编译器的自由裁量权,但你总是迫使它与铸造,如果这是你的想法?
另一个原因从不直接比较浮动。
if (fabs(result - expectedResult) < 0.00001)