The floating point numbers are represented in computers according to the IEEE 574 standard.
In simple words, the fractional numbers are encoded in computers using a fixed number of bits (digits), in a similar way we write the real numbers on paper (we use base 10 to write the numbers, the computers use base 2 to handle them). But not all the fractional numbers can be written using a finite number of digits (no matter what base we use to write them). Actually, most of them have an infinite representation and only a tiny slice of them are privileged.
For example, 1/3
is a fractional number that cannot be represented exactly using the decimal notation. You can write it as 0.3
, 0.33
, 0.333
or even 0.3333333333333333
but nobody can ever write all its digits. No matter how many 3
's you write, there is a point where you stop and the number you write is not the exact value of 1/3
but an approximation (a value that is close enough to the real value).
There always is an error when you work with approximate values. They are small and negligible but the arithmetic operations make them accumulate and sometimes they become big enough to affect the correctness of the final result.
We know from the elementary school that 3 * 1/3 = 1
.
Multiplying the representation of 1/3
displayed above by 3
will produce 0.9
, 0.99
, 0.999
and 0.9999999999999999
. All these numbers are close to 1
but none of them is equal to 1
.
Oops, we just encountered a rounding error!
In real life we are accustomed to round the numbers we use and overlook the rounding errors. The computers work in a different way. They try to get the best result they can and they don't round the numbers if they are not told to do it so.
Some of the numbers that can be represented exactly using a finite number of digits in base 10 have an infinite representation in base 2. For example, 1/10
is 0.1
in base 10 but it cannot be represented using a finite number of digits in base 2.
In fact, only the fractions having the denominator a power of 2 have a finite representation in base 2. In base 10, the numbers that can be represented with a finite number of digits are fractions whose denominators look like 2m*5n
, where m
and n
are non-negative integers.
Why me?
PHP
uses the standard IEEE 574 floating point format (as many other programming languages do) and this is why the numbers from your code are not represented exactly internally.
You can use the function number_format()
or sprintf()
to produce a representation of the number with the number of digits you need. If the number of digits you need is smaller than the precision of the floating point representation, number_format()
will produce the exact value you expect.
If you are dealing with money, you should always use number_format($number, 2)
to get the final representation of the amounts you are working with.
MySQL
, on the other hand, implements both floating point numbers (single and double precision) and fixed-point types. The DECIMAL
column type guarantees both the exact representation of the numbers on storage (using the number of decimal digits specified on the column definition) and the exact results of calculations using them.
This precision, however, comes with a penalty on the processing speed but overall, the benefits overcome the shortcoming.
And, of course, the precision and exactness of the DECIMAL
data type is ruined instantly when the values are loaded into PHP
for processing or display.