Disclaimer: If I were a betting man, I would bet there’s some code which does the following kicking around a forum, blog or two already.  Simply, I wasn’t lucky enough to find it.  Hence, the IF in “if I were a betting man.”

I ran into a case today where I wanted to reduce unused space in a generated chart.  I figured I could tighten up the chart if the minimum and maximum Y values were slightly beyond the min and max data point values.  For example, if the largest value in my dataset is 14, I would make the maximum value, and the corresponding Y axis label, 16. 

This fixed the real estate issue, but I didn’t like the my labels were now somewhat random and no longer looked clean.  For example, 14.64 + 2 = ugly. To get around this, I opted to pad the values to the nearest interval of 5 and helps with perceived consistency.

Original Chart


RoundToInterval() Function

Note the IntervalRounding enum below.  I consider it similar to Math.Round’s MidpointRounding enumeration where you can use MidPointRounding.ToEven to round a positive value to the nearest even number and MidPointRounding.AwayFromZero to round a value to the nearest number away from zero.  

// Sample call: Rounds 17 to 20. decimal d = RoundToInterval(17M, 5M, IntervalRounding.Up); private static decimal RoundToInterval(decimal value, decimal interval, IntervalRounding rounding) { // Guard against the divide by zero exception if (interval == 0) return decimal.MinValue; // For example, round 18 to the nearest interval of 5 // Quotient = 3.6, Remainder = 0.6, Whole = 3 decimal quotient = decimal.Divide(value, interval); decimal remainder = decimal.Subtract(quotient, decimal.Floor(quotient)); decimal whole = decimal.Subtract(quotient, remainder); // Rounding to the nearest interval and remainder // is over half way to the next interval value if (rounding == IntervalRounding.Nearest && remainder >= .5M || // Or we force rounding to the next highest interval // and we have a remainder. In otherwords, our value // isn’t on an interval already rounding == IntervalRounding.Up && remainder > 0M) { return interval * (whole + 1); } else { return interval * whole; } } public enum IntervalRounding { Nearest = 0, Up = 1, Down = 2 }

Final Chart:

The chart is now using more available space and the Y axis labels are rounded to the provided interval.  

Sorry for the blurry image.  If you really squint you can read it.  Maybe…

7 Comments to “C# RoundToInterval()”

  1. Jon Galloway says:

    It’s a little sleazy, but I think you could get away with this:

    public static int RoundToInterval(double input, int multiple)
    {
    return (int)(input+multiple-(input%multiple));
    }

    My test program:
    using System;
    using System.Collections.Generic;

    public class TestRounding
    {
    public static void Main()
    {
    Random rand = new Random(Guid.NewGuid().GetHashCode());
    for(int i=1;i

  2. Ben Griswold says:

    Yes, this works great if you’re rounding up and your interval is an int (I started down that path too.) Unfortunately, I have charts which display values from .1 – .5 and I’ve opted to round to .1. Still, I’m sure there’s a better way than what I came up with. Thanks, Jon.

  3. Michael Isaacs says:

    The following should also work:

    public static decimal RoundToInterval(decimal value,
    decimal interval, IntervalRounding rounding)
    {
    // Guard against the divide by zero exception
    if (interval == 0)
    return decimal.MinValue;

    decimal result = value / interval;

    switch (rounding)
    {
    case IntervalRounding.Nearest:
    return (decimal.Round(result, 0, MidpointRounding.AwayFromZero) * interval);
    case IntervalRounding.Up:
    return (decimal.Ceiling(result) * interval);
    case IntervalRounding.Down:
    return (decimal.Floor(result) * interval);
    default:
    return decimal.MinValue;
    }

    }

  4. bgriswold says:

    Hi Michael. I’ve run your routine through a number of tests and it works great! Your implementation is cleaner than my attempt. Well done.

  5. I have a Joomla website and already set up a Google Analytics account, now how do I add the code to my website so that it will keep track of visitors etc to every page? Thanks!.

  6. Just a few things you must recall:

Leave a Reply

You can wrap your code with [ruby][/ruby] or [python][/python] blocks for syntax highlighting and you can use these traditional tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>