With float, your assumption $x == $x + 1
is not necessarily true:
$x=2;
echo ((float)($x+1)==(float)($x))?'EQUAL':'Not Equal';
yields "Not Equal".
In the converter linked in the comments (http://www.h-schmidt.net/FloatConverter/IEEE754.html), you can reproduce this. decimal 2.0
yields 0x40000000
, decimal 3.0
yields 0x40400000
, so they're indeed different when it comes to IEEE754 float representation.
Whereas, e.g., decimal 0.1
cannot be represented as float: 0x3dcccccd
, which is 0.10000000149011612
.
What's decimal 9223372036854775807
? That's 0x5f000000
, which is 9.223372E18
, which is 9223372180000000000
.
What's decimal 9223372036854775808
(PHP_MAX_INT + 1
)? That's 0x5f000000
, too.
What's decimal 9223372036854776832
(PHP_MAX_INT + 1025
)? That's 0x5f000000
, too.
What's decimal 9223372036854776833
(PHP_MAX_INT + 1026
)? That's 0x5f000000
, too.
They're all the same.
Whereas, e.g.: decimal 9223373000000000000
(PHP_MAX_INT + 963145224193
)? That's 0x5f000001
, which is 9.223373E18
, which is 9223373000000000000
.
Now, why does:
((float)($x+1025)==(float)($x+1026))?'EQUAL':'Not Equal';
yield "Not Equal"?
You're adding an integer to PHP_MAX_INT
.
$x=PHP_INT_MAX;
$y=PHP_INT_MAX-1;
$z=PHP_INT_MAX+1;
var_dump($x);
var_dump($y);
var_dump($z);
yields:
int(9223372036854775807)
int(9223372036854775806)
float(9.2233720368548E+18)
PHP implicitly converts integers too large to float. And that's where you're basically lost in PHP internals (at least in my opinion), because from here, you'll never know what will happen (without knowing PHP internals, feel free to correct me, though).
Notice this:
$x=PHP_INT_MAX;
$a=(float)($x+1025.0); // 1025 float
$b=(float)($x+1026.0); // 1026 float
$c=(float)($x+1025); // 1025 int
$d=(float)($x+1026); // 1026 int
var_dump($x);
var_dump($a);
var_dump($b);
var_dump($c);
var_dump($d);
var_dump($a==$b);
var_dump($a===$b);
var_dump($c==$d);
var_dump($c===$d);
yields:
int(9223372036854775807)
float(9.2233720368548E+18)
float(9.2233720368548E+18)
float(9.2233720368548E+18)
float(9.2233720368548E+18)
bool(true)
bool(true)
bool(false)
bool(false)
If you add an integer ($x+1026
) to PHP_MAX_INT
, it is converted to float, and when you add a float ($x+1026.0
), it is float, too, of course. But, obviously, they're not the same internally, see the comparisons above.
Bottom line:
- Don't compare floats for equality
- Be careful about your casts;
(float)($x+1026)
is an integer addition, and afterwards casted to float, whereas (float)($x+1026.0)
converts $x
to float, then adds the float 1026.0
, then casts (superfluously) to float.
Edit: additionally, see: