14,271,804 members

# How .NET's Math.Round has Nothing to do with Maths. And That's OK!

Rate this:
5 Jan 2019CPOL
About the unexpected behaviour of .NET's Math.Round

## Introduction

Before we start, imagine what values "`a`" and "`b`" would have after running the following:

```a = Math.Round(1.5);
b = Math.Round(2.5);```

If your answer is "`a = 2` and `b = 3`", you are, just like I was, wrong. The correct answer is that both `a` and `b` end up becoming `2`. Confused? You might want to stick around for the reason why.

## Background

About a week ago, I was working on some code that was moving two entities along the x-axis. Inside the library, their `x` value was a `double`, but the `public` interface only allowed for meters in the form of an integer. I used `Math.Round` to translate the `double` value into that integer.

One of the requirements for the code was that the entities could never be closer than one meter to each other. I used the rounded value to check this.

As you might have guessed by now, the code kept failing. Even though both entities started out exactly one meter apart, had the same starting speed and were accelerating with the same speed, using the same algorithm, the integer value kept returning the same `x` value once in a while and thus the code kept failing.

At first, I thought it was some kind of precision error as a result of using `double` values. But this wouldn't make much sense, as the algorithm would result in the same precision loss in both values. After some debugging, I eventually found out it was not the `double` but `Math.Round` that was behaving differently than I had anticipated.

## Bankers Rounding

After I had figured out the problem was with the use of `Math.Round`, I quickly figured out the problem: the default[1] implementation for rounding in .NET is "Round half to even"[2] a.k.a. "Bankers Rounding". This means that mid point values are rounded towards the nearest even number. In the example I provided in the introduction, this means both values are being round towards `2`, the nearest even number.

So why was it implemented like this in .NET? Is it a bug?

Well, when first implemented, Microsoft followed the IEEE 754 standard. This is the reason of the default `Math.Round` implementation.[3] (Note: The current IEEE 754 standard contains five rounding rules[4])

Another good reason is that bankers rounding does not suffer from negative or positive bias as much as the round half away from zero method over most reasonable distributions.

## Round Half Away From Zero

But all is not lost.

If you expect `1.5` to be rounded to `2` and `2.5` to be rounded to `3` (like I expected), the `Math.Round` method has an override that allows you to use the "Round half away from zero"[5] method instead.

```a = Math.Round(1.5, MidpointRounding.AwayFromZero);
b = Math.Round(2.5, MidpointRounding.AwayFromZero);```

In the code snippet above, `1.5` is rounded to `2` and `2.5` is rounded to `3`.

## Round Half Up

Interestingly however, after doing some research, it looks like "Round half away from zero" is also not the method commonly used in maths. Instead, the "Round half up"[6] method is usually used[7] in maths. For positive numbers, there is no difference, but for negative numbers, mid point values are rounded towards +∞ instead of away from 0.

This way, there are the same amount of fractions being rounded to zero, while in the "Round half away from zero" method, both `0.5` and `-0.5` are not rounded to zero, making zero an exception to all other numbers.

## Math ≠ maths

So it turns out that the `Math.Round` method does not even support the actual rounding method that is commonly used in maths.

When I first discovered this, I was quite disappointed. After all, even with the good reasons that were provided, the library is still called `Math`. It does seem to communicate a certain intent.

But writing this article did make me think: before looking into it, I was not even aware there were so many rounding methods. Each with its own pros and cons. Each with its own consequences. If I didn't know about all these methods, I certainly did not know about those consequences. So maybe it is not such a bad thing that someone else did this for me, and made the appropriate "default" decision.

After all, if the consequences of your rounding are that critical to your code, I do hope that you don't make the assumptions I did, or at least discover they were wrong with some good old fashion tests.

## Wrapping Up

Even though this subject isn't really brain surgery (or rocket science for that matter), I do hope you learned something new, or at least enjoyed the read.

In the end, I think this is a good reminder of how complex even the seemingly simple things we use every day can be. And there is probably a lesson about assumptions in here as well. ;)

Happy rounding!

## Other Programming Languages

After discussing this subject with others, I got curious how other languages handle the mid point values. I was happily surprised that almost every language did have this subject covered. However, there are a lot of differences between languages.

To hopefully help someone in the future, I have mapped the rounding methods in a table. X's in bold are default implementations, other X's are optional parameters or separate methods.

In an attempt to not clutter the references list, the language names in the table link to the documentation I used.

Without further ado, the big "programming language/rounding method table":

 Round half up Round half down Round half towards zero Round half away from zero Round half to even Round half to odd Random tie-breaking Java C Python* C++ VB .NET Java Script C# PHP Objective C MATLAB R Perl Swift Go Delphi Ruby** X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X

