#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
includefdiv
指令生成的程序集,而使用-Ofast
includesfmul
指令生成的程序集,请参阅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-一些非常小的delta。
最后,相乘的结果是500 *(0.002- delta)= 1-一些小的值。当此值转换为时int
,将被截断,因此结果int
为0。