为什么浮动计算和转换在调试和发布配置中显示不同的结果?

AZ.*_*AZ. 9 c c++ floating-point visual-c++

这对我来说真的是一个奇怪的错误,我花了很长时间才弄清楚发生了什么.为了简化和重现,只需使用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);  
Run Code Online (Sandbox Code Playgroud)

为什么result2在调试/释放模式下显示不同的值?

Mys*_*ial 10

在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
Run Code Online (Sandbox Code Playgroud)

编辑:这看起来像编译器优化器错误给我.

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 );
Run Code Online (Sandbox Code Playgroud)

输出:

5374, 5375
Run Code Online (Sandbox Code Playgroud)

拉出(float)((a-b)/c)单独的作业不应影响下的结果strict (/fp:strict).


我知道其中一个从事MSVC优化工作的人.我会向他发送一份错误报告.

更新:

这是他们的回答:

嗨亚历克斯,谢谢你的错误报告.我将尝试为即将发布的VC++版本修复此问题,但它可能无法实现.

FWIW,如果你抛出/ arch:SSE2,并且因为我们正在启用/ arch:SSE2默认用于下一个VC++版本,该错误不会重现(https://connect.microsoft.com/VisualStudio/feedback/details/688736 /编译器生成-SSE-指令,而无需拱-SSE).

因此,默认行为将显示此错误已得到修复.但是如果你恢复到旧的FP模型(throw/arch:IA32),那么bug可能仍然存在.

埃里克

所以他们已经证实这是一个错误.