问题
对于实现精确 IEEE 754 算术的 C99 编译器f
,divisor
类型 的值是否float
存在使得f / divisor != (float)(f * (1.0 / divisor))
?
编辑:通过“实现精确的 IEEE 754 算术”,我的意思是一个正确地将 FLT_EVAL_METHOD 定义为 0 的编译器。
语境
提供符合 IEEE 754 的浮点的 AC 编译器只能将单精度除以常数替换为单精度乘以逆,如果所述逆本身可以精确表示为float
.
在实践中,这只发生在二次幂的情况下。因此,程序员 Alex 可能确信它f / 2.0f
会像以前一样被编译f * 0.5f
,但如果 Alex 可以接受乘以0.10f
而不是除以 10,则 Alex 应该通过在程序中编写乘法来表达它,或者使用编译器选项,例如 GCC 的-ffast-math
.
这个问题是关于将单精度除法转换为双精度乘法。它总是产生正确的舍入结果吗?它是否有可能更便宜,从而成为编译器可能进行的优化(即使没有-ffast-math
)?
我已经比较了 1 到 2(float)(f * 0.10)
之间f / 10.0f
的所有单精度值f
,但没有找到任何反例。float
这应该涵盖产生正常结果的 normal 的所有划分。
然后我使用以下程序将测试推广到所有除数:
#include <float.h>
#include <math.h>
#include <stdio.h>
int main(void){
for (float divisor = 1.0; divisor != 2.0; divisor = nextafterf(divisor, 2.0))
{
double factor = 1.0 / divisor; // double-precision inverse
for (float f = 1.0; f != 2.0; f = nextafterf(f, 2.0))
{
float cr = f / divisor;
float opt = f * factor; // double-precision multiplication
if (cr != opt)
printf("For divisor=%a, f=%a, f/divisor=%a but (float)(f*factor)=%a\n",
divisor, f, cr, opt);
}
}
}
搜索空间足够大,足以让这变得有趣 (2 46 )。该程序当前正在运行。有人可以告诉我它是否会在完成之前打印一些东西,也许会解释为什么或为什么不打印?