Friday, February 6, 2009

Rounding to the nearest 1000 in C#

Working on that demo app, this came up - I wanted a number rounded to the nearest 1000. This is easy enough in Excel - the ROUND function takes negative values, so that =ROUND(2009,-3) will give you 2000. The Math.Round function in System.dll doesn't offer this functionality however - you have to implement that yourself. Here's an example of one way to do this:

using System;
 
static class Program
{
    static void Main(string[] args)
    {
        double d = (double)new Random().Next();
        // round to the nearest 1000
        Console.WriteLine("{0} rounded to the nearest thousand is {1}", d, Round(d, -3));
        // round to the nearest 100 etc
        Console.WriteLine("{0} rounded to the nearest hundred is {1}", d, Round(d, -2));
    }
 
    static double Round(double value, int digits)
    {
        if ((digits < -15) || (digits > 15))
            throw new ArgumentOutOfRangeException("digits", "Rounding digits must be between -15 and 15, inclusive.");
 
        if (digits >= 0)
            return Math.Round(value, digits);
 
        double n = Math.Pow(10, -digits);
        return Math.Round(value / n, 0) * n;
    }
 
    static decimal Round(decimal d, int decimals)
    {
        if ((decimals < -28) || (decimals > 28))
            throw new ArgumentOutOfRangeException("decimals", "Rounding decimals must be between -28 and 28, inclusive.");
 
        if (decimals >= 0)
            return decimal.Round(d, decimals);
 
        decimal n = (decimal)Math.Pow(10, -decimals);
        return decimal.Round(d / n, 0) * n;
    }
}

4 comments:

Jarda said...

If you need only number why not to use smth like. Only need to check that result value will not overflow int.maxValue

int mod = value % 1000;
if(mod>0)
{
value += 1000 - rest;
}

Anonymous said...

Your solution works fine but it works rather slow. On the following website I found methods that work about 5 times faster: http://cboard.cprogramming.com/csharp-programming/75260-return-value-nearest-100-a.html

I think you should avoid usage of Math.Pow...

kr

txs8311 said...

Thanks kr - I tested your suggestion on my machine. Avoiding Math.Pow was indeed quicker - about 3 times for integers, twice as fast for doubles.

Anonymous said...

decimal amount1 = 87347.21m;

int roundTo = 1000;
int closestToOneThousand = (int)(((double)amount1 + (0.5 * roundTo)) / roundTo) * roundTo;

Console.WriteLine(closestToOneThousand);

This is better.