为什么两个具有 PHP_INT_MAX 值的 float 变量相同,除非其中一个被添加值大于 1025
Why two float variables with PHP_INT_MAX values are same unless one of them is added with value greater than 1025
<?php
$x=PHP_INT_MAX;
echo ((float)($x+1026)==(float)($x))?'EQUAL':'Not Equal';
我知道浮点运算并不精确,$x 和 $x+1 靠得太近以至于它们四舍五入为相同的浮点值,如果您使用 1 和1025,但只有在您使用超过 1025 的值后,它才会开始输出 'Not Equal'。我想知道为什么?背后的原因是什么?为什么只有 1025 之后?
对于浮动,您的假设 $x == $x + 1
不一定正确:
$x=2;
echo ((float)($x+1)==(float)($x))?'EQUAL':'Not Equal';
产量 "Not Equal"。
在评论中链接的转换器 (http://www.h-schmidt.net/FloatConverter/IEEE754.html) 中,您可以复制它。十进制 2.0
产生 0x40000000
,十进制 3.0
产生 0x40400000
,所以当涉及到 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';
产量"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)
PHP_MAX_INT
加上整数($x+1026
)就转为浮点数,加上浮点数($x+1026.0
)也是浮点数,当然。但是,很明显,它们在内部并不相同,请参阅上面的比较。
底线:
- 不要比较浮点数是否相等
- 小心你的石膏;
(float)($x+1026)
是整数加法,然后转换为浮点数,而 (float)($x+1026.0)
将 $x
转换为浮点数,然后添加浮点数 1026.0
,然后(多余地)转换为浮点数。
编辑:另外,参见:
- Force PHP integer overflow
- http://php.net/manual/en/language.types.integer.php
<?php
$x=PHP_INT_MAX;
echo ((float)($x+1026)==(float)($x))?'EQUAL':'Not Equal';
我知道浮点运算并不精确,$x 和 $x+1 靠得太近以至于它们四舍五入为相同的浮点值,如果您使用 1 和1025,但只有在您使用超过 1025 的值后,它才会开始输出 'Not Equal'。我想知道为什么?背后的原因是什么?为什么只有 1025 之后?
对于浮动,您的假设 $x == $x + 1
不一定正确:
$x=2;
echo ((float)($x+1)==(float)($x))?'EQUAL':'Not Equal';
产量 "Not Equal"。
在评论中链接的转换器 (http://www.h-schmidt.net/FloatConverter/IEEE754.html) 中,您可以复制它。十进制 2.0
产生 0x40000000
,十进制 3.0
产生 0x40400000
,所以当涉及到 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';
产量"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)
PHP_MAX_INT
加上整数($x+1026
)就转为浮点数,加上浮点数($x+1026.0
)也是浮点数,当然。但是,很明显,它们在内部并不相同,请参阅上面的比较。
底线:
- 不要比较浮点数是否相等
- 小心你的石膏;
(float)($x+1026)
是整数加法,然后转换为浮点数,而(float)($x+1026.0)
将$x
转换为浮点数,然后添加浮点数1026.0
,然后(多余地)转换为浮点数。
编辑:另外,参见:
- Force PHP integer overflow
- http://php.net/manual/en/language.types.integer.php