Compare floats in php
If you do it like this they should be the same. But note that a characteristic of floating-point values is that calculations which seem to result in the same value do not need to actually be identical. So if $a
is a literal .17
and $b
arrives there through a calculation it can well be that they are different, albeit both display the same value.
Usually you never compare floating-point values for equality like this, you need to use a smallest acceptable difference:
if (abs(($a-$b)/$b) < 0.00001) {
echo "same";
}
Something like that.
PHP float comparison
you can just do it this way:
//just a check if it is float, than round it to 1 decimal number and compare
if(is_float($a)){
echo 'not a float';
$a = round($a,1);
}
and output will be 'IF'
Is there any way to compare float numbers correctly in PHP?
Use this method:
$a = 0.2;
if ( abs($a - 0.2) < 0.00001 )
return true;
else
return false;
Comparing floats - same number, but does not equal?
floating point numbers have limited precision. view the warning about comparing them here:
http://php.net/manual/en/language.types.float.php
PHP Comparing float values
I found where the problem actually was. My getBalance()
method was actually returning the value 1 when being converted to a float. 1 was the position of the record in the array. Changing the declaration of $floatCurrentBalance
to: $floatCurrentBalance = floatval($currentBalance['balance']);
Formulas for comparing float equality in PHP
This probably allows checking epsilon with a relative error rather than an absolute error.
Compare these two cases:
function areEqual(float $a, float $b) : bool {
return abs(($a - $b) / $b) < 0.00001;
}
areEqual(10000, 10000.01);
areEqual(0.0000001, 0);
Fact about the example values above: Our epsilon here is
0.00001
for convenience ‐ the smallest epsilon possible is much smaller than these values anyway, so let's ignore this fact. Our algorithm assumes that$a
and$b
are both similar, so it does not matter whether we divide by$a
or$b
. Actually,10000
should be much larger than that (a very enormous exponent), and0.0000001
can be much smaller, but for the sake of convenience, let's assume these are the values that may cause problems.
Now you can already see the difference.
For the large numbers: If the compared floats are extremely large, epsilon may be too small. The float internally can only store a definite number of digits for precision, while the exponent can be way greater than that. As a result, the source of floating point error, i.e. the final digits of floats, would appear at somewhere that can be higher than the unit digits. In other words, for extremely large floats, the absolute error can be greater than 1
, much less our epsilon of 0.00001
.
For the small numbers: This is even more obvious. Both numbers are smaller than the epsilon already. Even if you compare them with 0, while the relative error is infinitely large, you still think that they are equal. For this case, you either multiply up both operands, or you decrease the epsilon. They are actually the same, but in terms of implementation, it is more convenient to divide the difference with one of the operands, which will multiply up for small numbers (/ 0.0001
is equivalent to * 10000
) or divide down for large numbers (/ 10000
while the difference is hopefully way smaller than 10000
)
There is another name for this check. While abs($a - $b)
is called the absolute error, we usually use the relative error, which is absolute error ÷ approximate value. Since the values can be negative as well, we abs
the whole thing ($a - $b) / $b
instead. Our "epsilon", 0.00001
, in this case, means that our tolerate relative error is 0.00001
, i.e. 0.001% error.
Keep in mind that this is still not absolutely safe. After numerous transformations in your program, you may, for example, add/multiply your numbers with some big numbers, then subtract down again, leaving the impure error in the big numbers somewhere still negligible to humans but notable to your epsilon value. Therefore, always think twice before choosing an epsilon value or float comparison algorithm.
As the best practice, avoid adding, subtracting or multiplying big numbers with small numbers. They will increase the chance of errors. When developing (especially simplifying) your algorithms, always put into consideration that their might be an error in your floats. This may increase work load to a stupid extent, but as long as you are aware of it, this kind of worry sometimes saves you from getting kicked out of teams.
php integer and float comparison mismatch
Notice the big red warning in the PHP Manual!
Never expect anything when comparing floats. The result of round, even if the precision is 0, is still a float. In your particular case it happened that the result was a little bigger than expected, so casting to int resulted in equality, but for other numbers it might as well happen for it to be a little smaller than expected and casting to int won't round it, but truncate it, so you can't use casting as a workaround. (As a note, a better solution than yours would be casting to string :), but still a lousy option.)
If you need to work with amounts of money always use the BC Math extension.
For rounding with BC Math you can use this technique:
$x = '211.9452';
$x = bcadd($x, '0.005', 2);
Good luck,
Alin
Related Topics
Difference Between Require, Include, Require_Once and Include_Once
How to Reindex an Array in PHP But With Indexes Starting from 1
How to Make Asynchronous Http Requests in PHP
Creating One Array from Another Array in PHP
Prevent Direct Access to a PHP Include File
Laravel Requires the Mcrypt PHP Extension
Two-Way Encryption: I Need to Store Passwords That Can Be Retrieved
Access a JavaScript Variable from PHP
MySQLi Update Throwing Call to a Member Function Bind_Param() Error
PHP: Return All Dates Between Two Dates in an Array
Apache Shows PHP Code Instead of Executing It
MySQL VS MySQLi When Using PHP
Warning: a Non-Numeric Value Encountered
PHP Elvis Operator VS Null Coalescing Operator
Https and Ssl3_Get_Server_Certificate:Certificate Verify Failed, Ca Is Ok