6

For some reason, PHP decided that if:

$a = "3.14159265358979326666666666"

$b = "3.14159265358979323846264338"

$a == $b is true.

Why is that, and how can I fix that?

It ruins my code.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131

5 Answers5

7

The Problem

PHP converts strings (if possible) to numbers (source). Floating points have a limited precision (source). So $a == $b because of rounding errors.

The Fix

Use === or !==.

Try it

<?php

$a = "3.14159265358979326666666666";
$b = "3.14159265358979323846264338";

if ($a == $b) {
    echo "'$a' and '$b' are equal with ==.<br/>";
} else {
    echo "'$a' and '$b' are NOT equal with ==.<br/>";
}

if ($a === $b) {
    echo "'$a' and '$b' are equal with ===.<br/>";
} else {
    echo "'$a' and '$b' are NOT equal with ===.<br/>";
}
?>

Results in

'3.14159265358979326666666666' and '3.14159265358979323846264338' are equal with ==.
'3.14159265358979326666666666' and '3.14159265358979323846264338' are NOT equal with ===.

Note

When you want to do high precision mathematics, you should take a look at BC Math.

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
4

You could use === in the equality test.

$a = "3.14159265358979326666666666";
$b = "3.14159265358979323846264338";

if($a===$b)
{
    echo "ok";
}
else
{
    echo "nope";
}

This code will echo nope.

Comparing with == is a loose comparison, and both strings will be converted to numbers, and not compared right away.

Using === will perform a string comparison, without type conversion, and will give you the wanted result.

You can find more explanations in the PHP manual:

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Theox
  • 1,363
  • 9
  • 20
  • Ah damn. Should have written mine as an answer instead of a comment! +1 to you anyway :) – Albzi Mar 28 '14 at 09:50
  • Also this can helps: http://stackoverflow.com/questions/19161722/php-long-numbers-in-string-comparison – ilpaijin Mar 28 '14 at 09:54
1

Read PHP: Comparison Operators

If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically. These rules also apply to the switch statement. The type conversion does not take place when the comparison is === or !== as this involves comparing the type as well as the value.

Others have recommended BC Math, but if you are doing floating point comparisons, the traditional way of comparing numbers is to see if they are the same to a reasonable error level

$epsilon = 1.0e-10;
if (abs($a - $b) < $epsilon) then {
    // they're the same for all practical purposes
}
vogomatix
  • 4,856
  • 2
  • 23
  • 46
1

Try using $a === $b instead; you should never use == for string comparison.

Albzi
  • 15,431
  • 6
  • 46
  • 63
Bugs Bunny
  • 2,496
  • 1
  • 26
  • 32
1

You should not to compare a float variable like that.

Try this:

bccomp($a, $b, 26)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Minh Nguyen
  • 490
  • 1
  • 3
  • 8
  • Re *"Try this"*: Perhaps explain it instead? E.g., what is the magic number "26" supposed to do? Why not 25 or 27? Without looking at the documentation, I would expect that it should be 15, 16 or 17, corresponding to [8-byte IEEE floats](https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64). Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/22709511/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Sep 17 '21 at 20:09