* The table references Python 3.7 but Python 2 actually has a different round implementation. It will round half away form zero.
** The mode keywords in Ruby are `:up` for "round half away from zero" and `:down` for "round half towards zero", making them quite confusing in my opinion.

As I have no experience with most of these languages, feel free to point out any mistakes. I will correct the table accordingly.

## History

• 23-12-2018 - Version 1
• 23-12-2018 - Version 1.1
• Minor textual changes
• 24-12-2018 - Version 1.2
• Clarified example
• 26-12-2018 - Version 1.3
• Minor textual change
• 05-01-2018 - Version 2.0

## License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

## About the Author

 Software Developer Netherlands
Jasper is part of an amazing development team at Vanderlande, where he is a software developer working with C#. His main focus when coding is quality and readability, and he is experienced in a broad range of subjects (Software design, testing, UI, simulation, multithreading, networking and more).

His passion for programming can be traced back to his pre-professional days. Where, even as an elementary school student he could be found on the computer creating computer games. The reason? There is just no feeling like being able to think something up, create it, and then see others enjoy it.

Outside the office, he's a contributor to the Code Project and there is always a project he's working on. When he's not coding he likes to make and edit video’s, can discuss theoretical physics for hours and if you challenge him to a board game, he won’t say no. He can also frequently be found in the gym and travels when he can.

## Comments and Discussions

 First PrevNext
 Thanks Kuber Vats30-Jan-19 19:00 Kuber Vats 30-Jan-19 19:00
 Neg. nos.? Darryl Bryk2-Jan-19 7:26 Darryl Bryk 2-Jan-19 7:26
 Re: Neg. nos.? Jasper Lammers2-Jan-19 20:20 Jasper Lammers 2-Jan-19 20:20
 5/5 Frans Vdm28-Dec-18 22:43 Frans Vdm 28-Dec-18 22:43
 Rounding Hillmann27-Dec-18 21:09 Hillmann 27-Dec-18 21:09
 Fun read. JJVH8427-Dec-18 1:20 JJVH84 27-Dec-18 1:20
 My vote of 5 Irene Troupansky26-Dec-18 4:31 Irene Troupansky 26-Dec-18 4:31
 Statistical Analysis has nothing to do with Maths? mtryczak26-Dec-18 0:16 mtryczak 26-Dec-18 0:16
 Re: Statistical Analysis has nothing to do with Maths? Jasper Lammers26-Dec-18 1:52 Jasper Lammers 26-Dec-18 1:52
 Re: Statistical Analysis has nothing to do with Maths? MKJCP27-Dec-18 7:37 MKJCP 27-Dec-18 7:37
 Good to know Member 1153395725-Dec-18 16:05 Member 11533957 25-Dec-18 16:05
 "Maths" LOL Pong God25-Dec-18 10:39 Pong God 25-Dec-18 10:39
 Re: "Maths" LOL Jasper Lammers25-Dec-18 20:31 Jasper Lammers 25-Dec-18 20:31
 Re: "Maths" LOL Pong God26-Dec-18 4:51 Pong God 26-Dec-18 4:51
 Re: "Maths" LOL Jasper Lammers27-Dec-18 0:15 Jasper Lammers 27-Dec-18 0:15
 Re: "Maths" LOL DaveBoltman1-Jan-19 20:55 DaveBoltman 1-Jan-19 20:55
 Re: "Maths" LOL Pong God7-Jan-19 9:43 Pong God 7-Jan-19 9:43
 Re: "Maths" LOL JRickey7-Jan-19 11:48 JRickey 7-Jan-19 11:48
 Re: "Maths" LOL Pong God7-Jan-19 17:26 Pong God 7-Jan-19 17:26
 Re: "Maths" LOL DaveBoltman7-Jan-19 21:09 DaveBoltman 7-Jan-19 21:09
 Excellent Thanks787225-Dec-18 7:34 Thanks7872 25-Dec-18 7:34
 Similar discovery on rounding nedcove25-Dec-18 7:24 nedcove 25-Dec-18 7:24
 Re: Similar discovery on rounding Jasper Lammers25-Dec-18 20:31 Jasper Lammers 25-Dec-18 20:31
 .Net uses the wrong (unexpected) default parameter snoopy00125-Dec-18 1:57 snoopy001 25-Dec-18 1:57
 Re: .Net uses the wrong (unexpected) default parameter Jasper Lammers12-Jan-19 11:04 Jasper Lammers 12-Jan-19 11:04
 Last Visit: 24-Aug-19 11:01     Last Update: 24-Aug-19 11:01 Refresh 12 Next »

General    News    Suggestion    Question    Bug    Answer    Joke    Praise    Rant    Admin

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Tip/Trick
Posted 23 Dec 2018

21.4K views
15 bookmarked