As you know, Ethereum smart contracts can’t handle real (floating point) numbers easily. So, we all work with integers.
Still, if you work with percentages, you will have to divide one number by another. That’s where rounding comes in. For example, imagine you need to send “13% as dividends” to the account A. What if you have 10 tokens to split? Should you round 1.3 tokens to 1 or 2? It’s obvious that 1.3 should be rounded to 1. It’s high school math, nothing interesting.
There are common approaches to dealing with real numbers in smart contracts. Some store the numerator and denominator as separate variables so you can describe 1/3 by storing 1 in the numerator and 3 in the denominator, but that’s a different story for another time.
The story begins when you have to round 1.5. What if we always round it to 1? Your system will accumulate the error and your investor will ALWAYS loose dividends. If you round it to 2, you will ALWAYS lose money. Imagine you send dividends millions of times. Is there any way we can reduce the accumulated error?
Bankers are not necessarily always against the whole society. They have something that we can use called “bankers rounding,” aka “round-half-to-even”. The idea is that when a number is halfway between two others, it is rounded toward the nearest even number. For instance, 2.125 rounds down to 2.12. Meanwhile, 2.135 rounds up to 2.14. Other decimal fractions are rounded according to the same method: 2.122 to 2.12, 2.127 to 2.13, -2.122 to -2.12, etc. So, you won’t ALWAYS lose money, just like your client.
Ok, let’s introduce that function to the cryptocurrency world!
In crypto.tickets we use smart contracts for accounting (We call it “billing”), so when the ticket is resold on the secondary market, the event organizer receives 50% of the markup as a fee. Let’s describe how and where we use bankers rounding.
- Let feeOrg_ppm store the number of dividend ppms the event organizer should receive. Ppm stands for parts-per-million, so 1% is 10000 ppm. Eventually, feeOrg_ppm will be equal to 50000.
- Let markup_cents store the current markup, for example, 14 cents.
To calculate how much the organizer should receive, we use this simple formula:
That’s where the bankersRoundedDiv() method comes in:
If markup_cents is 14, then the event organizer will receive 7 cents.
If markup_cents is 15, then the event organizer will receive 8 cents (7.5 is rounded to the nearest even number).
If markup_cents is 17, then the event organizer will receive 8 cents (8.5 is rounded to the nearest even number which is still 8).
“Bankers Rounding” Code
The code is available here — https://github.com/cryptoticket/openzeppelin-solidity/blob/master/contracts/math/RoundedDivMath.sol#L53
Tests are available here — https://github.com/cryptoticket/openzeppelin-solidity/blob/master/test/math/RoundedDivMath.test.js
Round-half-to-even helps you minimize the accumulated error, so your client will be happy when receiving fees or dividends.
Feel free to contact me: [email protected]