1.2.834. No Real Comparison¶
Avoid comparing decimal numbers with ==, ===, !==, !=. Real numbers have an error margin which is random, and makes it very difficult to match even if the compared value is a literal.
PHP uses an internal representation in base 2 : any number difficult to represent with this base (like 0.1 or 0.7) will have a margin of error. Use precision formulas with abs() to approximate values with a given precision, or avoid reals altogether.
<?php
$a = 1/7;
$b = 2.0;
// 7 * $a is a real, not an integer
var_dump( 7 * $a === 1);
// rounding error leads to wrong comparison
var_dump( (0.1 + 0.7) * 10 == 8);
// although
var_dump( (0.1 + 0.7) * 10);
// displays 8
// precision formula to use with reals. Adapt 0.0001 to your precision needs
var_dump( abs(((0.1 + 0.7) * 10) - 8) < 0.0001);
?>
See also Floating point numbers.
1.2.834.1. Connex PHP features¶
1.2.834.1.1. Suggestions¶
Cast the values to integer before comparing
Compute the difference, and keep it below a threshold
Use the
gmp
or thebcmath
extension to handle high precision numbersChange the ‘precision’ directive of PHP :
ini_set('precision', 30)
to make number largerMultiply by a power of ten, before casting to integer for the comparison
Use floor(), ceil() or round() to compare the numbers, with a specific precision
1.2.834.1.2. Specs¶
Short name |
Type/NoRealComparison |
Rulesets |
All, Analyze, CE, CI-checks, Changed Behavior, PHP recommendations, Top10 |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
ClearPHP |
|
Examples |
|
Available in |