【问题标题】:Force PHP integer overflow强制 PHP 整数溢出
【发布时间】:2008-11-19 02:26:27
【问题描述】:

我们有一些整数运算,由于历史原因,它在 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?)

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

【问题讨论】:

    标签: c# php integer-overflow


    【解决方案1】:

    所以我解决了这个问题,并发现了很多关于 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 的某些版本上。不同版本的 PHP 在 int > PHP_INT_MAX 时返回不同的值。

    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 的 30TwoBitIntval 函数:

    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 编译器的位数。

    【讨论】:

    • 我认为您的意思是 PHP_INT_MAX,而不是 PHP_MAX_INT。
    【解决方案2】:

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

    function intval32bits($value)
    {
        $value = ($value & 0xFFFFFFFF);
    
        if ($value & 0x80000000)
            $value = -((~$value & 0xFFFFFFFF) + 1);
    
        return $value;
    }
    

    【讨论】:

    • $value = -((~$value &amp; 0xFFFFFFFF) + 1); 部分的意义何在?
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      我认为这可能与 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 确定最大值。

      【讨论】:

        【解决方案5】:

        这行得通吗?

        echo (-1580033017 + -2072974554) & 0xffffffff
        

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

        function s32add($a, $b) {
            return ($a + $b) & 0xffffffff;
        }
        

        【讨论】:

          【解决方案6】:

          检查您的 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);
          }
          

          【讨论】:

            猜你喜欢
            • 2016-08-05
            • 1970-01-01
            • 2022-01-21
            • 1970-01-01
            • 1970-01-01
            • 2015-11-14
            • 2023-03-17
            • 2014-01-24
            相关资源
            最近更新 更多