根据平台,C#舍入不同?

时间:2017-11-15 08:37:39

标签: c# rounding

我有一小段代码

double s = -2.6114289999999998;
double s7 = Math.Round(s, 7);
double s5 = Math.Round(s, 5);
double s6 = Math.Round(s, 6);

使用Platform = Any CPU,我得到了

s7: -2.611429   
s5: -2.61143    
s6: -2.611429   

使用Platform = x64,我得到了

s7: -2.6114289999999998 
s5: -2.61143    
s6: -2.6114289999999998

为什么呢? (从VS的本地窗口复制输出)

整段代码是:

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

4 个答案:

答案 0 :(得分:3)

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

可以(尽管不建议)将x87精度更改为与SSE2精度相同(即使用更低的精度)。

您可以通过_controlfp() API。

执行此操作

以下程序演示。在x86模式下运行此程序,您将看到如何使用_controlfp(0x00030000, 0x00020000)导致输出更改为与x64版本类似(但不完全相同!):

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

但是,你不应该以这种方式乱用FPU(如果你这样做,你应该尽快恢复到之前的设置)。

答案 1 :(得分:2)

根据CSharp语言规范3.0,可能会出现以下情况:

  

有关详细信息,请参阅规范中的第4.1.6章

     

可以以比操作的结果类型更高的精度执行浮点运算。例如,某些硬件体系结构支持“扩展”或“长双”浮点类型,其范围和精度比double类型更大,并使用此更高精度类型隐式执行所有浮点运算。只有在性能成本过高的情况下,才能使这种硬件架构以较低的精度执行浮点运算,而不是要求实现失去性能和精度,C#允许更高精度的类型用于所有浮点运算。除了提供更精确的结果外,这几乎没有任何可衡量的影响。但是,在x * y / z形式的表达式中,乘法产生的结果超出双范围,但随后的除法将临时结果带回双范围,表达式的计算结果更高范围格式可能会导致生成有限结果而不是无穷大。

简而言之:C#规范实际上声明硬件架构可能会对浮点类型产生一些影响(Double,Float)。

The language specification as .doc can be found here.

答案 2 :(得分:2)

无法使用64位浮点表示值-2.611429。在32位模式下编译时,该值将改为使用80位(generate a reporting dashboard)。

答案 3 :(得分:1)

在这里回答:https://stackoverflow.com/a/19978623/4891523

  

x64托管代码将使用SSE进行双/浮点计算而不是   使用x86托管代码时的x87 FPU。