Werken met grote getallen in PHP

Om modulaire machtsverheffingte gebruiken zoals u zou vereisen bij het gebruik van de Fermat Primality Testmet grote aantallen (100.000+), het vereist een aantal zeer grote berekeningen.

Als ik twee grote getallen vermenigvuldig (bijvoorbeeld: 62574 en 62574), lijkt PHP het resultaat naar een float te casten. Het verkrijgen van de moduluswaarde daarvan levert vreemde waarden op.

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

Is er een manier om PHP deze berekeningen correct te laten uitvoeren? Is er ook een andere methode om moduluswaarden te vinden die voor grote getallen zouden werken?


Antwoord 1, autoriteit 100%

Om de een of andere reden zijn er twee standaardbibliotheken in PHP die de willekeurige lengte/precisiegetallen verwerken: BC Mathen GMP. Persoonlijk geef ik de voorkeur aan GMP, omdat het frisser is en een rijkere API heeft.

Op basis van GMP heb ik Decimal2-klassegeïmplementeerd voor het opslaan en verwerken van valutabedragen ( zoals USD 100,25). Veelmod-berekeningen zonder problemen. Getest met zeergrote getallen.


Antwoord 2, autoriteit 91%

gebruik dit

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

Antwoord 3, autoriteit 38%

heb je een kijkje genomen op bcmod()? php heeft problemen met gehele getallen van meer dan 2^31 – 1 op 32-bits platforms.

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

Antwoord 4, autoriteit 7%

Ik raad je aan om BigIntegerte proberen. Als dat niet lukt, kun je SWIGgebruiken om C/C++-code toe te voegen voor de big integer-berekeningen en koppel het aan je code.


Antwoord 5, autoriteit 5%

Ik heb een heel kleine code voor je geschreven die zeker zal werken in het geval van grote aantallen-

<?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
    */
?>

Je hoeft alleen maar strings te gebruiken om grote getallen op te slaan en om ermee te werken gebruik je GMP-functies in PHP.

U kunt enkele goede GMP-functies bekijken in de officiële PHP-handleiding hier-
http://php.net/manual/en/ref.gmp.php


Antwoord 6, autoriteit 5%

Ik heb een andere oplossing gevonden, maar het nummer wordt opgeslagen als een string. Zodra je het teruggooit naar een numeriek, ben je beperkt tot de precisie van het onderliggende platform. Op een 32-bits platform is de grootste int die u kunt weergeven als een int-type 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"

Antwoord 7, autoriteit 4%

$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);

Antwoord 8, autoriteit 2%

<?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);
?>

Other episodes