#c #module #overflow #modular-arithmetic #int128
#c #модуль #переполнение #модульная арифметика #int128
Вопрос:
В моем c-коде я должен выполнить ряд рекурсивных модульных операций. В частности, я должен выполнять такие операции, как (A * B) MoDC, с C ~ 2 ^ 126 и A,B, которые, в принципе, могут быть очень большими числами (от 0 до 2 ^ 128 — 1) (я работаю со 128-битными unsigned __int128
переменными).
Проблема в том, как выполнить модуль во время процесса умножения. Мне это нужно, потому что, если модуль выполняется после умножения, я могу превысить 2 ^ 128 (если A и B очень большие) во время умножения и повредить последовательную модульную операцию.
Итак, я хотел бы выполнить умножение, которое перезапускается с 0 каждый раз, когда я передаю C (во время процесса умножения), а не каждый раз, когда я передаю 2 ^ 128 — 1.
Как мне это сделать?
Ответ №1:
Наивное решение состоит в том, чтобы реализовать умножение как цикл по битам, сдвигая на единицу и добавляя каждый раз. Таким образом, вы можете вычислять модуль промежуточного результата при каждом проходе через цикл.
Для этого требуется 128 сдвигов, 128 дополнений и 128 операций по модулю. Если это слишком медленно для вас, то какой-нибудь специалист, вероятно, может подсказать вам оптимизацию (но все знают, что вам следует рассматривать оптимизацию только после того, как вы уверены, что самое простое решение недостаточно быстрое).
Комментарии:
1. Спасибо за ваш ответ, Том V, я ищу более прямой путь, поскольку мне приходится повторять операцию много раз
2. Единственное, что я могу придумать, это то, что вы можете перевести (a * b) в (An a) * (Bn b) и выбрать n в степени 2, (2 ^ 64, если ваша машина может иметь 128 битных целых чисел). Это делает умножение намного быстрее, чем работа по частям за раз, но затем вам придется повторно собрать полученное 256-битное слово и выполнить 256-битное деление. К сожалению, я не думаю, что есть простой и быстрый ответ на этот вопрос, кроме, возможно, использования готовой библиотеки bignum, где кто-то выполнил эту работу за вас.