Возможно, вы также захотите ознакомиться с модулем gmpy. Это интерфейс между Python и библиотекой с высокой точностью GMP. gmpy обеспечивает функцию переворачивания, которая делает именно то, что вам нужно:
>>> import gmpy
>>> gmpy.invert(1234567, 1000000007)
mpz(989145189)
Изменено ответ
Как отметил @hyh, что gmpy.invert()
возвращает 0, если обратное не существует. Это соответствует поведению функции GMP mpz_invert()
. gmpy.divm(a, b, m)
обеспечивает общее решение для a=bx (mod m)
.
>>> gmpy.divm(1, 1234567, 1000000007)
mpz(989145189)
>>> gmpy.divm(1, 0, 5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: not invertible
>>> gmpy.divm(1, 4, 8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: not invertible
>>> gmpy.divm(1, 4, 9)
mpz(7)
divm()
возвращает решение, когда gcd(b,m) == 1
и вызывает исключение, когда мультипликативный обратный не существует.
Отказ от ответственности: Я являюсь постоянным хранителем библиотеки gmpy.
Обновленный ответ 2
gmpy2 теперь корректно вызывает исключение, если обратное не существует:
>>> import gmpy2
>>> gmpy2.invert(0,5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: invert() no inverse exists
Наивные экспоненцирование не вариант из-за времени (и памяти) предел для любой достаточно большой значение p, например, 1000000007. – dorserg
модульное возведение в степень выполняется с максимальным умножением N * 2, где N - количество бит в экспоненте. используя модуль 2 ** 63-1, обратный может быть вычислен в подсказке и немедленно возвращает результат. – phkahler
Ничего себе, потрясающе. Я знаю о быстром возвышении, я просто не знал, что функция pow() может принимать третий аргумент, который превращает его в модульное возведение в степень. – dorserg