Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Rounding of decimal type in C#

Tags:

c#

rounding

Guys, I am writing a method for rounding. Input is a decimal type (four decimal places guaranteed). The rounding rule is that 0.005 or less is ignored, i.e. look at third decimal place - if it is <= 5, round down else round up. Some use cases : 82.3657 -> 82.36, 82.3667 -> 82.37, 82.5967 -> 82.60, 82.9958 -> 82.99, 82.9968 -> 83.00 Any good ideas? I have worked it out as follows.

private decimal CustomRound(decimal x)
{
   decimal rX = Math.Truncate(x * 100) / 100;
   decimal x3DecPlaces = Math.Truncate(x * 1000) / 1000;
   decimal t = (x3DecPlaces * 1000) % 10;
   if (t >= 6)
      rX = rX + 0.01m;
   return rX;
}
like image 310
redzon Avatar asked Jan 27 '11 10:01

redzon


1 Answers

I don't believe there's anything built-in for that, because it's a pretty unusual requirement (for example the idea that 1.3358 is closer to 1.33 than to 1.34 is odd). Your code looks reasonably appropriate.

EDIT: You can't use MidpointRounding to get the effect you want here, because the point at which you start rounding up isn't the midpoint - it's (say) 1.336 rather than the normal 1.335. Only 1.335 is treated as the midpoint between 1.33 and 1.34, because that is the mid-point. You've effectively got a biased rounding here in an unusual way.

You can't even just truncate to three DP and then use MidpointRounding, as there's no "towards zero" mode.

One slightly odd option would be to effectively perform the bias yourself:

private static decimal CustomRound(decimal x)
{
    return decimal.Round(x - 0.001m, 2, MidpointRounding.AwayFromZero);
}

So it would treat 82.3657 as 82.3647 and round that to 82.36; it would treat 82.3667 and 82.3657 and round it to 82.37, and it would treat 82.5967 as 82.5957 and round it to 82.60 etc. I think that does what you want - but only for positive values. You'd need to work out exactly what behaviour you want for negative values.

Whatever you do, you need to document it very clearly :)

Just as a matter of preference, I would use decimal.Truncate rather than Math.Truncate, just to make it clearer that everything really is done with decimals.

like image 146
Jon Skeet Avatar answered Sep 29 '22 06:09

Jon Skeet