为啥浮动计算和强制转换在调试和发布配置中显示不同的结果?
Posted
技术标签:
【中文标题】为啥浮动计算和强制转换在调试和发布配置中显示不同的结果?【英文标题】:Why floating calculation and casting shows different result in debug and release configuration?为什么浮动计算和强制转换在调试和发布配置中显示不同的结果? 【发布时间】:2012-02-10 18:32:25 【问题描述】:这对我来说确实是一个奇怪的错误,我花了很长时间才弄清楚发生了什么。为了简化和重现,只需使用 VS2005 创建一个空的 win32 控制台应用程序,并在 main 方法中使用此代码:
float a = 411.00418f;
float b = 1.0f;
float c = 0.076279849f;
unsigned short result = (unsigned short)( (a-b)/c );
unsigned short result2 = (unsigned short)( (float)((a-b)/c) );
// Debug: 5374, 5375
// Release: 5374, 5374
printf("%d, %d\n", result, result2);
为什么 result2 在调试/发布模式下显示不同的值?
【问题讨论】:
【参考方案1】:在 MSVC 中,默认的浮点模式是 precise (/fp:precise)
。这意味着优化器可能会进行某些优化以提高准确性或性能。
尝试将模式更改为strict (/fp:strict)
。这将使编译器在舍入等方面遵循严格的浮点规则。
(编辑:strict (/fp:strict)
在这种情况下似乎不起作用...)
如果您查看优化构建的反汇编,您可以看到整个计算已被折叠和优化。
push 5374 ; 000014feH
push 5374 ; 000014feH
push OFFSET ??_C@_07MHMABKGB@?$CFd?0?5?$CFd?6?$AA@
call DWORD PTR __imp__printf
add esp, 12 ; 0000000cH
编辑:对我来说,这看起来像是一个编译器优化器错误。
在strict (/fp:strict)
下,下面的代码会产生不同的结果:
float a = 411.00418f;
float b = 1.0f;
float c = 0.076279849f;
unsigned short result1 = (unsigned short)((float)((a-b)/c));
float d = (float)((a-b)/c);
unsigned short result2 = (unsigned short)( d );
输出:
5374, 5375
将(float)((a-b)/c)
拉出到单独的赋值中不应影响strict (/fp:strict)
下的结果。
我认识一位从事 MSVC 优化器工作的人。我会向他发送错误报告。
更新:
这是他们的回应:
您好 Alex,感谢您提交此错误报告。我会尝试解决这个问题 即将发布的 VC++ 版本,但它可能不会成功。
FWIW,如果您抛出 /arch:SSE2,该错误不会重现,因为我们 正在为下一个 VC++ 版本默认启用 /arch:SSE2 (https://connect.microsoft.com/VisualStudio/feedback/details/688736/compiler-generates-sse-instructions-without-arch-sse)。
因此,默认行为将显示此错误已修复。但如果 你恢复到旧的 FP 模型(抛出 /arch:IA32)这个错误可能 仍然存在。
埃里克
所以他们已经确认这是一个错误。
【讨论】:
我将“浮点模型”设置为“Strict (/fp:strict)”,结果是一样的。我错过了什么吗? 我也注意到了。我也在努力弄明白。在优化构建中,优化器折叠所有计算。我认为这就是它不尊重严格的舍入行为的地方。 其实我的项目在vs2010中使用的是C++/CLI,所以可能也受影响了? 在我提交此报告之前,我正在尝试验证Strict (/fp:strict)
确实确实保证了代码中所写的严格 FP。这应该与 CLI 无关。这是不尊重严格浮点的优化器。以上是关于为啥浮动计算和强制转换在调试和发布配置中显示不同的结果?的主要内容,如果未能解决你的问题,请参考以下文章