2020/04/26

A gotcha on python's round method (Banker's rounding)

Before studying the gotcha, let’s have a quiz, and see whether you will fall into the trap on round() or not.
Try to round below 22 float numbers to nearest integer, and see whether you can get them all correct. Below is the quiz in python.
floatNumbers = [1.1, 1.2, 1.3, 1.4, 1.49, 1.5, 1.51, 1.6, 1.7, 1.8, 1.9]
roundNumbers = list(map(round, floatNumbers))
formatFloatNumbers = ['%.02f' % num for num in floatNumbers]
formatRoundNumbers = ['%.02f' % num for num in roundNumbers]
print('Q', formatFloatNumbers)
print('A', formatRoundNumbers)

floatNumbers = [2.1, 2.2, 2.3, 2.4, 2.49, 2.5, 2.51, 2.6, 2.7, 2.8, 2.9]
roundNumbers = list(map(round, floatNumbers))
formatFloatNumbers = ['%.02f' % num for num in floatNumbers]
formatRoundNumbers = ['%.02f' % num for num in roundNumbers]
print('Q', formatFloatNumbers)
print('A', formatRoundNumbers)
Below is the answer.
Q ['1.10', '1.20', '1.30', '1.40', '1.49', '1.50', '1.51', '1.60', '1.70', '1.80', '1.90']
A ['1.00', '1.00', '1.00', '1.00', '1.00', '2.00', '2.00', '2.00', '2.00', '2.00', '2.00']
Q ['2.10', '2.20', '2.30', '2.40', '2.49', '2.50', '2.51', '2.60', '2.70', '2.80', '2.90']
A ['2.00', '2.00', '2.00', '2.00', '2.00', '2.00', '3.00', '3.00', '3.00', '3.00', '3.00']
The gotcha is on 2.50 case. Result of rounding 2.50 will be 2.00 instead of 3.00. And, this is a default, and correct behavior on rounding.

Why?

This rounding behavior is named as Round half to even
In short, this is a limitation from hardware. Since I am not going to go through the hardware’s limitation here, I suggest you to read this to have a full picture on them.
In fact, I would like to focus on another naming of this rounding: Banker's Rounding

Banker’s Rounding

Beside surprised by the behavior, I am also surprised on another name of this rounding technique, which is Banker's Rounding.
As the name stated, it is a rounding used by banks. So, why would banks adopt this strange rounding at all? Interestingly, this is because of Fairness.
Earning money is a job of banks (and for all companies). But, banks need to do it in a legal, and fair way. Rounding is essential on bank’s deals. For example, time deposits, and credit card’s loan etc. To round up / round down a number to the nearest integer, there are 9 cases (from 0.1 to 0.9).
Numbers will be evenly distributed among these 9 cases in statistical point of view. Banks round down numbers in 0.1 ~ 0.4 while round up numbers in 0.6 ~ 0.9. Chances for banks paying more or lesser is even (fairness) for these 8 cases. The problematic case is 0.5. If banks round up on 0.5, it will pay much more (5 cases), investors must be angry about that. Vice versa, if banks round down on 0.5, clients must be mad about that.
As a result, banks adopt round half to even to fix this fairness issues. After adopting this rounding, a single 0.5 case will be divided into 2 cases (even or odd cases). Banks will have equal chances on rounding up / down numbers. That’s why it is also named as Banker's rounding
IMO, this is a really clever trick to make every parties happy.

References

沒有留言:

張貼留言