VC++ 使用 fp:fast 会导致错误(不仅仅是不准确)的结果 - 这是编译器错误吗?
VC++ using fp:fast causes wrong (not just inaccurate) results - is this a 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
- Return 到以前的编译器 (15.2)
查看反汇编向我们展示了编译器试图为我们做一些好事 - 它只是在编译时计算了整个事情并用一个数字替换。
优化后的代码只有一行:
011F1000 vmovss xmm0,dword ptr [__real@c3c56f11 (011F2118h)]
我的问题是:这是编译器错误(我应该报告)还是 fp:fast 的错误用法?
我在这里看到了同样的事情。我想我发现了问题:hoursToMicroseconds(24)
溢出了。它不应该,因为表达式应该在与 1000000LL
相乘之前转换为 unsigned long long
。但是,如果将该结果转换回 unsigned int
,您将得到 500654080 而不是 86400000000。因此整个计算最终归结为 -394.868。
我肯定会说这是一个编译器错误。看来您可以通过先将 unsigned long long
结果转换为 double
来规避它。
编辑
你知道还有什么好笑的吗?如果您将所有函数设为 constexpr
,并在 main()
中将 result
声明为 constexpr
,它 将 产生正确的结果。因此,编译器中显然有两个独立的代码路径可以在编译时计算值,其中一个已损坏。
我已经安装了最新的 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
- Return 到以前的编译器 (15.2)
查看反汇编向我们展示了编译器试图为我们做一些好事 - 它只是在编译时计算了整个事情并用一个数字替换。
优化后的代码只有一行:
011F1000 vmovss xmm0,dword ptr [__real@c3c56f11 (011F2118h)]
我的问题是:这是编译器错误(我应该报告)还是 fp:fast 的错误用法?
我在这里看到了同样的事情。我想我发现了问题:hoursToMicroseconds(24)
溢出了。它不应该,因为表达式应该在与 1000000LL
相乘之前转换为 unsigned long long
。但是,如果将该结果转换回 unsigned int
,您将得到 500654080 而不是 86400000000。因此整个计算最终归结为 -394.868。
我肯定会说这是一个编译器错误。看来您可以通过先将 unsigned long long
结果转换为 double
来规避它。
编辑
你知道还有什么好笑的吗?如果您将所有函数设为 constexpr
,并在 main()
中将 result
声明为 constexpr
,它 将 产生正确的结果。因此,编译器中显然有两个独立的代码路径可以在编译时计算值,其中一个已损坏。