Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

I am using Visual Studio Professional 2012. I created a new C# ConsoleApplication, targeting .NET Framework 4.5, with following code:

    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. //Same result with previous framework version, and I tried VCE2010.

I know such problem usually results from the way double data type is stored (i.e. finite decimals converted to infinite binary fraction). But I didn't expect this to happen with only 5 decimal digits like 2.44445

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#. Thanks.

like image 346
limilaw Avatar asked Dec 27 '12 13:12

limilaw


People also ask

How do you round off a double in C#?

Round(Double, Int32, MidpointRounding) This method is used to rounds a double precision floating-point value to a specified number of fractional digits. A parameter specifies how to round the value if it is midway between two numbers.

What is MidpointRounding AwayFromZero?

Rounding away from zeroMidpoint values are rounded to the next number away from zero. For example, 3.75 rounds to 3.8, 3.85 rounds to 3.9, -3.75 rounds to -3.8, and -3.85 rounds to -3.9. This form of rounding is represented by the MidpointRounding.

Does C# automatically round up or down?

50000001" will always round up and ". 4999999" will always round down the the nearest integer. So a 15.5 can never become a 14. Any value that is larger than 14.5 and smaller than 15.5 will round to 15 any value larger than 15.5 and smaller than 16.5 will round to 16.

How do you round up and down in C#?

Use Math. Ceiling(87.124563563566) or Math. Floor(87.124563563566) for always rounding up or rounding down.


1 Answers

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. 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.

If you need to store fractional numbers precisely, consider using the decimal type instead.

like image 147
cdhowie Avatar answered Sep 28 '22 12:09

cdhowie