C# Math.Round

Method call

Math.Round rounds numbers to the nearest value. It receives the desired number of significant digits. This static method provides an accurate way to round double and decimal types. It reduces the risk of bugs.

Static Method

Example

Math written on chalkboard

First, Math.Round has several overloads and two rounding modes defined on the MidpointRounding enumerated constants. Here we round an example double and decimal type. We see what Math.Round will return with different arguments.

OverloadingDoublesDecimals
Program that uses Math.Round: C#

using System;

class Program
{
    static void Main()
    {
	//
	// Round double type in three ways.
	//
	double before1 = 123.45;
	double after1 = Math.Round(before1, 1, MidpointRounding.AwayFromZero); // Rounds "up"
	double after2 = Math.Round(before1, 1, MidpointRounding.ToEven); // Rounds to even
	double after3 = Math.Round(before1);

	Console.WriteLine(before1); // Original
	Console.WriteLine(after1);
	Console.WriteLine(after2);
	Console.WriteLine(after3);

	//
	// Round decimal type.
	//
	decimal before2 = 125.101M;
	decimal after4 = Math.Round(before2);
	decimal after5 = Math.Round(before2, 1);

	Console.WriteLine(before2); // Original
	Console.WriteLine(after4);
	Console.WriteLine(after5);
    }
}

Output

123.45
123.5  <-- MidpointRounding.AwayFromZero
123.4  <-- MidpointRounding.ToEven
123

125.101
125
125.1
Framework: NET

The Math.Round method is called several times. Because the .NET Framework differentiates between a decimal type and a double type, the best overloads are automatically chosen. You can call Math.Round with one to three arguments.

Enum

The first argument is the number you are rounding. The second argument is the number of digits after the decimal place you want to keep. And the third argument is an optional rounding mode enumerated constant.

Program icon

Then:The program shows three outputs of Math.Round on a double with value 123.45.

Info:The Math.Round call that specifies one decimal place and the MidpointRounding.AwayFromZero constant rounds that value up to 123.5.

And:The Math.Round call with one decimal place and the MidpointRounding.ToEven constant rounds down to 123.4. The result is even.

MidpointRounding

Question and answer

What is the exact difference between the MidpointRounding.ToEven and MidpointRounding.AwayFromZero enumerated constants? My testing indicates that the difference is found when rounding the number 0.5.

Testing results for 0.5. MidpointRounding.ToEven will round 0.5 to 0—this is because zero is even. MidpointRounding.AwayFromZero will round 0.5 to 1—this is because one is away from zero.

Program that demonstrates MidpointRounding: C#

using System;

class Program
{
    static void Main()
    {
	for (double i = 0.1; i < 0.99; i += 0.1)
	{
	    Console.WriteLine("{0}=({1},{2})", i,
		Math.Round(i, MidpointRounding.ToEven),
		Math.Round(i, MidpointRounding.AwayFromZero));
	}
    }
}

Output

0.1=(0,0)
0.2=(0,0)
0.3=(0,0)
0.4=(0,0)
0.5=(0,1)
0.6=(1,1)
0.7=(1,1)
0.8=(1,1)
0.9=(1,1)

Note:This article had an error in its description of rounding behaviors on scientific data. Thanks to Gus Gustafson for a correction.

Performance

Performance optimization

How does Math.Round affect performance? Recently I added calls to Math.Round in a program that is performance-sensitive. How did this affect the overall efficiency of the program? I benchmarked Math.Round to get a general idea.

Program that benchmarks Math.Round: C#

using System;
using System.Diagnostics;

class Program
{
    const int _max = 100000000;
    static void Main()
    {
	var s1 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    double d = Math.Round(1.3665, 0);
	    if (d == 1.5)
	    {
		throw new Exception();
	    }
	}
	s1.Stop();
	var s2 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    double d = Math.Round(1.3665, 1);
	    if (d == 1.5)
	    {
		throw new Exception();
	    }
	}
	s2.Stop();
	Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /
	    _max).ToString("0.00 ns"));
	Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /
	    _max).ToString("0.00 ns"));
	Console.Read();
    }
}

Output

20.72 ns
25.26 ns
This section provides information

Calls to Math.Round required about 20 nanoseconds. A call with zero decimal places required less time than a call with one decimal place. It is possible that the more decimal places required, the slower the method becomes.

Also, certain computations could be optimized by avoiding Math.Round. An if-statement would evaluate faster. Simply casting a double to an int rounds down. This requires only 2 nanoseconds. Using Math.Round requires 20 nanoseconds.

IfCast to Int

Summary

We looked at the Math.Round method in the C# language. We saw an example of using the MidpointRounding enumerated type and how you can round numbers "away from zero" and also to the nearest even number.


C#: Number: Math