0

Possible Duplicates:
In C#: Math.Round(2.5) result is 2 (instead of 3)! Are you kidding me?
.Net Round Bug

I have a halfway value (number.5) and I need to specify how this will be rounded (upper or lower value.)

I understand the behaviour of Math.Round with the MidPointRounding parameter but that does not solve my problem:

// To Even
Console.WriteLine(Math.Round(4.4)); // 4
Console.WriteLine(Math.Round(4.5)); // 4
Console.WriteLine(Math.Round(4.6)); // 5
Console.WriteLine(Math.Round(5.5)); // 6

// AwayFromZero
Console.WriteLine(Math.Round(4.4)); // 4
Console.WriteLine(Math.Round(4.5)); // 5
Console.WriteLine(Math.Round(4.6)); // 5
Console.WriteLine(Math.Round(5.5)); // 6

// in one case I need 
Console.WriteLine(Math.Round(4.4)); // 4
Console.WriteLine(Math.Round(4.5)); // 4
Console.WriteLine(Math.Round(4.6)); // 5
Console.WriteLine(Math.Round(5.5)); // 5

// another case I need
Console.WriteLine(Math.Round(4.4)); // 4
Console.WriteLine(Math.Round(4.5)); // 5
Console.WriteLine(Math.Round(4.6)); // 5
Console.WriteLine(Math.Round(5.5)); // 6
Community
  • 1
  • 1
thedev
  • 2,816
  • 8
  • 34
  • 47
  • http://stackoverflow.com/questions/977796/in-c-math-round2-5-result-is-2-instead-of-3-are-you-kidding-me – CodesInChaos Mar 02 '11 at 09:03
  • this is not a dup, he is looking for a way to midpoint round towards zero or possible towards -inf (can't tell which cos all the examples are positive) – jk. Mar 02 '11 at 10:16

6 Answers6

5

You have a overload to Math.Round that take a enum value from MidpointRounding.

This has two options:

  • ToEven (default) Also called bankers rounding. Will round to the nearest pair. So 2.5 becomes 2, while 3.5 becomes 4.
  • AwayFromZero: Always round X.5 up to X+1; So 2.5 for example becomes 3.
Øyvind Bråthen
  • 59,338
  • 27
  • 124
  • 151
  • If i use Math.Round(3.5,MidpointRounding.ToEven) will always be 4 but I need it to be 3 in some cases – thedev Mar 02 '11 at 09:07
  • And in which cases do you need it to be 3? If you can mention the cases, maybe I can find a solution for you :) Probably it will involve Math.Floor() or Math.Ceiling() as other have mentioned. – Øyvind Bråthen Mar 02 '11 at 09:12
  • I think I will need to manually check if I have a halfway value (x.5) and use Floor or Ceiling depending on the case – thedev Mar 02 '11 at 09:26
  • 1
    So something like `if( myValue % 1 == 0.5) FloorOrCeil();`. One thing to remember here is that if you are using the `double` type, 0.5 might not be exactly 0.5 because of floating point precision, so either you should use another data type like `decimal`, or you need to add a small slack to 0.5 so that values that are "close enough" also count as 0.5. – Øyvind Bråthen Mar 02 '11 at 09:52
  • 1
    eh? .5 is exactly representable in floating point, if you are not exactly at .5 you don't want to do midpoint rounding anyway – jk. Mar 02 '11 at 10:12
  • @jk - The problem is that this is not always true. One example: `double sum = 0; for( int i = 0; i < 5000; i++ ) sum += 0.00001;`. Here you would assume sum is 0.5 and a candidate for "halfway rounding", but sum is in fact 0.0500000000000046. You can read more about this here: http://support.microsoft.com/kb/42980 – Øyvind Bråthen Mar 02 '11 at 11:07
  • that is irrelevant here. mid point rounding only occurs at exactly .5 by definition. eg. Math.Round does not consider 0.5000000046 to be 'close enough' to 0.5 to round it to 0, it rounds it to 1 – jk. Mar 02 '11 at 11:52
  • @jk - And that is my point exactly. In my example OP probably want to *treat* the value as 0.5, and therefore either round it up and down according to his own logic by using Floor or Ceiling. So his if-test should take a minor difference into consideration **if** he want to compensate for floating point precision errors. – Øyvind Bråthen Mar 02 '11 at 13:05
5

It seems like what you want is a non-existant MidpointRounding value of TowardsZero or TowardsNegativeInfinity. The only option is to code the rounding yourself.

perhaps something like this: (not tested, and probably doesn't deal well with inf/nan etc)

double RoundTowardNegInfinity(double val)
{
  var frac = val - Math.Truncate(val);
  if (frac == 0.5 || frac == -0.5)
  {
    return Math.Floor(val);
  }
  return Math.Round(val);
}

double RoundTowardZero(double val)
{
  var frac = val - Math.Truncate(val);
  if (frac == 0.5 || frac == -0.5)
  {
    return Math.Truncate(val);
  }
  return Math.Round(val);
}
jk.
  • 13,817
  • 5
  • 37
  • 50
  • 1
    note this is one of the few cases where comparing floating point numbers for equality is the correct thing to do! – jk. Feb 16 '12 at 14:28
2

The Round method has two different ways of rounding that you can specify:

value = Math.Round(value, MidpointRounding.ToEven);

and:

value = Math.Round(value, MidpointRounding.AwayFromZero);

(If you don't specify a MidpointRounding value, ToEven is used.)

If you want to want to round up, you use the Ceiling method instead:

value = Math.Ceiling(value);

If you want to round down, you use the Floor method:

value = Math.Floor(value);
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
1

Take a look at the Math.Round() call that takes a MidpointRounding argument. With it, you can specify ToEven (rounded towards the nearest even number) or AwayFromZero (rounded to the nearest number in the direction away from zero) to alter the rounding behaviour.

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
adrianbanks
  • 81,306
  • 22
  • 176
  • 206
1

You can use Math.Round(), Math.Ceiling() or Math.Floor() depending on your needs.

Nick
  • 25,026
  • 7
  • 51
  • 83
1

Have a look at http://msdn.microsoft.com/en-us/library/ms131274.aspx, you can use the Math.Round(Decimal, MidpointRounding) for this.

KBoek
  • 5,794
  • 5
  • 32
  • 49