Why is this condition false? [duplicate] - php

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
Some strange things are going on in my code. Could someone explain please why is this condition false?
When I output object's members with php's function var_dump(), I get this:
string(6) "105.63"
float(105.63)
from one object, and this is output from another object:
string(6) "667.69"
float(667.69)
Then I do comparison like this:
if(105.63 == "105.63"){
echo "true";
} else {
echo "false";
}
if(667.69 == "667.69"){
echo "true";
} else {
echo "false";
}
it outputs 2 times true for sure, if we write code like in my example above. But in my class, it behaves differently. In first if I get false and in second if I get true. Then I looked to the data more deeply with var_export() function and it seems like I actually have following data:
'105.63'
105.6300000000000096633812063373625278472900390625
and
'667.69'
667.69000000000005456968210637569427490234375
So I decide to check wether my conditions work with that data... And they dont. Actually, only first one doesn't. Why do I get output false and true in following code?
if(105.6300000000000096633812063373625278472900390625 == "105.63"){
echo "true";
} else {
echo "false";
}
if(667.69000000000005456968210637569427490234375 == "667.69"){
echo "true";
} else {
echo "false";
}
I know how to fix this. But I'm interested why conditions fails in first if.
EDIT
Php does type juggling when we use == comparison operator!
Take a look at this:
var_export((float) "105.63");
var_export((string) 105.6300000000000096633812063373625278472900390625);
var_export((float) "667.69");
var_export((string) 667.69000000000005456968210637569427490234375);
outputs:
105.63
'105.63'
667.69000000000005
'667.69'
Should not this mean that the first condition be true and the second false? But I get false in first and true in second. Sorry if I was unclear.

Check the manual: http://php.net/manual/en/language.types.float.php
There is a big warning section about comparing floating point numbers:
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. For a "simple" explanation, see the » floating point guide
that's also titled "Why don’t my numbers add up?"
Why dont my numbers add up?

Related

Equal value failed to enter the condition

What are the possible odds of this value not entering the condition?
$a = 106709.71; //value in first table
$b = 106709.71; //value in second table
They're both Decimal in table.
I have the following code:
$a != $b ? '' : 'disabled';
It always returns the disabled one.
I have tried replicating it on PHP Emulator, but it worked even the other one is declared as string '106709.71' == 106709.71. It returns true.
I tried displaying the data on the front end and it's the same, they're both 106709.71.
My assumption is that the other one is displayed without a comma but the comma is there.
I trim the comma on both values using rtrim($var) and it works.
Any thoughts on why this is happening? Is it possible that it's displayed in the front and back end without comma but in reality there's a comma?
I think you are facing the issue of comparing decimals. It is not that straightforward. In https://www.php.net/manual/en/language.types.float.php there is a good description as to why you should not attempt a direct comparison and use other methods:
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.
For simple explanation on how to do that you can refer to Compare decimals in PHP answer. And this whole website: Floating Point Guide goes from simple to deep on why that happens and how to remedy that.
P.S. : In your question, there is a typo $a != b ? '' : 'disabled';. It must be $a != $b ? '' : 'disabled'; That could also cause problems :)
I have tried your case and i get the desired output:
$a = 106709.71; //value in first table
$b = 106709.71; //value in second table
$result = ($a != $b) ? 'Not Equal' : 'Equal'; //return FALSE because it is equal
echo $result;
Output
Equal
If i do a change in comparison like:
$a = 106709.71; //value in first table
$b = 106709.71; //value in second table
$result = ($a == $b) ? 'Not Equal' : 'Equal'; //returns TRUE
echo $result;
Output
Not Equal

floor() in php not working

<?php
echo gettype ( 5.00 ); // return double
echo gettype((5)); // return integer
echo gettype(((167.00-158.65)/167.00*100)); // return double
echo floor(5.00); // return 5
echo floor(5); // return 5
echo ((167.00-158.65)/167.00*100); // return 5
echo floor(((167.00-158.65)/167.00*100)); // return 4
var_dump(5.00); // return float(5)
var_dump(5); // return int(5)
var_dump((167.00-158.65)/167.00*100); // return float(5)
var_dump(intval(5)); // return int(5)
var_dump(intval((167.00-158.65)/167.00*100)); // return int(4)
echo gettype(intval(((167.00-158.65)/167.00*100))); // return integer
echo floor(intval((167.00-158.65)/167.00*100)); // return 4
?>
Why floor function in php not working in last case?
How to get 5 from last statement?
Is there any other function or method in php to get exact least amount?
That behaviour is caused by limited precision of floating point numbers. The last case is of type float (check it with var_dump), and the Manual says:
Warning
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....
Source:
http://php.net/manual/en/language.types.float.php

