float/double 转换在 VS2012 和 VS2015 之间的差异

difference of float/double conversion betwen VS2012 and VS2015

我有以下代码:

 float a = 0.02f * 28f;
 double b = (double)a;
 double c = (double)(0.02f * 28f);
 Console.WriteLine(String.Format("  {0:F20}",  b));
 Console.WriteLine(String.Format("  {0:F20}", c));

然而,无论是从 VS2012 还是 VS2015 编译(两者都有 "standard" 设置)returns 不同的结果

在 VS2012 中

0,56000000238418600000
0,55999998748302500000

在 VS2015 中:

0,56000000238418600000
0,56000000238418600000

VS2012反汇编:

           float a = 0.02f * 28f;
0000003a  mov         dword ptr [ebp-40h],3F0F5C29h 
            double b = (double)a;
00000041  fld         dword ptr [ebp-40h] 
00000044  fstp        qword ptr [ebp-48h] 
            double c = (double)(0.02f * 28f);
00000047  fld         qword ptr ds:[001D34D0h] 
0000004d  fstp        qword ptr [ebp-50h] 

VS2015反汇编:

            float a = 0.02f * 28f;
001E2DE2  mov         dword ptr [ebp-40h],3F0F5C29h  
            double b = (double)a;
001E2DE9  fld         dword ptr [ebp-40h]  
001E2DEC  fstp        qword ptr [ebp-48h]  
            double c = (double)(0.02f * 28f);
001E2DEF  fld         dword ptr ds:[1E2E7Ch]  
001E2DF5  fstp        qword ptr [ebp-50h]  

正如我们所看到的,两种情况下的反汇编都不相同,这正常吗?这可能是 VS2012 或 VS2015 中的错误吗?或者此行为是否由某些已更改的特定设置控制? 谢谢!

这里的问题是,在 Roslyn 编译器中,在编译时完成的常量浮点计算与早期版本的执行方式略有不同 - 这导致了不同的行为。

但是,这不是错误,因为 C# 标准的这一部分:

4.1.6 Floating-point types

Floating-point operations may be performed with higher precision than the result type of the operation. For example, some hardware architectures support an “extended” or “long double” floating-point type with greater range and precision than the double type, and implicitly perform all floating-point operations using this higher precision type. Only at excessive cost in performance can such hardware architectures be made to perform floating-point operations with less precision, and rather than require an implementation to forfeit both performance and precision, C# allows a higher precision type to be used for all floating-point operations. Other than delivering more precise results, this rarely has any measurable effects. However, in expressions of the form x * y / z, where the multiplication produces a result that is outside the double range, but the subsequent division brings the temporary result back into the double range, the fact that the expression is evaluated in a higher range format may cause a finite result to be produced instead of an infinity. To force a value of a floating point type to the exact precision of its type, an explicit cast can be used.

发生的事情是,您看到了由上述原因导致的未定义行为的结果,其中 Roslyn 编译器在编译时完成的浮点计算使用的精度与之前在编译时完成的计算不同编译器。

请注意,Roslyn 编译器的初始版本中实际上存在一个由更新 2 修复的错误:https://github.com/dotnet/roslyn/issues/7262 - 但这只是一个兴趣点,与以下差异没有直接关系VS2012 和 VS2015(更新 2)之间的结果。

另请参阅以下内容了解更多详情: