Is there a way to do 'correct' arithmetical rounding in .NET? / C#

Posted by Markus on Stack Overflow See other posts from Stack Overflow or by Markus
Published on 2010-03-25T11:07:43Z Indexed on 2010/03/25 11:13 UTC
Read the original article Hit count: 379

I'm trying to round a number to it's first decimal place and, considering the different MidpointRounding options, that seems to work well. A problem arises though when that number has sunsequent decimal places that would arithmetically affect the rounding.

An example:

With 0.1, 0.11..0.19 and 0.141..0.44 it works:

Math.Round(0.1, 1) == 0.1
Math.Round(0.11, 1) == 0.1
Math.Round(0.14, 1) == 0.1
Math.Round(0.15, 1) == 0.2
Math.Round(0.141, 1) == 0.1

But with 0.141..0.149 it always returns 0.1, although 0.146..0.149 should round to 0.2:

Math.Round(0.145, 1, MidpointRounding.AwayFromZero) == 0.1
Math.Round(0.146, 1, MidpointRounding.AwayFromZero) == 0.1
Math.Round(0.146, 1, MidpointRounding.ToEven) == 0.1
Math.Round(0.146M, 1, MidpointRounding.ToEven) == 0.1M
Math.Round(0.146M, 1, MidpointRounding.AwayFromZero) == 0.1M

I tried to come up with a function that addresses this problem, and it works well for this case, but of course it glamorously fails if you try to round i.e. 0.144449 to it's first decimal digit (which should be 0.2, but results 0.1.) (That doesn't work with Math.Round() either.)

private double round(double value, int digit)
{
    // basically the old "add 0.5, then truncate to integer" trick
    double fix = 0.5D/( Math.Pow(10D, digit+1) )*( value >= 0 ? 1D : -1D );
    double fixedValue = value + fix;

    // 'truncate to integer' - shift left, round, shift right
    return Math.Round(fixedValue * Math.Pow(10D, digit)) / Math.Pow(10D, digit);
}

I assume a solution would be to enumerate all digits, find the first value larger than 4 and then round up, or else round down. Problem 1: That seems idiotic, Problem 2: I have no idea how to enumerate the digits without a gazillion of multiplications and subtractios.

Long story short: What is the best way to do that?

© Stack Overflow or respective owner

Related posts about c#

Related posts about .NET