Почему две переменные типа float со значениями PHP_INT_MAX одинаковы, если только одна из них не добавлена ​​со значением больше 1025

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

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

5

Решение

С поплавком, ваше предположение $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так что они действительно отличаются, когда дело доходит до представления IEEE754 с плавающей точкой.

Принимая во внимание, например, десятичный 0.1 не может быть представлен как float: 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, он конвертируется в float, и когда вы добавляете float ($x+1026.0), это тоже поплавок, конечно. Но, очевидно, они не одинаковы внутри, см. Сравнение выше.

Нижняя линия:

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

Изменить: дополнительно см .:

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]