强制PHP整数溢出
我们有一些整数算术,由于历史的原因,在PHP上的工作方式与在一些静态types的语言中一样。 自从我们上次升级PHP以来,溢出整数的行为已经改变。 基本上我们使用下面的公式:
function f($x1, $x2, $x3, $x4) { return (($x1 + $x2) ^ $x3) + $x4; }
但是,即使转换:
function f($x1, $x2, $x3, $x4) { return intval(intval(intval($x1 + $x2) ^ $x3) + $x4); }
我仍然结束了完全错误的数字…
例如,在$ x1 = -1580033017,$ x2 = -2072974554,$ x3 = -1170476976)和$ x4 = -1007518822的情况下,我最终得到了PHP中的-30512150和C#中的1617621783。
只要加在一起$ x1和$ x2我不能得到正确的答案:
在C#中我得到
(-1580033017 + -2072974554) = 641959725
在PHP中:
intval(intval(-1580033017) + intval(-2072974554)) = -2147483648
这是一样的:
intval(-1580033017 + -2072974554) = -2147483648
我不介意写一个“IntegerOverflowAdd”函数或什么的,但我不能完全弄清楚(-1580033017 + -2072974554)等于641959725.(我知道它是-2147483648 +(2 * 2 ^ 31) ,但是-2147483648 + 2 ^ 31是-1505523923,它大于Int.Min,那么为什么要加2 * 2 ^ 31而不是2 ^ 31?)
任何帮助将不胜感激…
所以我解决了这个问题,并且发现了很多关于PHP的知识(至less在处理整数溢出的方面)。
1)完全依赖于在哪个平台上运行机器,哪个版本的PHP,是否运行Suhosin Hardened PHP以及编译多less位(32或64)。 6台机器的运行方式与我预期的一样(实际上是错误的,至less根据其文档是错误的),3台机器的行为方式我仍然无法解释,3台机器根据intval命令所做的行为文档。
2)当int> PHP_MAX_INT(不是int&0xffffffff)时,Intval应该返回PHP_MAX_INT,但是这只发生在某些版本的PHP4和PHP5上。 当int> PHP_MAX_INT时,不同版本的PHP返回不同的值。
3)以下代码可以返回3个不同的结果(见1):
<?php echo "Php max int: ".PHP_INT_MAX."\n"; echo "The Val: ".(-1580033017 + -2072974554)."\n"; echo "Intval of the val: ".intval(-3653007571)."\n"; echo "And 0xffffffff of the val: ".(-3653007571 & 0xffffffff)."\n"; ?>
它可以返回(这似乎是正确的,但错误的&0xffffff)
Php max int: 2147483647 The Val: -3653007571 Intval of the val: -2147483648 And of the val: -2147483648
它可以返回(与intval的PHP文档相矛盾):
Php max int: 2147483647 The Val: -3653007571 Intval of the val: -641959725 And of the val: -641959725
在64位机器上它返回(这是正确的):
Php max int: 2147483647 The Val: -3653007571 Intval of the val: -3653007571 And of the val: -641959725
解
无论如何,我需要一个可以在所有这些平台上工作的解决scheme,而不是依赖于用特定的Max int编译的特定版本的PHP的怪癖。 因此,我想起了以下交叉PHP 30TwoBitIntval函数:
function thirtyTwoBitIntval($value) { if ($value < -2147483648) { return -(-($value) & 0xffffffff); } elseif ($value > 2147483647) { return ($value & 0xffffffff); } return $value; }
评论
我认为PHP的devise者应该说Int是一个32位的Int,不pipe它是在32位还是在64位或128位的机器上运行的(比如DotNet CLR),并且没有随机地上转换为浮动取决于PHP编译器下的位数。
如果您希望在32位和64位平台上都有32位intval的100%工作解决scheme,那么我build议您使用以下解决scheme:
function intval32bits($value) { $value = ($value & 0xFFFFFFFF); if ($value & 0x80000000) $value = -((~$value & 0xFFFFFFFF) + 1); return $value; }
在内部,PHP对大多数数字使用“整数”types。 但是,这些只是到目前为止:如果您将一个大整数添加到一个大整数,PHP会看到结果太大,以适应一个正常的整数,并将其分配给一个浮点数。 然而,浮点数(浮点数)本身只有这么高,而且在十六位数字附近有一个点,PHP将完全失去这个情节。
有一个选项可以使用任意精度math, 支持任意大小和精度的数字,以string表示 。 在这里看到更多: http : //us2.php.net/bc
我认为它可能与PHP中的整数无符号32位,如在C#中,他们默认签名32位。
您正在使用正常31-32位范围边缘的数字进行游戏。
请参阅PHP手册中的其他文档:
http://www.php.net/manual/en/language.types.integer.php
整数的大小是依赖于平台的,尽pipe最大值约为20亿是通常的值(这是32位的)。 PHP不支持无符号整数。 整数大小可以使用常量PHP_INT_SIZE确定,最大值使用自PHP 4.4.0和PHP 5.0.5以来的常量PHP_INT_MAX。
这会工作吗?
echo (-1580033017 + -2072974554) & 0xffffffff
总而言之,你可以做(赦免任何语法错误,我很久没有碰到PHP):
function s32add($a, $b) { return ($a + $b) & 0xffffffff; }
检查您的PHP版本号 – 我相信您可能会得到不同版本的PHP的不同结果,可能对长整数有不同的支持。 我相信在PHP5的最后一个版本里有一个长整型的bug。
在版本PHP 5.2.0 – 答案是完全一样的,你在C#
1617621783,
利用你上面的确切function。
您可以使用phpinfo()命令轻松地find您的版本号。
$x1 = -1580033017; $x2 = -2072974554; $x3 = -1170476976 ; $x4 = -1007518822; echo f($x1, $x2, $x3, $x4); function f($x1, $x2, $x3, $x4) { return intval(intval(intval($x1 + $x2) ^ $x3) + $x4); }