在PHP中使用大量数字

时间:2008-10-17 07:49:15

标签: php bignum

要在modular exponentiation使用大号(100,000+)时使用Fermat Primality Test,需要进行一些非常大的计算。

当我乘以两个大数字(例如:62574和62574)时,PHP似乎将结果转换为浮点数。获得模数值会返回奇怪的值。

$x = 62574 * 62574;
var_dump($x);          // float(3915505476) ... correct
var_dump($x % 104659); // int(-72945)  ... wtf.

有没有办法让PHP正确执行这些计算?或者,是否有另一种方法可以找到适用于大数的模数值?

8 个答案:

答案 0 :(得分:52)

由于某种原因,PHP中有两个标准库处理任意长度/精度数:BC MathGMP。我个人更喜欢GMP,因为它更新鲜,并且具有更丰富的API。

基于GMP,我已实施Decimal2 class来存储和处理货币金额(如100.25美元)。 很多的mod计算没有任何问题。使用非常大号进行测试。

答案 1 :(得分:49)

使用此

 $num1 = "123456789012345678901234567890";
 $num2 = "9876543210";
 $r    = mysql_query("Select @sum:=$num1 + $num2");
 $sumR = mysql_fetch_row($r);
 $sum  = $sumR[0];

答案 2 :(得分:19)

你看过bcmod()了吗? php在32位平台上存在超过2 ^ 31 - 1的整数问题。

var_dump(bcmod("$x", '104659') ); // string(4) "2968"

答案 3 :(得分:4)

我建议你试试BigInteger。如果这不成功,您可以使用SWIG为大整数计算添加C / C ++代码并将其链接到您的代码中。

答案 4 :(得分:3)

$x = 62574 * 62574;

// Cast to an integer
$asInt = intval($x);
var_dump($asInt);
var_dump($asInt % 104659);

// Use use sprintf to convert to integer (%d), which will casts to string
$asIntStr = sprintf('%d', $x);
var_dump($asIntStr);
var_dump($asIntStr % 104659);

答案 5 :(得分:3)

我找到了另一个解决方案,但该号码将存储为字符串。一旦将其强制转换为数字,您将被限制在底层平台的精度。在32位平台上,您可以表示为int类型的最大int是2,147,483,647:

/**
 * @param string $a
 * @param string $b
 * @return string
 */
function terminal_add($a, $b){
    return shell_exec('echo "'.$a.'+'.$b.'"|bc');
}

// terminal_add("123456789012345678901234567890", "9876543210")
// output: "123456789012345678911111111100"

答案 6 :(得分:1)

我为你写了一个非常小的代码,如果有大数字肯定会有效 -

<?php
    $x = gmp_strval(gmp_mul("62574","62574")); // $x="3915505476"
    $mod=gmp_strval(gmp_mod($x,"104659"));  //$mod="2968"

    echo "x : ".$x."<br>";
    echo "mod : ".$mod;

    /* Output:
        x : 3915505476
        mod : 2968
    */
?>

您只需使用字符串存储大数字,并使用PHP中的GMP函数对它们进行操作。

您可以在官方PHP手册中查看一些优秀的GMP功能 - http://php.net/manual/en/ref.gmp.php

答案 7 :(得分:1)

<?php
function add($int1,$int2){
    $int1 = str_pad($int1, strlen($int2), '0', STR_PAD_LEFT);
    $int2 = str_pad($int2, strlen($int1), '0', STR_PAD_LEFT);
    $carry = 0;
    $str = "";
    for($i=strlen($int1);$i>0;$i--){
        $var = $int1[$i-1] + $int2[$i-1] + $carry;
        $var = str_pad($var, 2, '0', STR_PAD_LEFT);
        $var = (string) $var;
        $carry = $var[0];
        $str = $str . $var[1];
    }
    $res = strrev($str.$carry);
    echo ltrim($res,"0");
}
add($int1,$int2);
?>