Math.Round
This C# method rounds numbers to the nearest value. It receives the desired number of significant digits. It is part of the System
namespace.
This static
method provides an accurate way to round double
and decimal types. It reduces the risk of bugs and can make programs have more consistent output.
To begin, consider this simple example of calling Math.Round
. The fractional part of 1.234 is removed, as it is closer to 1 than 2, and we are left with a result of 1.
using System; double value = 1.234; Console.WriteLine("ROUND: {0}", Math.Round(value));ROUND: 1
Math.Round
has several overloads and 2 rounding modes defined on the MidpointRounding
enum
. Here we round an example double
and decimal type.
Math.Round
will return with different arguments. We use 1, 2 and 3 arguments.double
or decimal type.using System; // // 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);123.45 123.5 123.4 123 125.101 125 125.1
MidpointRounding
What is the difference between MidpointRounding.ToEven
and MidpointRounding.AwayFromZero
? My testing indicates that the difference is found when rounding the number 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.using System; 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)); }0.1=(0,0) 0.2=(0,0) 0.30000000000000004=(0,0) 0.4=(0,0) 0.5=(0,1) 0.6=(1,1) 0.7=(1,1) 0.7999999999999999=(1,1) 0.8999999999999999=(1,1)
How does Math.Round
affect performance? I benchmarked Math.Round
to get a general idea. Sometimes using a local cache can speed up this logic.
Math.Round
with a second argument of 0. The result is tested against in an if
-statement.Math.Round
again, but with a second argument of 1.Math.Round
calls are slower than a local variable load, but not slow enough to be a big concern.Math.Round
in this program was made several times faster—the results are impressive.using System; using System.Diagnostics; const int _max = 100000000; // Version 1: use Math.Round with argument of 0. 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(); // Version 2: use Math.Round with argument of 1. 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"));5.52 ns Math.Round, 0 4.91 ns Math.Round, 1
Certain computations could be optimized by avoiding Math.Round
, or by caching its results. An if
-statement would evaluate faster.
Numbers can be rounded with the Math.Round
method. We used the MidpointRounding
enumerated type. And we learned how to round numbers "away from zero" and to the nearest even number.