a*b < a for 0 <= b < 1 in IEEE floating point with positive a?

Is a*b < a for 0 <= b < 1 in IEEE floating point with positive a?

我正在用 C++ 编写,在舍入到最近模式下使用符合 IEEE 的算法。如果 a 是一个正的 short int(16 位)并且 b 是一个浮点数(32 位),其中 0 <= b < 1,a*b < a 是否总是计算为真?

也许吧。这取决于编译器决定如何计算浮点表达式(阅读 FLT_EVAL_METHOD,由 C99 发明,但现在是 C++ 标准的一部分,如果你想要血淋淋的细节。)

一旦 a 可以大于 4,表示为 float 的乘积 a*b 将在 b 时四舍五入为 a "big enough",例如 b = 1-ε/2(其中 ε 是 1.0 与下一个可表示数字 2-23 之间的差值。)但是如果编译器 not 在中间评估中执行舍入,在比较之前,产品可能会保持一些(更好的)内部精度,其中 a*b 仍然不同于 a,并且将始终断言对该内部精度所做的比较。这种情况并不少见:例如,由于 x87 协处理器的设计,将所有结果保持为 64 位 long double 是 32 位 x86 架构的典型做法; 53 位 double 也会将所有值分开,因为 24+16<53.

假设您的编译器中没有错误,显式转换为 float 应该 强制舍入,所以 (float)a*b < a 应该 有时评估为假。这里要特别小心,因为这个区域是你编译器的known to show compiler bugs, particularly since floating-point is declared "reserved to experts" and programmers are generally advised to not rely on details like these. You should particularly take care to not activate the optimization options (like /fp:fast),很可能跳过舍入操作以提高性能。

一种更安全(但仍不完全安全)的测试方法是将乘法结果显式存储到 float 变量中,如

float c = a * b;
  if (c < a) call_Houston();

同样,C++ 标准要求显式舍入(这是很合乎逻辑的,因为表达式的表示形式必须存储到 32 位浮点变量中。)但同样,一些 聪明 编译器,特别是在优化模式下,可能 猜测 表达式在之后被重用,并且可以采用短路径并重用寄存器内评估(它具有更高的精度), 并毁掉你的努力(并且让休斯顿毫无察觉。)GCC 编译器过去常常建议在这种情况下用像

这样的代码请求编译器
volatile float c = a * b;
  if (c < a) call_Houston();

然后转到 specific options like -ffloat-store。这并不能防止理智值的损失。顺便说一句,最近版本的 GCC 在这方面更加理智(因为 bug323 已修复。)