I have this tiny piece of code
double s = -2.6114289999999998;
double s7 = Math.Round(s, 7);
double s5 = Math.Round(s, 5);
double s6 = Math.Round(s, 6);
With Platform = Any CPU, I get
s7: -2.611429
s5: -2.61143
s6: -2.611429
With Platform = x64, I get
s7: -2.6114289999999998
s5: -2.61143
s6: -2.6114289999999998
Why? (Output copied from VS's Locals window)
The whole piece of code is:
private void btnAlign_Click(object sender, EventArgs e)
{
double s = -2.6114289999999998;
double s7 = Math.Round(s, 7);
double s5 = Math.Round(s, 5);
double s6 = Math.Round(s, 6);
}
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).
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With