php 64bit整数溢出与Java implmention不同

时间:2014-07-27 14:43:38

标签: java php random

我正在尝试在php中实现Java的Random类,经过几个小时后,我发现当将两个64位长的数字相乘时,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结果。

3 个答案:

答案 0 :(得分:3)

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

PHP结果与以整数形式对未接地输入进行乘法,然后将结果转换为64位浮点一致。

以下结果中的所有数字都是十六进制的,因为它更容易看到发生了什么。

完整产品是db7e4d92597bf73676

舍入到IEEE 754 64位浮点的乘积为db7e4d92597bf80000

Java结果是7e4d92597bf73676,是完整产品中最不重要的64位。

PHP产品是7e4d92597bf80000,是产品双重转换整数值的最低64位。

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

答案 1 :(得分:0)

正确的结果是: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;

不同

答案 2 :(得分:0)

凭借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相同。