Rounding Ain’t So Round
This is part 3/10 from my talk “10 Things You Didn’t Know About C#”, from Utah Code Camp 2014.
Remember learning how to round in elementary school? Most of us learned that the decimal rounds to the nearest whole number, and that half always rounds away from zero.
Interestingly, this is not what C# does by default, and being unaware of it might cause unexpected results.
C#’s default method for rounding is called half-to-even rounding, or sometimes “Banker’s Rounding”. True to the name, this rule states that half will always round to the nearest even number. This type of rounding is more precise over many calculations because it eliminates the bias that rounding away from zero creates. This bias-eliminating property is one of the reasons this type of rounding is recommended in the IEEE 754 standard for rounding in floating-point numbers.
There is one other type of rounding you need to know about from the IEEE spec. It is known as Round-toward-zero, but you might know it as truncation. This type of rounding simply removes any decimal, producing a whole number, and is always biased toward zero.
Getting Expected Results
What if you want to round the way you are used to? Fortunately, Microsoft has you partially covered. The System.MidpointRounding enum lists both AwayFromZero, and ToEven as valid rounding types.
Math.Round() will let you round however you want, but by default will apply Half-to-even rounding.
Convert.ToInt32() and variants do not give you the luxury of choosing your rounding type, and will always apply Half-to-even rounding.
Lets look at some comparisons. Here is the code:
And the output:
Take note that we have two different answers for any index, and three different lists!
Moral of the story: Be careful in how you choose to handle your decimals. Accuracy matters!