我已经安装了最新的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的错误用法?
/fp:fast
会导致预计算被存储为“double”,但随后以“float”形式加载?无论如何,看起来像是一个错误。 - Baum mit Augenint
和unsigned long long
的大小分别是多少? (b) 按照时间倒序逐步剥离计算:在degToRad
函数中,将return deg * FACTOR
改为return deg
。优化后的结果和非优化结果是否仍然不同?然后移除/ 1000000.0f
并进行测试。接着移除/ hoursToMicrosecs(24)
并测试。(如果失败了,就把它放回去并拆开其中的计算)。继续这样做,其中一个步骤会让你达到优化和非优化结果相同的点,这将给你一个线索,说明哪里出了问题。 - Eric Postpischil