Чтобы предотвратить переполнение, вы можете использовать тот факт, что вы получите тот же результат, если вы сначала берете по модулю каждого из ваших входных чисел; на самом деле:
(M**k) mod p = ([M mod p]**k) mod p,
для матрицы M
. Это происходит из следующих двух основных тождеств, которые действительны для целых чисел x
и y
:
(x+y) mod p = ([x mod p]+[y mod p]) mod p # All additions can be done on numbers *modulo p*
(x*y) mod p = ([x mod p]*[y mod p]) mod p # All multiplications can be done on numbers *modulo p*
То же самое относится и к матрицам, поскольку сложение и умножение матриц может быть выражено посредством скалярного сложения и умножения. При этом вы только возводите в степень небольшие числа (n mod p обычно намного меньше, чем n), и вероятность переполнения гораздо ниже. Поэтому в NumPy вы просто делаете
((arr % p)**k) % p
чтобы получить (arr**k) mod p
.
Если этого по-прежнему недостаточно (т. Е. Существует риск того, что [n mod p]**k
вызовет переполнение, несмотря на то, что n mod p
является небольшим), вы можете разбить возведение в степень в несколько возведений в степень. Фундаментальные тождества выше дают
(n**[a+b]) mod p = ([{n mod p}**a mod p] * [{n mod p}**b mod p]) mod p
и
(n**[a*b]) mod p = ([n mod p]**a mod p)**b mod p.
Таким образом, вы можете разбить мощность k
на a+b+…
или a*b*…
или любую их комбинацию. Приведенные выше идентификаторы позволяют выполнять возведения только небольших чисел в маленькие числа, что значительно снижает риск переполнения целых чисел.