Модульное умножение больших чисел

Мне нужно найти эффективный алгоритм модульного умножения трех чисел.

Другими словами, есть ли способ найти это в C?

(100100101010001001 * 1010000100100010 * 10010001001010100101001) % 1000000007

person mjnovice    schedule 06.01.2013    source источник


Ответы (1)


Если вы хотите избежать целочисленного переполнения, вы можете преобразовать

(a * b * c) % d

в

((((a % d) * (b % d)) % d) * (c % d)) % d

In C:

unsigned long work(unsigned long a, unsigned long b, unsigned long c, unsigned long d)
{
    unsigned long r = a % d;
    r *= b % d;
    r %= d;
    r *= c % d;
    r %= d;
    return r;
}

Однако он все еще может переполняться, но реже, чем наивная версия. Если вы хотите быть абсолютно уверены, что он не переполнится, вам следует использовать некоторую форму библиотеки больших чисел, например gmplib. Использование будет выглядеть так:

unsigned long work(unsigned long a, unsigned long b, unsigned long c, unsigned long d)
{
    mpz_t tmp, res;
    unsigned long r;
    mpz_init_set_ui(tmp, a);
    mpz_mul_ui(res, tmp, b);
    mpz_mul_ui(tmp, res, c);
    mpz_mod_ui(res, tmp, d);
    r = mpz_get_ui(res);
    mpz_clear(res);
    mpz_clear(tmp);
    return r;
}

Возможно, Gmplib поддерживает прямую установку результата в ту же переменную, что и один из операндов, но я не уверен. Вы должны проверить это в документации.

person kmkaplan    schedule 06.01.2013
comment
ну, это, безусловно, переполняется для указанного примера. Можем ли мы использовать libgmp в C?? - person mjnovice; 06.01.2013
comment
@user1537727 user1537727 Конечно, Gmplib основан на C. Отредактировано, чтобы привести пример. - person kmkaplan; 06.01.2013
comment
@user1537727 user1537727 Являются ли числа, которые вы называете максимальными? В частности, гарантированно ли 1000000007 помещается в 32 бита? Какой у вас компилятор? Отредактированное решение должно работать на 64-битных платформах для ваших номеров. - person kmkaplan; 06.01.2013
comment
@user1537727 user1537727 Извините, я не заметил, что одно из чисел, 10010001001010100101001, имеет длину более 64 бит. В этом случае у вас действительно нет выбора, кроме как использовать какую-то библиотеку больших чисел. - person kmkaplan; 06.01.2013
comment
› В этом случае у вас действительно нет выбора, кроме как использовать библиотеку больших чисел. Подождите, подождите, это неправда! Если вы начинаете с большого числа в виде строки, вы можете получить его значение по модулю следующим образом: uint64_t number = 0; для каждой цифры числительного: {число *= 10; число += цифра-'0'; число %= модуль; } Затем действуйте оттуда, никаких bigints не требуется. - person Don Hatch; 22.08.2013
comment
упс, сотрите число %= модуль из этого - person Don Hatch; 23.08.2013