Работа с большими числами в PHP

Чтобы использовать модульное возведение в степень, как вам потребуется при использовании критерия примитивности Ферма с большими числами (более 100000), требуется несколько очень больших вычислений.

Когда я умножаю два больших числа (например, 62574 и 62574), PHP, кажется, приводит результат к плавающей запятой. Получение значения модуля, которое возвращает странные значения.

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

Есть ли способ заставить PHP выполнять эти вычисления правильно? Альтернативно, есть ли другой метод для нахождения значений модуля, который работал бы для больших чисел?

7 ответов

Решение

По какой-то причине в PHP есть две стандартные библиотеки, обрабатывающие произвольные числа длины / точности: BC Math и GMP. Я лично предпочитаю GMP, так как он более свежий и имеет более богатый API.

На основе GMP я реализовал класс Decimal2 для хранения и обработки сумм в валюте (например, 100,25 долларов США). Множество мод расчетов без проблем. Проверено с очень большими числами.

Использовать этот

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

Вы смотрели на bcmod()? У php проблемы с целыми числами свыше 2^31 - 1 на 32-битных платформах.

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

Я предлагаю вам попробовать BigInteger. Если это не сработает, вы можете использовать SWIG, чтобы добавить код C/C++ для больших целочисленных вычислений и связать его с вашим кодом.

Я написал очень маленький код для вас, который, безусловно, будет работать в случае больших чисел

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

Вам просто нужно использовать строки для хранения больших чисел, а для работы с ними использовать функции GMP в PHP.

Вы можете проверить некоторые хорошие функции GMP в официальном руководстве по PHP здесь - http://php.net/manual/en/ref.gmp.php

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

Я нашел другое решение, но номер будет сохранен в виде строки. Как только вы приведете его к числовому значению, вы будете ограничены точностью базовой платформы. На 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"
<?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);
?>
Другие вопросы по тегам