PHP floating point error with basic arithmetic operation [duplicate]

This question already has answers here:
Compare floats in php
(17 answers)
Closed 8 years ago.
I am new to PHP and trying to perform a simple arithmetic addition and comparison. I have an array with some decimal values and after adding all the values, I am trying to compare it to 1. My array is:
$myArray=[0.2,0.7,0.1]
and my code is:
$sum=0;
foreach($myArray as $val){
$sum+=$val;
}
Here, the sum comes out to be 1. But when I compare it using the following code:
if($sum!=1)
{
echo "Good";
}
else
{
echo "Bad";
}
it echoes "Good".
However, when my array contains values 0.8 and 0.2, it echoes "Bad". Can anyone help me on this?
If you check the PHP docs on floating-point numbers: php.net/manual/en/language.types.float.php, there is a huge warning on the page.
"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."
Thus, you could get unexpected results such as 0.2 + 0.7 = 0.900000000001. It's simply because computers have a hard time representing decimals. Binary was really built for integers.
Careful in your logic; I think you meant if($sum == 1) echo "Good", etc. In that case, 0.2+0.7+0.1 would echo "Bad", because it's totally possible that 0.2+0.7+0.1 = 1.00000001 or 0.99999999. On the other hand, adding a smaller number of floats together decreases the error, so 0.8+0.2 is more precise than 0.2+0.7+0.1.

php substraction 145.48 - 80.26 != 65.22 [duplicate]

This question already has an answer here:
The accuracy of PHP float calculate
(1 answer)
Closed 8 years ago.
I got a problem with PHP.
This exact substraction below is wrongly computed.
<?php
$test = 145.48 - 80.26;
if($test != 65.22)
echo 'not good !';
else
echo 'good';
?>
This echoes "not good" !!!
Why ?
Computers aren't very good at storing floating point (decimal) numbers since representing a base 10 decimal number in binary is hard. For instance, if you try to store the number 0.2 in binary, the computer will store a series following the pattern 0.00110011… . Depending on the size of the floating point number (i.e. how many bits have been allocated for it in memory), the precision will vary, but more important, it will never accurately store exactly 0.2.
There are several ways to fix this, one is using the BC Math library and do something like:
bcsub("145.48", "80.26");
But sometimes the better solution is to just acknowledge that the numbers won't be accurate and account for the error, i.e.
if (abs($x - $y) < $e)
where e is some very small number, e.g. 10^(-5). This is common practice when working with physics calculations and similar, but of course you should never attempt this when working with discrete numbers, e.g. currencies.
To do exact floating number arithmetic you can use bc_math:
$test = bcsub("145.48", "80.26");
assert ($test == "65.22");

php float math operation bug?

the summary here:
$a = 213480.7-190.46;
exit($a-213290.24);
# 2.9103830456734E-11
the result output suppose to be 0. but it output
the story of the operation result :
$b is : 213480.7
-190.46
$b is : 213290.24
now the balance looks correct. but when use comparison operator.. the result is weird
here is the var_dump and compare result
var_dump($b);
# float 213290.24
if ($b==213290.24) {
exit('same');
} elseif ($b>213290.24) {
exit('larger '.($b-213290.24));
} else {
exit('smaller '.($b-213290.24));
}
#larger 2.9103830456734E-11
can anyone tell me how to solve it??
See here: http://php.net/manual/en/language.types.float.php
So never trust floating number results to the last digit, and never
compare floating point numbers for equality. If higher precision is
necessary, the arbitrary precision math functions and gmp functions
are available.
The common method of dealing with float comparisons is to add an allowable epsilon, or small difference in floating point values, so anything within a small tolerance is considered equivalent.
if (abs(213290.24 - $b) < .001) {
exit('same')
}
Computations performed on floating point numeric values always have inherent error resulting from their machine representation. For this reason, you should not use the equality operator == to compare floating point values.
The typical approach is to decide on a minimum allowable error, and check if the difference between the values you want to compare is less than the desired error.
$min_error = 0.00001;
if (abs($a - $b) < $min_error)
{
exit("same");
}
This is not problem of php, it's connected with the nature of binary float.
You can't represent all rational number accurately with float. For example, you might try to compare 0.1 + 0.2 == 0.3, it will be failse, because 0.3 is not represented accurately.

Categories