Here's an extension method that uses simple logic and System.Math
methods (which may be more optimized).
using System;
public static class NumericRoundingExtensions
{
/// <summary>
/// Rounds a number to the nearest multiple of another number
/// </summary>
/// <param name="value">The value to round</param>
/// <param name="factor">The factor to round to a multiple of. Must not be zero.</param>
/// <param name="mode">Defines direction to round if <paramref name="value"/> is exactly halfway between two multiples of <paramref name="factor"/></param>
/// <remarks>
/// Use with caution when <paramref name="value"/> is large or <paramref name="factor"/> is small.
/// </remarks>
/// <exception cref="DivideByZeroException">If <paramref name="factor"/> is zero</exception>
public static double RoundToNearestMultipleOfFactor(this double value, double factor, MidpointRounding mode = MidpointRounding.AwayFromZero)
{
return Math.Round(value / factor, mode) * factor;
}
}
If you are using .Net Framework, then the mode can be AwayFromZero
or ToEven
. If you are using a newer version of .Net, there are six different modes for handling values that are halfway between two multiples of the factor. Midpoint Rounding documentation
I found this question searching for a method for long
values that doesn't convert to floating point. If you happen to be working with integral types, like long or int, then it is best to use the following:
public static long RoundToNearestMultipleOfFactor(this long value, long factor)
{
if (factor == 0)
{
throw new ArgumentOutOfRangeException(nameof(factor), factor, "Cannot be zero");
}
var halfAbsFactor = Math.Abs(factor) >> 1;
return value + Math.Sign(value) * (halfAbsFactor - (Math.Abs(value) % factor + halfAbsFactor % factor) % factor);
}
For a full extension method class for integral types, see my answer to a similar question