C# rounding differently depending on platform?

Solution 1:

The value -2.611429 cannot be represented using 64-bit floating point. When compiling in 32-bit mode the value will instead use 80-bit (extended precision).

Solution 2:

On x64, the SSE2 FPU is used and on x86 the x87 FPU is used.

It is possible (although not advised) to change the x87 precision to be the same as the SSE2 precision (i.e., use lower precision).

You can do that via the _controlfp() API.

The following program demonstrates. Run this program in x86 mode and you'll see how the use of _controlfp(0x00030000, 0x00020000) causes the output to change to be similar to (but not quite the same!) as the x64 version:

using System;
using System.Runtime.InteropServices;

namespace ConsoleApp3
{
    class Program
    {
        static void Main()
        {
            double s = -2.6114289999999998;

            Console.WriteLine(Math.Round(s, 7).ToString("R")); // -2.611429

            if (!Environment.Is64BitProcess)
                _controlfp(0x00030000, 0x00020000);

            Console.WriteLine(Math.Round(s, 7).ToString("R")); // -2.61142897605896
        }

        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint _controlfp(uint newcw, uint mask);
    }
}

However, you should not mess around with the FPU in this way (and if you do, you should revert to the previous setting asap).

Solution 3:

According to the CSharp language specification 3.0 the following might be the case:

See chapter 4.1.6 at the specification for more information

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.

In short: The C# spec actually states that hardware architectures may have some impact on floating point types (Double, Float).

The language specification as .doc can be found here.

Solution 4:

Answered here : https://stackoverflow.com/a/19978623/4891523

x64 managed code will use SSE for double/float computation instead of x87 FPU when using x86 managed code.