October 28, 2016Clément Hannicq3 min read
We use computers every day to solve mathematical issues, from how much taxes should I apply to my users’ basket to computing next week’s weather forecast.
Solving most of those problems is nowhere near easy, and would be harder still if we didn’t use mathematics to reason, represent and compute insane amounts of data.
But the code we execute on our computers isn’t exactly the same as the doing the maths we try to represent.
For instance, the plus operator does not yield the same results as a real addition.
Don’t believe me? Run
Spoiler alert: you won’t get 0.3 (if you do, let me know which browser you are using).
This issue comes from how computers represent decimal numbers, you could try doing the same addition with python, C… and the result would be
This rounding error is caused, deep down, by the fact that our computer only can store a finite amount of data (ref. needed) when there is an infinite amount of decimal numbers (ref. needed).
Some languages, like PHP (tested with PHP 5.5.14) will actually return 0.3 for 0.1 + 0.2.
In this case do we really have a solution? Were PHP developers able to solve this problem many other languages developers failed to? Of course not, the result was simply rounded, which can be made apparent by running some other cleverly crafted additions:
0.30000000000000004 - 0.3 would yield
0.30000000000000004 - (0.1 + 0.2) would yield
One could argue that, to display the taxes amount on an amazon basket, rounding to two digits would be more than enough (on all the monetary systems I know of), and a
0.00000000000004 error on the displayed amount would be of little to no consequence.
Floats are a deadly issue, literally. See the Patriot Missile Failure on February 25, 1991, which caused the death of 28 soldiers. The main cause for that failure was that 0.1 is not a round number, as far as floats are concerned.
So yes, the gap between the mathematics we use to reason about software and its implementation can be a problem, and a deadly one.
Some of those problems have been solved on some languages using rational arithmetic instead of floating point arithmetic.
Using rational arithmetic does have a performance (both in terms of CPU and memory) impact, and does not solve all rounding errors (specially with irrational numbers).
The only solution I can recommend is to always assume that a floating point operation is inexact and be ready to handle the consequences, which means:
As we’ve seen, the implemented operators does not yield the same results as their mathematical counterparts, and they also does not share the same properties.
a + (b + c) = (a + b) + c)
a == band
b == cthen
a == c)
Web Developer at Theodo