强制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); }