我用C ++编写,使用符合圆形到最近模式的IEEE算法。如果a是正短整数(16位)并且b是浮点数(32位),则其中0 <= b <1。 1,a * b&lt;总是评价为真?
答案 0 :(得分:2)
也许。这取决于编译器如何决定评估浮点表达式(请阅读C99发明的FLT_EVAL_METHOD,但现在是C ++标准的一部分,如果你想要血腥细节的话。)
只要a
可以大于4,当a*b
为“大float
时,表示为a
的产品b
会向b = 1-ε/2
舍入足够的“,例如a*b
(其中ε是1.0和下一个可表示的数字之间的差异,2 -23 。)但是如果编译器不执行在中间评估中进行舍入,在比较之前,产品可以保持一些(更好的)内部精度,其中a
仍然不同于(float)a*b < a
,并且对内部精度的比较将是总是断言。这种情况并不罕见:由于x87协处理器的设计,将所有结果保持为64位长双倍是典型的32位x86架构,例如; 53位双精度值也会使所有值保持分离,因为24 + 16 <53。
假设编译器中没有错误,浮动的显式强制转换应该强制进行舍入,因此float
应该有时评估为false。在这里要特别谨慎,因为这个区域known显示编译器错误,特别是因为浮点被声明为“专家保留”,程序员通常建议不依赖这些细节。您应特别注意不激活编译器的优化选项(如/fp:fast
),这些选项很可能跳过改善绩效的四舍五入行动。
执行测试的一种更安全(但仍然不是完全安全)的方法是将乘法结果显式存储到float c = a * b;
if (c < a) call_Houston();
变量中,例如
volatile float c = a * b;
if (c < a) call_Houston();
再次,C ++标准需要显式舍入(这是非常合乎逻辑的,因为表达式的表示必须存储到32位浮点变量中。)但是这里再次提到了一些聪明的编译器,特别是在优化模式下,可能会猜测表达式在之后重复使用,并且可以采用短路径并重用寄存器内评估(具有更高的精度),并破坏您的努力(和让休斯顿不知道。)GCC编译器曾经建议在这种情况下向编译器提供类似
的代码{{1}}
然后转到specific options like -ffloat-store
。这并不能防止失去理智点。顺便说一句,最近版本的GCC在这方面更加明智(因为bug323是固定的。)