8

我们有一些整数运算,由于历史原因,它在 PHP 上的工作方式与在一些静态类型语言中的工作方式相同。自从我们上次升级 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?)

任何帮助,将不胜感激...

4

6 回答 6

14

所以我解决了这个问题,并发现了很多关于 PHP 的东西(至少在它处理整数溢出的方式上)。

1) 它完全取决于机器运行的平台、PHP 的版本、是否运行 Suhosin Hardened PHP 以及编译的位数(32 或 64)。6 台机器的行为符合我的预期(实际上是错误的,至少根据他们的文档是错误的),3 台机器的行为方式我仍然无法解释,3 台机器的行为与 intval 命令在文档。

2) 当 int > PHP_INT_MAX(不是 int & 0xffffffff)时,Intval 应该返回 PHP_INT_MAX,但这只发生在 PHP4 和 PHP5 的某些版本上。当 int > PHP_INT_MAX 时,不同版本的 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";
?>

它可以返回(这对于 Intval 似乎是正确的,但对于 & 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

解决方案

无论如何,我需要一个可以在所有这些平台上工作的解决方案,并且不依赖于使用特定 Max int 编译的特定 PHP 版本的怪癖。因此,我想出了以下跨 PHP 的 ttyTwoBitIntval 函数:

function thirtyTwoBitIntval($value)
{
    if ($value < -2147483648)
    {
        return -(-($value) & 0xffffffff);
    }
    elseif ($value > 2147483647)
    {
        return ($value & 0xffffffff);
    }
    return $value;
}

评论

我确实认为 PHP 的设计者应该说一个 Int 是一个 32 位 Int,无论它是在 32 位、64 位还是 128 位机器上运行(例如 DotNet CLR),并且没有将它随机上转换为浮动取决于 PHP 在编译器下的位数。

于 2008-11-19T23:53:17.977 回答
11

如果您想在 32 位和 64 位平台上都有 32 位整数的 100% 工作解决方案,那么我建议您使用以下解决方案:

function intval32bits($value)
{
    $value = ($value & 0xFFFFFFFF);

    if ($value & 0x80000000)
        $value = -((~$value & 0xFFFFFFFF) + 1);

    return $value;
}
于 2010-01-23T14:27:36.293 回答
3

在内部,PHP 对大多数数字使用“整数”类型。然而,这些只是到目前为止:如果你将一个大整数添加到一个大整数,PHP 将看到结果太大而无法放入一个普通整数,并将其分配给一个浮点数。然而,浮点数 (floats) 本身只会变得如此之高,并且在 16 位标记附近有一个点,PHP 将完全失去情节。

有一个选项可以使用任意精度数学,它支持任意大小和精度的数字,表示为 strings。在这里查看更多信息:http: //us2.php.net/bc

于 2008-11-19T02:39:54.943 回答
2

我认为这可能与 PHP 中的整数是无符号 32 位有关,因为在 C# 中它们默认为有符号 32 位。

您正在使用正常 31-32 位范围边缘的数字。

请参阅 PHP 手册中的其他文档:

http://www.php.net/manual/en/language.types.integer.php

整数的大小取决于平台,尽管通常值约为 20 亿的最大值(即 32 位有符号)。PHP 不支持无符号整数。自 PHP 4.4.0 和 PHP 5.0.5 起,可以使用常量 PHP_INT_SIZE 确定整数大小,使用常量 PHP_INT_MAX 确定最大值。

于 2008-11-19T02:34:30.150 回答
2

这行得通吗?

echo (-1580033017 + -2072974554) & 0xffffffff

概括地说,您可以这样做(请原谅任何语法错误,我很长时间没有接触过 PHP):

function s32add($a, $b) {
    return ($a + $b) & 0xffffffff;
}
于 2008-11-19T02:36:43.733 回答
1

检查您的 PHP 版本号 - 我相信您可能会使用不同版本的 PHP 获得不同的结果,这些版本可能对长整数有不同的支持。我相信最后一个 PHP 5 版本中存在长整数错误。

在 PHP 5.2.0 版本中 - 答案与 C# 中的答案完全相同

1617621783,

利用上面的确切功能。

您可以使用phpinfo()命令轻松找到您的版本号。

$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);
}
于 2008-11-19T03:22:15.280 回答