繁体   English   中英

PHP 64位整数溢出与Java实现不同

[英]php 64bit integer overflow differs from Java implmention

我试图在php中实现Java的Random类,并且在几个小时后,我发现当将两个64位long乘在一起时,php返回的值与java的值不同。

在PHP中

echo (int) (160577175182 * 25214903917);

9101091335015235584

在Java小程序中

g.drawString( "Java: " + (160577175182L * 25214903917L), 10, 10 );

Java: 9101091335015183990

有趣的是,如果以编程器模式将其置于calc中,它还会生成9101091335015183990。

25214903917是Java随机魔术数0x5DEECE66D

160577175182是测试种子值

我知道结果数大于64位数字,因此两者的结果都不正确。 我只需要能够在php中复制java结果。

我使用Java中的扩展算术类进行了一些测试,并得出以下结论:

PHP结果与对整数形式的未取整输入进行乘法运算一致,但随后将结果转换为64位浮点数。

以下结果中的所有数字均为十六进制,因为更容易看到正在发生的情况。

完整的产品是db7e4d92597bf73676

舍入为IEEE 754 64位浮点的产品是db7e4d92597bf80000

Java结果为7e4d92597bf73676,是整个乘积的最低有效64位。

PHP乘积为7e4d92597bf80000,即乘积双转换的整数值的最低有效64位。

我不是PHP专家。 PHP是否具有扩展的整数数据类型或库? 为了获得正确的结果,必须从乘积中提取低阶64位,而无需先转换为浮点。

正确的结果是: 4048938043477406987894

它是一个72位数字。 因此存在溢出。

Java部分是正确的4048938043477406987894 mod (2^64) = 9101091335015183990

php实现可能会被PHP_INT_MAX四舍五入,并且应该为9101091335015184428

所以我的猜测是检查PHP_INT_MAX并将其用作JAVA实现。

也可能是echo (int) (160577175182 * 25214903917); echo (int) (int)160577175182 * (int)25214903917;

借助mrVoid的深刻见解

private function java_multi($large_a,$large_b)
{
    $mul_str = bcmul($large_a,$large_b);
    $hex = $this->dec2hex($mul_str);
    $hex = substr($hex,-16);
    return (int) $this->hex2dec($hex);
}

感谢joost

function dec2hex($number)
{
    $hexvalues = array('0','1','2','3','4','5','6','7',
               '8','9','A','B','C','D','E','F');
    $hexval = '';
     while($number != '0')
     {
        $hexval = $hexvalues[bcmod($number,'16')].$hexval;
        $number = bcdiv($number,'16',0);
    }
    return $hexval;
}

// Input: A hexadecimal number as a String.
// Output: The equivalent decimal number as a String.
function hex2dec($number)
{
    $decvalues = array('0' => '0', '1' => '1', '2' => '2',
               '3' => '3', '4' => '4', '5' => '5',
               '6' => '6', '7' => '7', '8' => '8',
               '9' => '9', 'A' => '10', 'B' => '11',
               'C' => '12', 'D' => '13', 'E' => '14',
               'F' => '15');
    $decval = '0';
    $number = strrev($number);
    for($i = 0; $i < strlen($number); $i++)
    {
        $decval = bcadd(bcmul(bcpow('16',$i,0),$decvalues[$number{$i}]), $decval);
    }
    return $decval;
}

这个

java_multi(160577175182,25214903917)

退货

9101091335015183990

与Java相同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM