Warm tip: This article is reproduced from serverfault.com, please click

c++--Ofast在使用长双精度字时会产生不正确的代码

(c++ - -Ofast produces incorrect code while using long double)

发布于 2020-06-03 13:21:09
#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

编译器资源管理器,网址-Ofasthttps : //gcc.godbolt.org/z/YkX7fB

看来这行引起了问题。

在此处输入图片说明

Questioner
Ghastlcon
Viewed
0
Daniel Langr 2020-06-03 23:21:51

随着-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;
}

使用-O2includefdiv指令生成的程序集,而使用-Ofastincludesfmul指令生成的程序集,请参阅https://gcc.godbolt.org/z/58VHxb

接下来,1/500,即0.002,无法long double精确表示因此,发生了一些舍入,并且看起来,在你的情况下,这种舍入恰好是向下的。可以通过以下表达式检查:

500.0L * (1.0L / 500.0L) < 1.0L

评估方式为truehttps//gcc.godbolt.org/z/zMcjxJ因此,确切的存储乘数为0.002-一些非常小的delta

最后,相乘的结果是500 *(0.002- delta)= 1-一些小的值当此值转换为时int,将被截断,因此结果int为0。