none
Math.Round() Not Working Properly. RRS feed

  • Question

  • Math.Round() functionality giving wrong result in this below scenario.


    Expected Result:9.92

    Math.Round(9.915, 2, MidpointRounding.AwayFromZero)  //Actual result :9.91

    Math.Round(9.915, 2) //Actual result :9.91

    Please let me know the right way to get the desired result. 

    Thursday, March 3, 2016 8:49 AM

Answers

  • Just to add to previous answer: doubles have a larger range but are not as precise as decimals. Decimals are more precise but use up slightly more memory (and are a bit slower I believe).

    If you just use a constant number in your program as in your example, C# will assume double and use the appropriate overload of Math.Round(double).

    If you want to tell C# that your number should actually be read as a decimal then use the 'M' suffix.

    Try this in console app:

     Console.WriteLine(Math.Round(9.915, 2, MidpointRounding.AwayFromZero));
     Console.WriteLine(Math.Round(9.915M, 2, MidpointRounding.AwayFromZero));

    This will produce output:

    9.91
    9.92
    

    Because the second line uses 9.915M, telling C# to read the value as a decimal and using the overload Math.Round(decimal).

    Thursday, March 3, 2016 9:24 AM
  • "If it is working in decimal then why it is not working for double?"

    There are various reasons why double computations can produce less than expected results.

    The very general explanation is that double has a fixed (and finite) precision so there's always the possibility that the result of an operation cannot be exactly represented in a double. But that's true for decimal as well. For example, neither decimal nor double can exactly represent the result of 1/3.

    But in the specific case of rounding to a certain number of digits the main problem is that double uses a base 2 representation while decimal uses a base 10 representation. It's easy and precise to chop of digits from a base 10 number but it's more difficult and imprecise to do the same thing with a base 2 number.

    Round(x, 2) multiplies x by 100.0, rounds the result to an integral number and then divides by 100.0. The initial multiplication can introduce a tiny "error" that is then amplified by rounding to integer. This can be seen if you try the following code:

    Console.WriteLine(9.915 * 100.0 - 991.5);

    This prints something like -1.13686837721616E-13 and not 0. This value is very small and for typical double computation it's perfectly OK. But this small value is enough to move the original value below the midpoint and then rounding to integer produces a value that's off by far more than 1E-13.

    Friday, March 4, 2016 6:45 AM
    Moderator
  • "Math.Round() functionality giving wrong result in this below scenario."

    The result is correct given the way floating point rounding to a specified number of decimals works, read the Rounding and precision section from the MSDN documentation.

    "Please let me know the right way to get the desired result."

    It depends on why you need this and why you use floating point in the first place.

    • if the values you are trying to round represent currency then you should use decimal instead of double, rounding decimal values like works fine (I haven't tested).
    • if rounding is done for display purposes then consider using a format string that limits the number of decimals to 2 instead of using Math.Round, that usually works better. For example: 9.915.ToString("f2") produces 9.92.
    • if neither of the above are true then you should consider if such rounding is needed. It's an unusual operation in floating point code.

    Thursday, March 3, 2016 9:13 AM
    Moderator

All replies

  • "Math.Round() functionality giving wrong result in this below scenario."

    The result is correct given the way floating point rounding to a specified number of decimals works, read the Rounding and precision section from the MSDN documentation.

    "Please let me know the right way to get the desired result."

    It depends on why you need this and why you use floating point in the first place.

    • if the values you are trying to round represent currency then you should use decimal instead of double, rounding decimal values like works fine (I haven't tested).
    • if rounding is done for display purposes then consider using a format string that limits the number of decimals to 2 instead of using Math.Round, that usually works better. For example: 9.915.ToString("f2") produces 9.92.
    • if neither of the above are true then you should consider if such rounding is needed. It's an unusual operation in floating point code.

    Thursday, March 3, 2016 9:13 AM
    Moderator
  • Just to add to previous answer: doubles have a larger range but are not as precise as decimals. Decimals are more precise but use up slightly more memory (and are a bit slower I believe).

    If you just use a constant number in your program as in your example, C# will assume double and use the appropriate overload of Math.Round(double).

    If you want to tell C# that your number should actually be read as a decimal then use the 'M' suffix.

    Try this in console app:

     Console.WriteLine(Math.Round(9.915, 2, MidpointRounding.AwayFromZero));
     Console.WriteLine(Math.Round(9.915M, 2, MidpointRounding.AwayFromZero));

    This will produce output:

    9.91
    9.92
    

    Because the second line uses 9.915M, telling C# to read the value as a decimal and using the overload Math.Round(decimal).

    Thursday, March 3, 2016 9:24 AM
  • I understand what you try to say.. But adding M changes 9.915 to decimal no.. Before posting this question I have already tried using M and it is working fine.. If it is working in decimal then why it is not working for double??????
    Friday, March 4, 2016 4:16 AM
  • "If it is working in decimal then why it is not working for double?"

    There are various reasons why double computations can produce less than expected results.

    The very general explanation is that double has a fixed (and finite) precision so there's always the possibility that the result of an operation cannot be exactly represented in a double. But that's true for decimal as well. For example, neither decimal nor double can exactly represent the result of 1/3.

    But in the specific case of rounding to a certain number of digits the main problem is that double uses a base 2 representation while decimal uses a base 10 representation. It's easy and precise to chop of digits from a base 10 number but it's more difficult and imprecise to do the same thing with a base 2 number.

    Round(x, 2) multiplies x by 100.0, rounds the result to an integral number and then divides by 100.0. The initial multiplication can introduce a tiny "error" that is then amplified by rounding to integer. This can be seen if you try the following code:

    Console.WriteLine(9.915 * 100.0 - 991.5);

    This prints something like -1.13686837721616E-13 and not 0. This value is very small and for typical double computation it's perfectly OK. But this small value is enough to move the original value below the midpoint and then rounding to integer produces a value that's off by far more than 1E-13.

    Friday, March 4, 2016 6:45 AM
    Moderator
  • Hi biplabsmt,

    You could try using the below code. I think it solves your problem. So the trick is when you round the value declare it as decimal then it works. Hope this helps you.

    using System;
    
    namespace MathRound
    {
        class Program
        {
            static void Main(string[] args)
            {
                double a = 9.915;
                Console.WriteLine(Math.Round((decimal)a, 2, MidpointRounding.AwayFromZero));
                //Console.WriteLine(Math.Round((decimal)a, 2);
                Console.ReadLine();
            }
        }
    }
    

    Thanks,

    Sabah Shariq



    Friday, March 4, 2016 10:33 AM
  • In theory converting to decimal and rounding like this should always work because both conversions (from double to string and from double to decimal) are basically base 2 to base 10 conversions. If the double converted to string ends up as 9.915 then the same double converted to decimal should also end up as 9.915. But these conversions are handled by entirely different pieces of code so I wouldn't be too surprised to see that 9.915 converted to decimal ends up as 9.91499999...

    This seems to actually work fine in the case of 9.915 but you may have surprises for other values.

    Sunday, March 6, 2016 7:05 PM
    Moderator