Да, я знаю, что вопрос может показаться наивным, но я много искал в Google и на этом сайте, но не смог найти удовлетворительного ответа на него. Я просто хочу вычислить (A * B)% MOD, если a длинный длинный, а также b и MOD. Предположим, что MOD больше, чем A и B, такие, что A% MOD = A и B% MOD = B, но A * B больше, чем 64 бит. Как можно исправить значение (A * B)% MOD?Modulo умножения больших чисел
ответ
Основная идея заключается в том, чтобы сначала определить непереполняющую функцию addmod
, которая использует отрицательные числа в своей арифметике. Затем определите timesmod
с помощью битовых операций. Сложность времени равна O(N)
, где N - количество используемых бит (в этом случае 64).
#include <iostream>
using namespace std;
typedef long long BigInt; // must be signed, to detect overflow
BigInt A = 0x7fffffffffffff01;
BigInt B = 0x7fffffffffffff02;
BigInt M = 0x7fffffffffffff03;
// For simplicity it is assumed x, y, and m are all positive.
BigInt addmod(BigInt x, BigInt y, BigInt m)
{
x %= m;
y %= m;
BigInt sum = x-m+y; // -m <= sum < m-1
return sum < 0 ? sum + m : sum;
}
BigInt timesmod(BigInt x, BigInt y, BigInt m)
{
x %= m;
y %= m;
BigInt a = x < y ? x : y; // min
BigInt b = x < y ? y : x; // max
BigInt product = 0;
for (; a != 0; a >>= 1, b = addmod(b,b,m))
if (a&1) product = addmod(product,b,m);
return product;
}
int main()
{
cout << "A = " << A << endl;
cout << "B = " << B << endl;
cout << "M = " << M << endl;
cout << "A*B mod M = " << timesmod(A,B,M) << endl;
return 0;
}
Выход:
A = 9223372036854775553
B = 9223372036854775554
M = 9223372036854775555
A*B mod M = 2
Это легко подтверждается, так как A=-2
и B=-1
мод M
.
Примечание: этот код не оптимизирован.
Проблема в том, что вы используете подписанный тип для BigInt, поэтому вы не можете надежно обнаружить переполнение (это вызывает неопределенное поведение). Для получения надёжного поведения переполнения необходимо использовать неподписанный тип. –
@ChrisDodd Ты абсолютно прав; Спасибо что подметил это. Я обновил функцию 'addMod', чтобы исправить это. – Matt
Ваш метод почти идентичен окончательному методу, который я написал, который есть: 'long long int multiply (длинный длинный a, длинный длинный b, длинный длинный мод) { \t длинный длинный результат; \t if (b == 0) return 0LL; \t \t результат = умножить (a, b >> 1, mod); \t результат = (результат + результат)% mod; \t if (b & 1) result = (результат + a)% mod; \t \t результат возврата; } ' – unrealsoul007
У меня нет времени ответить на это прямо сейчас, поэтому я дам указатель и вернусь, чтобы позже отредактировать этот ответ. Посмотрите «умножение грамотности» в своем любимом учебнике алгоритмов (или поисковой системе). Основная идея состоит в том, чтобы разделить как A, так и B на кусочки, обработать куски по отдельности, а затем объединить куски, чтобы завершить расчет.
Я думаю, что вы можете сформировать 128-битный продукт в две части (высокие 64 бит и низкие 64 бит) и уменьшить каждую часть по модулю p. Предполагая, что p
составляет около 4^k
, вы можете затем выяснить, сколько p находится в этом количестве, разделив hi64/(p>>k)
; это должно дать вам примерно k-1
бит правильного ответа. Вычитайте, что много p
от всего, и теперь hi64
имеет около k-1
меньше бит. Сделайте это снова, но вычислите (hi64 << k-1)/(p >> k)
. Затем сделайте это снова, вычислив (hi64 << k+k-2)/(p >> k)
.
Шрифт, предложенный другим плакатом, звучит лучше, но я этого не понимаю. Надеюсь, этот плакат вернется и завершит свой ответ!
- 1. Modulo для больших чисел, которые квадратные
- 2. OR-умножения на больших целых
- 3. Параллельное умножение больших целых чисел
- 4. Потеря точности умножения больших длинных
- 5. Мультипликатор больших целых чисел (факториал)
- 6. Предел умножения целых чисел для библиотеки GMP
- 7. Двойная точность: умножение больших чисел
- 8. Modulo in custom class
- 9. Вычислить остаток умножения двух длинных чисел?
- 10. Умножение больших чисел в C++
- 11. Модульное умножение больших чисел в C++
- 12. (a/b) mod n для больших чисел?
- 13. Быстрое умножение больших чисел по модулю п
- 14. n! modulo m, a^p modulo m
- 15. Для следующих чисел умножения цикла
- 16. Алгоритм для умножения двух чисел
- 17. Умножение списка чисел без умножения
- 18. Использование modulo в диапазоне чисел в Ruby
- 19. Как проверить умножение двух больших чисел
- 20. Модификация модуля больших чисел
- 21. Математическое представление больших чисел?
- 22. Типы для больших чисел
- 23. Отдел больших чисел
- 24. Сортировка больших чисел
- 25. Суммирование больших чисел
- 26. Факторизация больших чисел
- 27. Отливки больших чисел
- 28. Найти факториал больших чисел
- 29. C++ Обработка больших чисел
- 30. ASM печать больших чисел
Мэтт: Я не согласен с дуплексом. unrealsoul: A * B = (A-X) * B + X * B, вы всегда можете разбить A таким образом на меньшие числа. Например. установите X = пол (A/2). Затем вы можете применить ту же процедуру, если субрезультат все еще слишком велик. –
Это комментарий человека, ответ которого принимается «Если максимальное значение long равно 2^63 - 1, тогда 1768431 * x не будет переполняться до тех пор, пока x <290331368171». Но это точно мое сомнение в том, что если A * B переполняется. – unrealsoul007
другими словами, divide et impera –