Reputation: 9303
I have a simple PHP program called "PuraPuraNanya":
$a = 100;
$b = 3;
$test1 = $a/ $b;
$test2 = 33.333333333333; // $test2 == $test1
var_dump(($test1 * $b)); // float(100)
var_dump(($test2 * $b)); // float(99.999999999999)
Any explanation for that?
Upvotes: 2
Views: 852
Reputation: 9303
Information from PHP
Warning
Floating point precision
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.
As noted in the warning above, testing floating point values for equality is problematic, due to the way that they are represented internally. However, there are ways to make comparisons of floating point values that work around these limitations.
To test floating point values for equality, an upper bound on the relative error due to rounding is used. This value is known as the machine epsilon, or unit roundoff, and is the smallest acceptable difference in calculations.
Many thanks to all who took the time to answer my question
Upvotes: 1
Reputation: 33502
100/3
results in 33.3-repeating
.
There is no decimal point value that will ever show it. In maths, such a number is normally shown by a little dot over the repeating value. (though I have no idea how to show that in this code box).
Refer to this wiki article to see how they are represented in various places and a much more detailed explanation that I have given here.
However, from the article here is a snippet of the summary:
In arithmetic, repeating decimal is a way of representing a rational number. Thus, a decimal representation of a number is called a repeating decimal (or recurring decimal) if at some point it becomes periodic, that is, if there is some finite sequence of digits that is repeated indefinitely. For example, the decimal representation of 1/3 = 0.3333333… or 0.3 (spoken as "0.3 repeating", or "0.3 recurring") becomes periodic just after the decimal point, repeating the single-digit sequence "3" infinitely. A somewhat more complicated example is 3227/555 = 5.8144144144…, where the decimal representation becomes periodic at the second digit after the decimal point, repeating the sequence of digits "144" indefinitely.
Now, that's the crux of your issue here, but also keep in mind (as the other two answers point out) that floats are amazingly innacurate in terms of calculations and comparisons. A quick search of this site will reveal a small army of people that have had problems with the internal representations of floats - mainly which resulted in unexpected behavior when doing comparisons.
Take a long read of the PHP warning on the float data type - again I have copied the important bit here:
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....
Upvotes: 5
Reputation: 13872
Not all float
s can be represented exactly by processor. $a/$b
is one of them.
So, $test1 != $test2
is true.
Upvotes: 1