Float difference / double conversion between VS2012 and VS2015

I have the following code:

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)); 

However, it returns different results if it is compiled from VS2012 or VS2015 (both have "standard" settings)

In VS2012

 0,56000000238418600000 0,55999998748302500000 

In VS2015:

 0,56000000238418600000 0,56000000238418600000 

VS2012 mismatch:

  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 mismatch:

  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] 

As we can see, disassembly is not the same in both cases, is this normal? Could this be a bug in VS2012 or VS2015? Or is this behavior controlled by some settings that have been changed? thanks!

+5
source share
1 answer

The problem here is that in the Roslyn compiler, the floating point calculations performed at compile time are slightly different than in earlier versions, which leads to behavior.

However, this is not an error due to this section of the C # standard:

4.1.6 Floating-Point Types

Floating point operations can be performed with greater precision than the type of result of the operation. For example, some hardware architectures support an “extended” or “long double” floating point type with a greater range and precision than a double type, and implicitly perform all floating point operations using this higher precision type. Only at an excessive cost of performance can such hardware architectures be created to perform floating point operations with less accuracy and instead of requiring the implementation to lose performance and accuracy, C # allows you to use a higher type of accuracy for all floating point operations. Providing more accurate results, it rarely has any measurable effects. However, in expressions of the form x * y / z, where multiplication yields a result that goes beyond the double range, but subsequent division returns the temporary result back into the double range, the fact that the expression is evaluated in a higher range can lead to the end result will be created instead of infinity. To force a floating-point type value to the exact precision of its type, you can use an explicit cast.

What happens is that you see the results of undefined behavior as a result of the above, where the floating point calculation performed by the Roslyn compiler at compile time uses a different precision from the calculation performed at compiler time by the compilers.

Please note that the original version of the Roslyn compiler actually had a bug that was fixed by Update 2: https://github.com/dotnet/roslyn/issues/7262 - but this is only an interesting point of view and is not directly related differences in results between VS2012 and VS2015 (with Update 2).

For more information see below:

+5
source

Source: https://habr.com/ru/post/1265477/


All Articles