1

I used Math.Round like Math.Round(value, precision). The precision is 3.

when I used for value = 0.0015 the result will be 0.002

when I used for value = 0.0025 the result still be 0.002

It seems like when the last digit is even number it will round down but it will round up when the last digit is an odd number.

How to solve this problem?

Additional: In silverlight, there is no MidpointRounding

user3089631
  • 169
  • 1
  • 7
  • Are you dealing with `double` or with `decimal` values? `0.0015` and `0.0025` are `double` constants, but unless they're exactly representable, you won't have *that* problem with `double`, you'll just have a different problem. –  Feb 18 '14 at 06:07
  • 2
    Possible duplicate : http://stackoverflow.com/questions/7968485/math-round-seems-to-be-not-consistent?rq=1 – Jonas W Feb 18 '14 at 06:35

3 Answers3

1

By selecting a different rounding type see http://msdn.microsoft.com/en-us/library/f5898377(v=vs.110).aspx

From that link:

using System;

public class Example
{
   public static void Main()
   {
      double[] values = { 2.125, 2.135, 2.145, 3.125, 3.135, 3.145 };
      foreach (double value in values)
         Console.WriteLine("{0} --> {1}", value, 
                           Math.Round(value, 2, MidpointRounding.AwayFromZero));

   }
}
// The example displays the following output: 
//       2.125 --> 2.13 
//       2.135 --> 2.13 
//       2.145 --> 2.15 
//       3.125 --> 3.13 
//       3.135 --> 3.14 
//       3.145 --> 3.15

More info: http://msdn.microsoft.com/en-us/library/system.midpointrounding(v=vs.110).aspx

As noted by a commentator 2.135 --> 2.13 doesn't look right. This is because of floating point accuracies. The original article states:

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. This is illustrated in the following example, where 2.135 is rounded to 2.13 instead of 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.

NPSF3000
  • 2,421
  • 15
  • 20
  • 1
    2.135 -> 2.13 doesn't look like "away from zero" to me. Then again, I don't think 2.135 is exactly halfway between 2.13m and 2.14m. –  Feb 18 '14 at 06:05
  • So how can I round 2.135 --> 2.14 ?? – John Nguyen Jul 23 '14 at 05:22
  • @JohnNguyen MidpointRounding will work, the problem is that 2.1349 (etc) could be rounded to 2.135 when displayed with default formatting, but round down to 2.13 when rounded properly. – NPSF3000 Jul 23 '14 at 05:32
  • Sory, but I still didn't get you mean. I need round 2.135 to 2.14 (etc) but I tried `Math.Round(2.135, 2, MidpointRounding.AwayFromZero));` and `Math.Round(2.135, 2, MidpointRounding.ToEven));` both of them is 2.13 – John Nguyen Jul 23 '14 at 05:41
  • @JohnNguyen I actually don't know, I digged into it a bit and could not prove the error. – NPSF3000 Jul 23 '14 at 11:09
0

For Decimals, you could use

Decimal RoundAwayFromZero(Decimal v)
{
    return Math.Truncate(v + (v < 0m ? -.5m : .5m));
}

and the same for Doubles:

Double RoundAwayFromZero(Double v)
{
    return Math.Truncate(v + (v < 0.0 ? -.5 : .5));
}

Trivia: Truncate can also be expressed with modulo - here for Decimals:

Decimal Truncate(Decimal v)
{
    return v - (v % 1m);
}

For the rounding with explicit precision multiply before rounding, again here for Decimals:

Decimal RoundAwayFromZero(Decimal v, Int32 p)
{
    var f = (Decimal)Math.Pow(10, p);

    return RoundAwayFromZero(v * f) / f;
}
John
  • 6,693
  • 3
  • 51
  • 90
0

my current solution is implement my rounding method as below.

    private double Rounding(double value, int Precision)
    {
        double result = value;
        if (result.ToString().EndsWith("5"))
        {
            var power = result.ToString().LastIndexOf("5") - 1;
            if (power > Precision)
            {
                result = result + (1 / Math.Pow(10, power));
            }
        }
        result = Math.Round(result, Precision);
        return result;
    }
user3089631
  • 169
  • 1
  • 7
  • Scary and broken in many ways. :-) What if the number is greater than 1? More importantly, `.ToString()` itself already does rounding, for example: `Double.Parse( (5 / 9.0).ToString() ) > 0.555555555555555555555556` gives true, even though it's false. – John Feb 19 '14 at 09:50