0

I am abit confused at this and do not understand what is going here, am I missing something here can somebody explain, i'd like to understand and can't find any resource online that explains it or why it is happening.

Why does the following equation equal 0.23999999999999 and not 0.24 in PHP. I am applying no rounding here and all values are exact to two decimal places. So why is the answer being padded with all these 0.009999999999's?

return 65.00 + 0.03 - 0.90 - 50.00 - 13.89;
float(0.23999999999999)

How do I fix this or get it to show exactly what is retrived from db instead of padding these 9's.

All values in the db are stored as decimal 10,2

adam gouldie
  • 251
  • 3
  • 16
  • Can we have the actual code that fetch these data from your DB? – D4V1D Mar 27 '15 at 11:53
  • You can use round() check this link to get more information http://php.net/manual/fr/function.round.php – Ahmed Ziani Mar 27 '15 at 11:56
  • I don't think the OP wants to use extra function to correct a bug but rather understand why this occurs. – D4V1D Mar 27 '15 at 11:57
  • Hi david, I have not added the actual code from DB, because the result above I am getting are not values from DB. I have purposely manually typed the values in PHP as above to see what was causing the problem. And even without retrieving the values from DB and maually returning the line, it still resulted in the same answer. So this has nothing to do with the DB side, this is what is being returned by PHP – adam gouldie Mar 27 '15 at 11:58
  • 2
    I think [this](http://floating-point-gui.de/) will help you – Barcenal Mar 27 '15 at 11:59
  • D4V1D you are correct I do not want to round, because the values are related to money values, so every penny needs to be exact – adam gouldie Mar 27 '15 at 11:59
  • 3
    http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems - If these are monetary values, then they're best handled using integers at the lowest unit of currency (cents rather than dollars) then formatted to the major unit (dollars) purely for display purposes – Mark Baker Mar 27 '15 at 12:01
  • it's allready answer here floating point issue. http://stackoverflow.com/questions/14587290/can-i-rely-on-php-php-ini-precision-workaround-for-floating-point-issue – kamlesh.bar Mar 27 '15 at 12:16

1 Answers1

1

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.

Community
  • 1
  • 1
axiac
  • 68,258
  • 9
  • 99
  • 134
  • 1
    Addendum last sentence: Unless you load them into a string, that is. – Alexander Mar 27 '15 at 15:36
  • @Alexander you are absolutely right. I didn't think about that; when one uses `DECIMAL` to store a number it is usually an amount of money and the coder wants to process it somehow (add it with other amounts to get the total order value, add or subtract VAT, add an interest etc.) – axiac Mar 27 '15 at 15:43