简体   繁体   English

.NET Math.Round(<double>,<int>,MidpointRounding.AwayFromZero)无法正常工作

[英].NET Math.Round(<double>,<int>,MidpointRounding.AwayFromZero) not working correctly

I am using Visual Studio Professional 2012. I created a new C# ConsoleApplication, targeting .NET Framework 4.5, with following code: 我正在使用Visual Studio Professional 2012.我创建了一个针对.NET Framework 4.5的新C#ConsoleApplication,其代码如下:

    static void Main(string[] args)
    {
        double x = 2.44445;
        double y = Math.Round(x, 4, MidpointRounding.AwayFromZero);
        Console.WriteLine(y);
        Console.ReadKey();
    }

The expected result should be 2.4445, but it actually returns 2.4444. 预期结果应为2.4445,但实际上返回2.4444。 //Same result with previous framework version, and I tried VCE2010. //与之前的框架版本相同,我尝试了VCE2010。

I know such problem usually results from the way double data type is stored (ie finite decimals converted to infinite binary fraction). 我知道这种问题通常是由于存储双数据类型的方式(即有限小数转换为无限二进制分数)。 But I didn't expect this to happen with only 5 decimal digits like 2.44445 但我没想到这只会发生,例如2.44445只有5位小数

I'm worrying if such thing could happen with even shorter decimals. 我担心如果这样的事情会发生甚至更短的小数。 I would also like to learn a safer way to round (using away from zero convention) in C#. 我还想学习一种更安全的方法来在C#中舍入(使用远离零惯例)。 Thanks. 谢谢。

This is indeed due to the fragile precision of floating-point numbers. 这确实是由于浮点数的精确度很脆弱。 0.5 can be stored perfectly in IEEE floating point, but 0.45, 0.445 etc. cannot. 0.5可以完美地存储在IEEE浮点数中,但0.45,0.445等不能存储。 For example, the actual value that is stored when you specify 2.44445 is 11009049289107177/4503599627370496 which is 2.44449999999999989519494647... It should now be obvious why the number is rounded the way it is. 例如,指定2.44445时存储的实际值是11009049289107177/4503599627370496,即2.44449999999999989519494647 ...现在应该很明显为什么数字按原样舍入。

If you need to store fractional numbers precisely, consider using the decimal type instead. 如果需要精确存储小数,请考虑使用decimal类型。

Notes from msdn : 来自msdn的笔记

Because of the loss of precision that can result from representing decimal values as floating-point numbers or performing arithmetic operations on floating-point values, in some cases the Round(Double, Int32, MidpointRounding) method may not appear to round midpoint values as specified by the mode parameter. 由于将十进制值表示为浮点数或对浮点值执行算术运算可能导致精度损失,因此在某些情况下,Round(Double,Int32,MidpointRounding)方法可能看起来不像指定的那样舍入中点值通过mode参数。 This is illustrated in the following example, where 2.135 is rounded to 2.13 instead of 2.14. 这在以下示例中说明,其中2.135舍入为2.13而不是2.14。 This occurs because internally the method multiplies value by 10digits, and the multiplication operation in this case suffers from a loss of precision . 发生这种情况是因为内部方法将值乘以10digits,并且在这种情况下乘法运算会受到精度损失的影响

This is how Round implemented: 这就是Round实施的方式:

double num = roundPower10Double[digits];
value *= num;
if (mode == MidpointRounding.AwayFromZero)
{
    double num2 = SplitFractionDouble(&value);
    if (Abs(num2) >= 0.5)
    {
        value += Sign(num2);
    }
}

As you can see, value is multiplied by num, which is a value from 如您所见,value乘以num,它是来自的值

roundPower10Double = new double[] { 1.0, 10.0, 100.0, 1000.0, 10000.0, 
      100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000,  
      100000000000, 1000000000000, 10000000000000, 100000000000000, 1E+15 };    

So, actually you have 2.44445 * 10000.0 - 24444,0 which gives 0,499999999996362 . 所以,实际上你有2.44445 * 10000.0 - 24444,0 ,它给出了0,499999999996362 Which is less than 0.5 . 小于0.5 Thus you have 2.4444 . 因此你有2.4444

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用NET Math.Round( <decimal> , <int> ,MidpointRounding.AwayFromZero) - How to round off correctly with NET Math.Round(<decimal>,<int>,MidpointRounding.AwayFromZero) JavaScript中的Math.round MidPointRounding.AwayFromZero - Math.round MidPointRounding.AwayFromZero in javascript 使用Math.Round和MidpointRounding.AwayFromZero四舍五入一个数字 - Round a number using Math.Round with MidpointRounding.AwayFromZero 与Delphi中的MidpointRounding.AwayFromZero相当的Math.Round()是什么? - What is the equivalent of Math.Round() with MidpointRounding.AwayFromZero in Delphi? Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72 - Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72 使用Math.Round(ReportItems!category.Value,MidpointRounding.AwayFromZero)返回不正确的值 - Using Math.Round(ReportItems!category.Value,MidpointRounding.AwayFromZero) returns incorrect value 为什么Math.Round(106.8,2,MidpointRounding.AwayFromZero)返回106.8而不是106.80? - Why does Math.Round(106.8, 2, MidpointRounding.AwayFromZero) return 106.8 and not 106.80? 中点舍入为零 - MidpointRounding.AwayFromZero Math.Round在AwayFromZero模式下失败 - Math.Round fail on AwayFromZero mode 将MidpointRounding.AwayFromZero设置为默认的舍入方法 - Setting MidpointRounding.AwayFromZero as the default rounding method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM