1.2.826. 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.826.1. Suggestions

  • Cast the values to integer before comparing

  • Compute the difference, and keep it below a threshold

  • Use the gmp or the bcmath extension to handle high precision numbers

  • Change the ‘precision’ directive of PHP : ini_set('precision', 30) to make number larger

  • Multiply 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.826.2. Specs

Short name

Type/NoRealComparison

Rulesets

All, Analyze, CE, CI-checks, PHP recommendations, Top10

Exakat since

0.8.4

PHP Version

All

Severity

Major

Time To Fix

Quick (30 mins)

Precision

Very high

Features

real

ClearPHP

no-real-comparison

Examples

Magento, SPIP

Available in

Entreprise Edition, Community Edition, Exakat Cloud