• Type:

CH Never Use Floats for Money (2016)

Very basic background

Humans count and perform math in base ten or denary. This means there are ten
digits to represent all numbers and the base number is ten. Thousands are 10^3,
Hundreds are 10^2 and so on. We have adopted denary, probably, due to the fact
that most of us have 10 fingers, and learned to count on our fingers. Moreover
the word digit is a bi-word for finger.

Computers count and perform math in base two or binary. This means there are 2
digits to represent all numbers. 2^3 is the fourth position, 2^2 is the third
position and so on. 110 is 1 * 2^2 + 1 * 2^1 + 0 * 2^1 = 6 in denary.

Onward

Lets say we want to divide 1/3 and represent that in denary. We would have to
represent that in a forever repeating decimal 0.333333… which is only ever
going to be a representation of the true value of 1/3. Now if we were using
ternary, or base three number representation 1/3 would actually be represented
as exactly 0.1, as the first decimal position is 3^-1 which is the same as 1/3.

So in our denary system we have an approximation of 1/3 but in ternary we have
an exact representation of .1.

This is precisely the problem we have when trying to represent 10^-1, or 0.1 in
binary. There is not an exact binary representation of 0.1 or 0.01.

Why floats are bad for money

We would think yeah, floats would be great for money, because $1.40 is 1 dollar
and 4 tenths of a dollar. There is a decimal point, to have decimal points in
code we would have to use a double or floating point type. Well floating point
types are actually binary representations of denary numbers as mentioned above.

The float type has a sign, exponent, and fraction blocks within the 32 or 64 bit
structure which can be seen on wikipedia. You can see that you
have at your disposal a 23 bit binary fraction and an 8 bit binary exponent.

Example:

I sell 165 apples at $1.40 per apple. My accounting software uses floating point
numbers for the calculation.

>>> 165 * 1.40
230.99999999999997

As you can see in this example, you would need to perform rounding yourself to
get the correct number. Here is another common example, you are changing the
the price of bananas from $1.01 to $0.99 and need to calculate the lost revenue.

>>> 1.01 - 0.99
0.020000000000000018

Again you can see the that a rounding function would need to be applied. Moreover,
if you start getting into really big numbers you start loosing granularity, and
the smaller numbers start getting eaten by the bigger numbers:

>>> 1e16 * (1.01 - 0.99) - 0.01
200000000000000.2

The above, in an exact denary calculation should be 199999999999999.99.

The more operations you perform the worse your estimation becomes.

Another option

Another option is to use plain integers to represent currency. If you make $1.01
into 101¢ and perform all your calculations on cent integers you will never run
into these floating point approximation issues, as you are no longer performing
approximations. Here are the above examples using integer cents instead:

>>> 165 * 140
23100
>>> 101 - 99
2

There is also a good explanation of different solutions here as well

Read More

Previous Post

CH Open Source Security Tools You Should Know

Next Post

CH Show HN: Bob – A GUI for DNS Record Management and Name Auctions on Handshake

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top