5
<?php 
$x=PHP_INT_MAX; 
echo ((float)($x+1026)==(float)($x))?'EQUAL':'Not Equal'; 

Я знаю арифметику с плавающей точкой не является точным и $ х и $ х + 1 так близко друг к другу, что они закруглены к одному и тому же значению с плавающей запятой, и он показывает результат как EQUAL, если вы используете любое число от 1 до 1025, но только после того, как вы используете значение за пределами 1025, оно начнет выдавать результат как «Не равно». Я хочу знать, почему? В чем причина этого? Почему только после 1025?Почему два поплавковых переменные со значениями PHP_INT_MAX одинаковы, если один из них не добавляют значение больше, чем 1025

+2

Вы должны начать смотреть на [представлении битового уровня поплавков] (https: // эн. wikipedia.org/wiki/Floating_point), и это также будет зависеть от того, используете ли вы 32-разрядный или 64-разрядный PHP –

+0

, какую версию PHP у вас есть? с моим тестом я «не равный» с «$ x + 10» для примера – mmm

+1

Взгляните на [этот конвертер] (http://www.h-schmidt.net/FloatConverter/IEEE754.html), который позволяет вам чтобы увидеть представление с плавающей точкой для разных чисел –

ответ

4

С поплавком, ваше предположение $x == $x + 1 не всегда верно:

$x=2; 
echo ((float)($x+1)==(float)($x))?'EQUAL':'Not Equal'; 

дает "не равно".

В конвертере, указанном в комментариях (http://www.h-schmidt.net/FloatConverter/IEEE754.html), вы можете воспроизвести это. десятичный 2.0 дает 0x40000000, десятичный 3.0 дает 0x40400000, поэтому они действительно различаются, когда речь идет о представлении float IEEE754.

Принимая во внимание, что, например, десятичный 0.1 не может быть представлен как поплавок: 0x3dcccccd, что составляет 0.10000000149011612.

Что такое десятичный 9223372036854775807? Это 0x5f000000, что составляет 9.223372E18, что составляет 9223372180000000000.

Что такое десятичный 9223372036854775808 (PHP_MAX_INT + 1)? Это тоже 0x5f000000.

Что такое десятичный 9223372036854776832 (PHP_MAX_INT + 1025)? Это тоже 0x5f000000.

Что такое десятичный 9223372036854776833 (PHP_MAX_INT + 1026)? Это тоже 0x5f000000.

Все они одинаковые.

Принимая во внимание, что, например: десятичный 9223373000000000000 (PHP_MAX_INT + 963145224193)? Это 0x5f000001, что составляет 9.223373E18, что составляет 9223373000000000000.

Теперь, почему:

((float)($x+1025)==(float)($x+1026))?'EQUAL':'Not Equal'; 

выход "не равно"?

Вы добавляете целое число в 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); 

выходы:

int(9223372036854775807) 
int(9223372036854775806) 
float(9.2233720368548E+18) 

PHP неявно преобразует целые числа слишком большие, чтобы плавать. И вот где вы в основном потеряны в PHP-внутренностях (по крайней мере, на мой взгляд), потому что отсюда вы никогда не узнаете, что произойдет (не зная PHP-внутренности, не стесняйтесь меня исправлять).

Обратите внимание это:

$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); 

выходы:

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) 

Если добавить целое число ($x+1026) для PHP_MAX_INT, он преобразуется в поплавок, и при добавлении поплавок ($x+1026.0), он тоже плавает, конечно. Но, очевидно, они не являются внутренними, см. Сравнения выше.

Итог:

  • Не сравнивайте поплавки для равенства
  • Будьте осторожны о ваших слепков; (float)($x+1026) представляет собой целочисленное добавление и впоследствии литое в float, тогда как (float)($x+1026.0) преобразует $x в float, затем добавляет поплавок 1026.0, а затем бросает (излишне) плавать.

Edit: дополнительно, см: