VC++使用fp:fast导致错误(不仅仅是不准确)结果 - 这是编译器错误吗?

Asa*_*saf 6 c++ floating-point visual-c++ compiler-bug visual-studio-2017

我安装了最新的VS2017更新(15.4.4),在编译项目时,单元测试开始失败.在使用优化(/ O2)和浮点快速模型(/ fp:fast)时,似乎在某些情况下会出现问题.以前的编译器(VS2017更新15.2)没有发生此问题.

这是一个示例程序:

#include <iostream>

const float FACTOR = 0.01745329251994329576923690768489f;

unsigned long long hoursToMicrosecs(int hours)
{
    return hours * 3600 * 1000000LL;
}

float degToRad(float deg)
{
    return deg * FACTOR;
}

float f(int u1, int u2)
{
    float percent = ((u1 - u2) / 1000.0f) / (hoursToMicrosecs(24) / 1000000.0f);
    return degToRad(percent * 360);
}

int main()
{   
    auto result = f(3600000, 35063681);
    std::cout << result << '\n';
    return (result > -3.0f) ? 0 : -1;
}
Run Code Online (Sandbox Code Playgroud)

result 应该是-2.2881,但输出实际上是-394.868,这不仅是不准确的.

如果我执行以下任何操作,它会起作用:

  • 删除优化
  • 改为fp:精确
  • 返回上一个编译器(15.2)

看看反汇编表明编译器试图为我们做一些好事 - 它只是在编译时计算了整个事情并用一个数字代替.

优化的代码只是一个单行:

011F1000  vmovss      xmm0,dword ptr [__real@c3c56f11 (011F2118h)]  
Run Code Online (Sandbox Code Playgroud)

我的问题是:这是一个编译器错误(我应该报告)还是错误的使用fp:fast?

ois*_*syn 6

我在这看到同样的事情.我想我发现了这个问题:hoursToMicroseconds(24)溢出来了.它不应该,因为表达式应该unsigned long long在乘法之前转换为1000000LL.但是如果你将结果反馈给a unsigned int,你将得到5006540​​80而不是86400000000.所以整个计算最终归结为-394.868.

我肯定会说这是一个编译器错误.看起来你可以通过将unsigned long long结果转换为double第一个来绕过它.

编辑

你知道还有什么好玩的吗?如果你把你所有的功能constexpr,同时还宣布result为constexpr中main(),它会产生正确的结果.因此,编译器中显然有两个独立的代码路径可以在编译时计算值,其中一个被破坏.