Visual Studio 2008和2013之间的浮点不匹配

时间:2014-06-20 06:32:41

标签: visual-studio visual-c++ floating-accuracy

将C ++项目升级到Visual Studio 2013后,由于新VC编译器的浮点行为不同,程序的结果已更改。浮动模型设置为/ fp:precise

Visual Studio 2008(v9.0)

float f = 0.4f; //it produce f = 0.400000001
float f6 = 0.400000006f; //it produce f = 0.400000001

Visual Studio 2013(v12.0)

float f = 0.4f; //it produce f = 0.400000006                                 
float f1 = 0.40000001f; //it produce f1 = 0.400000006

项目的设置相同(已转换)。

我理解浮点模型中存在一种自由,但我不喜欢某些事情发生了变化,使用旧版/新版Visual Studio的人无法重现其他人报告的错误开发人员。是否有任何设置可以更改以在不同版本的Visual Studio中强制执行相同的行为?

我尝试将平台工具集设置为vs90,并且在VS2013中仍然生成0.400000006。

UPDATE:

我在Memory Window中跟踪了十六进制值。十六进制值f1,f1和f6都是相同的。在监视窗口中显示这些浮点值有所不同。此外,问题仍然是浮动0.3f。乘以相同的十进制值会得到不同的结果。

Visual Studio 2008(v9.0)

float a = 0.3f; //memory b8 1e 85 3e 00 00 40 40, watch 0.25999999
float b = 19400; 
unsigned long c = (unsigned long)((float)b * a); //5043

Visual Studio 2013(v12.0)

float a = 0.3f; //memory b8 1e 85 3e 00 00 40 40, watch 0.259999990
float b = 19400; 
unsigned long c = (unsigned long)((float)b * a); //5044

1 个答案:

答案 0 :(得分:4)

行为正确, float 类型只能存储7位有效数字。其余的只是随机噪音。您需要修复代码中的错误,您要么显示太多数字,要么向人类显示随机噪声,要么您的数学模型丢失了太多有效数字,您应该使用 double 代替。

VS2012发生了重大变化,影响了噪音数字的出现。部分代码生成器更改实现自动矢量化。 32位编译器传统上使用FPU进行计算。这对于产生不同的随机噪声非常臭名昭着,计算以80位中间格式执行,并在存储回存储器时被截断。由于优化器选择,发生此截断的确切时刻可能是不可预测的,因此产生不同的随机噪声。

代码生成器就像它已经为64位代码所做的那样,现在使用SSE2指令而不是FPU指令。这产生了更加一致的结果,不受代码优化器选择的影响,不再使用80位中间格式。有关FPU问题的背景资料可在this answer中找到。

这将是未来的行为,FPU永远不会再回来。相应地调整您的期望,这是一个“新常态”。并修复错误。