#include <cstdio>
int main(void)
{
int val = 500;
printf("%d\n", (int)((long double)val / 500));
printf("%d\n", (int)((long double)500 / 500));
}
显然,它应该输出
1 1
。但是,如果您使用-Ofast
进行编译,它将输出0 1
,为什么呢?而且,如果将
500
更改为其他值(例如400
)并使用-Ofast
进行编译,它将仍然输出1 1
。带有
-Ofast
的编译器资源管理器:https://gcc.godbolt.org/z/YkX7fB看来这行引起了问题。
最佳答案
使用-Ofast
,启用了-ffast-math
,这可能导致某些操作以不同且更快的方式进行计算。在您的情况下,(long double)val / 500)
可以计算为(long double)val * (1.0L / 500))
。在比较以下功能的-O2
和-Ofast
时,可以在生成的程序集中看到这一点:
long double f(long double a)
{
return a / 500.0L;
}
使用
-O2
生成的程序集涉及fdiv
指令,而使用-Ofast
生成的程序集涉及fmul
指令,请参见https://gcc.godbolt.org/z/58VHxb。接下来,1/500,即0.002,不能精确地用
long double
表示。因此,发生了一些舍入,并且看起来,在您的情况下,这种舍入恰好是向下的。可以通过以下表达式检查:500.0L * (1.0L / 500.0L) < 1.0L
评估为
true
:https://gcc.godbolt.org/z/zMcjxJ。因此,确切的存储乘数为0.002-一些很小的增量。最后,相乘的结果是500 *(0.002-delta)= 1-一些小值。并且当此值转换为
int
时,它被截断了,因此int
的结果为0。