c++ - VC++ 使用 fp :fast causes wrong (not just inaccurate) results - is this a compiler bug?

标签 c++ visual-c++ floating-point visual-studio-2017 compiler-bug

我已经安装了最新的 VS2017 更新 (15.4.4),但在编译我们的项目时,单元测试开始失败。 在使用优化 (/O2) 和浮点快速模型 (/fp:fast) 时,问题似乎发生在某些情况下。 以前的编译器(VS2017 update 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;
}

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

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

  • 移除优化
  • 更改为 fp:precise
  • 返回上一个编译器(15.2)

查看反汇编向我们展示了编译器试图为我们做一些好事 - 它只是在编译时计算了整个事情并用一个数字替换。

优化后的代码只是一行代码:

011F1000  vmovss      xmm0,dword ptr [__real@c3c56f11 (011F2118h)]  

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

最佳答案

我在这里看到了同样的事情。我想我发现了问题:hoursToMicroseconds(24) 溢出了。它不应该,因为表达式应该在与 1000000LL 相乘之前转换为 unsigned long long。但是,如果您将该结果转换回 unsigned int,您将得到 5006540​​80 而不是 86400000000。因此整个计算最终归结为 -394.868。

我肯定会说这是一个编译器错误。看来您可以通过首先将 unsigned long long 结果转换为 double 来规避它。

编辑

你知道还有什么好笑的吗?如果您将所有函数设为 constexpr,并且还在 main() 中将 result 声明为 constexpr,则 产生正确的结果。因此,编译器中显然有两个独立的代码路径可以在编译时计算值,其中一个已损坏。

关于c++ - VC++ 使用 fp :fast causes wrong (not just inaccurate) results - is this a compiler bug?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47464225/

相关文章:

c++ - 反馈: C++ developers who've switched to VS2010?

c++ - C 中的 OpenSSL : after second decryption in application run, 结果的前 16 个字节是垃圾

c++ - 更新 Windows 窗体 - Visual C++

c++ - Kahan算法中的加法而不是减法

c++ - 替换为 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

c++ - 错误 : '' was not declared in this scope

c++ - 在同一解决方案 C++ express 上的许多项目中更改平台工具集

c++ - 关闭一个对话框并打开另一个对话框

ios - 从 NSString 对象返回的浮点值不是我所期望的,我该如何更正从 NSString 中提取 float ?

rust - 如果 f32 不是 Eq,为什么会编译?