跨越PHP中的整数限制
有人能解释一下在最后两个案例中发生了什么吗跨越PHP中的整数限制,php,math,integer,integer-overflow,Php,Math,Integer,Integer Overflow,有人能解释一下在最后两个案例中发生了什么吗 $x=PHP_INT_MAX; var_dump($x); // int(9223372036854775807) no problem var_dump($x+1); // float(9.2233720368548E+18) value is cast to float still no problem var_dump($x+1-1); // float(9.22337
$x=PHP_INT_MAX;
var_dump($x); // int(9223372036854775807) no problem
var_dump($x+1); // float(9.2233720368548E+18) value is cast to float still no problem
var_dump($x+1-1); // float(9.2233720368548E+18) still okay
var_dump((int)($x+1-1)); // int(-9223372036854775808) negative value?!!
var_dump($x+1-$x); // float(0) zero?!!!!!!!!!!!
根据报告:
- PHP_INT_MAX是最大整数大小
- 如果PHP遇到一个超出整数类型边界的数字,它将被解释为浮点。还有,一个操作 结果将返回超出整数类型边界的数字 而是一个浮子
0111 (=7) + 0001 (=1) = 1000 (= -7)
这部分解释了一个数字如何突然变成一个非常大的负数
但是你会期望x+1-1是x,但这可能是一个有效数字的问题。PHP只存储14个有效数字,这不足以准确地存储像9223372036854775807这样的数字而不丢失信息
我将使用第5个测试进行解释:
浮点可以包含比整数大得多的数字,但有效位数的数量有限。这就是为什么它看起来像9.2233720368548E+18
而不是9223372036854800000
或9223372036854775808
由于像1
这样的低位数字在值的有效位之外,我认为9.2233720368548E+18+1
仍然是9.2233720368548E+18
。这也意味着9.2233720368548E+18+1-9.2233720368548E+18
是0
,因为+1
没有任何效果
我认为这实际上是对这两种现象的解释
奇怪的是,您通常不必知道这些实现细节中的任何一个,特别是在PHP这样的脚本语言中,但在这样的测试中,它们可能会出现,有时会导致奇怪的行为
此外,你可能想阅读。它很好地解释了使用浮点数可能出现的其他舍入错误,它将使您更深入地了解浮点数在一般情况下以及在PHP中的具体工作方式。这与计算机存储数字的方式有关。在本例中,是带符号的数字,这意味着它们既可以是负数也可以是正数
为了方便起见,我将使用一个8位示例。计算机可以存储从-128
到127
的数字。
-128
表示为1000 0000
,127
表示为0111111
。第一位表示数字是负数还是正数。每个位都值2^n
,WAREn
是从右到左的位置。对于127,它是2^0+2^1+2^2+2^3+2^4+2^5+2^6+2^7=127。
负值则相反
var_dump($x); // int(9223372036854775807) no problem
没有问题,因为我们只是将其设置为最大值
var_dump($x+1); // float(9.2233720368548E+18) value is cast to float still no problem
var_dump($x+1-1); // float(9.2233720368548E+18) still okay
这里有一些问题,+1和+1-1等于相同的东西。他们不应该这样做,但问题确实发生在这里,有点微妙
var_dump((int)($x+1-1)); // int(-9223372036854775808) negative value?!!
在这种情况下,0111(…)
+1等于1000(…)
,这是绝对值,请注意数字末尾的8,而正值为7设置了CPU中的溢出标志。
var_dump($x+1-$x); // float(0) zero?!!!!!!!!!!!
$x+1强制强制强制强制转换为浮点,然后减去相同的值(因为浮点数字存在舍入错误),$x+1与$x相同,因此$x-$x=0
希望这能澄清一些问题。两种不同的东西结合在一起:浮点舍入和整数溢出
var_dump($x+1-$x); // float(0) zero?!!!!!!!!!!!
这是因为算术是不精确的(它不可能精确,因为实数可能是无限的)$x
和$x+1
靠得很近,所以它们四舍五入到同一个浮点值,所以浮点($x+1)==浮点($x)
。现在您知道为什么$x+1-$x==0
结合整数溢出,可以得到以下结果:
var_dump((int)($x+1-1)); // int(-9223372036854775808) negative value?!!
由于上述原因,$x+1-1==float(9223372036854775808)
。当将其转换为int
时,它将变为负值
9223372036854775808==2^63
,它在64位有符号整数中变成了-2^63
,这与计算机存储数字的方式有关。特别是负数和浮点数。您的整数溢出解释是正确的,但您没有正确解释var_dump($x+1-$x);//浮动(0)
。在这种情况下,浮点数不会溢出。