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

6

我已经安装了最新的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;
}

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

如果我执行以下任何操作,则可正常工作:

  • 删除优化
  • 更改为 fp:precise
  • 返回到以前的编译器(15.2)

查看反汇编代码可以发现,编译器试图为我们做一些好事——它只在编译时计算了整个表达式,并替换为一个单独的数字。

优化后的代码只有一行:

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

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

1
优化后的代码只需加载预先计算好的结果。更有趣的是,gcc和clang都将其存储和加载为“double”,而不是“float”。也许/fp:fast会导致预计算被存储为“double”,但随后以“float”形式加载?无论如何,看起来像是一个错误。 - Baum mit Augen
有趣的想法。我检查了一下,将从该地址(0x011F2118)开始的8个字节或其前4个字节转换为double是否与预期结果相似,但是没有。所以我猜正确的结果并没有存储为double类型。感谢您的想法。 - Asaf
(a) intunsigned long long的大小分别是多少? (b) 按照时间倒序逐步剥离计算:在degToRad函数中,将return deg * FACTOR改为return deg。优化后的结果和非优化结果是否仍然不同?然后移除/ 1000000.0f并进行测试。接着移除/ hoursToMicrosecs(24)并测试。(如果失败了,就把它放回去并拆开其中的计算)。继续这样做,其中一个步骤会让你达到优化和非优化结果相同的点,这将给你一个线索,说明哪里出了问题。 - Eric Postpischil
1个回答

6

我也看到了同样的问题。我认为我找到了问题所在:hoursToMicroseconds(24)发生了溢出。这不应该发生,因为表达式在和1000000LL相乘之前应该被转换为unsigned long long。但是如果你将结果强制转换回unsigned int,你将得到500654080而不是86400000000。所以整个计算最终变成了-394.868。

我绝对会说这是编译器错误。似乎你可以通过先将unsigned long long结果转换为double来规避它。

编辑

你知道还有什么有趣的吗?如果你让所有函数都成为constexpr,并且在main()中也声明resultconstexpr,它将会产生正确的结果。因此,在编译器中显然有两条不同的代码路径可以在编译时计算出这个值,其中一个是错误的。


优秀的分析!我会向微软报告并在此处添加链接。 关于解决方法 - 我已将所有项目中的编译标志更改为fp:precise,因为可能还有其他地方发生这种情况,仅修改此函数可能不足够。 - Asaf
报告位置:https://developercommunity.visualstudio.com/content/problem/155625/c-compiler-bug-when-using-fpfast-and-o2.html - Asaf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接