Как вычислить a^^b по модулю m?

Мне нужно эффективно вычислить a^^b по модулю m для больших значений a,b,m‹2^32
, где ^^ — оператор тетрации: 2^^4=2^(2^(2^2) )

m не является простым числом и не степенью десяти.

Вы можете помочь?


person JeanClaudeDaudin    schedule 08.06.2015    source источник
comment
Какой язык? Что вы пробовали?   -  person Thomas Ayoub    schedule 08.06.2015
comment
en.wikipedia.org/wiki/Exponentiation_by_squaring   -  person Adam Stelmaszczyk    schedule 08.06.2015
comment
Вы можете попробовать реализовать его на python, но не забудьте использовать модульное свойство (a mod n) (b mod n) == ab mod n, так как это уменьшит часть вашей работы, в худшем случае a = b = m = 2^32 - 1 конечный результат потребует много времени и памяти для запуска.   -  person Rakholiya Jenish    schedule 08.06.2015
comment
@PhamTrung Это не дубликат, поскольку речь идет о тетрации, а не о возведении в степень.   -  person templatetypedef    schedule 08.06.2015
comment
@Thomas Я использую C ++, но решение на python приветствуется. Я пытался:   -  person JeanClaudeDaudin    schedule 08.06.2015
comment
следующий математический подход неверен (код Python): def tetration(a,b,m): `t=1` `для i в диапазоне (b):` `t1=pow(a,t,m)` `if t==t1:break` `t =t1`` вернуть t1`   -  person JeanClaudeDaudin    schedule 08.06.2015
comment
@bilbo у вас есть какое-нибудь решение этой проблемы, какой-нибудь псевдокод ??   -  person Atul    schedule 26.04.2017


Ответы (1)


Чтобы было ясно, a^^b — это не то же самое, что a^b, это экспоненциальная башня a^(a^(a^...^a)) где есть b копий a, также известная как тетрация . Пусть T(a,b) = a^^b, поэтому T(a,1) = a и T(a,b) = a^T(a,b-1).

Чтобы вычислить T(a,b) по модулю m = a^T(a,b-1) по модулю m, мы хотим вычислить степень по модулю m с чрезвычайно большим показателем степени. Что вы можете использовать, так это то, что модульное возведение в степень является предпериодическим с длиной предпериода, не превышающей наибольшую степень простого числа в простой факторизации m, которая не превышает log_2 m, а длина периода делит phi (m), где phi (m) это функция Эйлера. На самом деле длина периода делит функцию Кармайкла от m, lambda(m). Так,

a^k mod m = a^(k+phi(m)) mod m as long as k>log_2 m.

Обратите внимание, что a не обязательно взаимно просто с m (или позднее с phi(m), phi(phi(m)) и т. д.). Если бы это было так, вы могли бы сказать, что a^k mod m = a^(k mod phi(m)) mod m. Однако это не всегда верно, когда a и m не взаимно просты. Например, phi(100) = 40, и 2^1 по модулю 100 = 2, но 2^41 по модулю 100 = 52. Вы можете уменьшить большие показатели степени до конгруэнтных чисел по модулю фи(m), которые составляют не менее log_2 m, так что вы можно сказать, что 2 ^ 10001 по модулю 100 = 2 ^ 41 по модулю 100, но вы не можете уменьшить это до 2 ^ 1 по модулю 100. Вы можете определить мод m [минимум x] или использовать min + mod (a-min, m) пока a>мин.

Если T(a,b-1) > [log_2 m], то

a^T(a,b-1) mod m = a^(T(a,b-1) mod phi(m) [minimum [log_2 m]])

в противном случае просто вычислите a ^ T (a, b-1) по модулю m.

Рекурсивно вычислите это. Вы можете заменить фи(м) на лямбда(м).

Вычисление простой факторизации числа меньше 2 ^ 32 не займет много времени, поскольку вы можете определить простые множители не более чем за 2 ^ 16 = 65 536 пробных делений. Теоретико-числовые функции, такие как фи и лямбда, легко выражаются в терминах простой факторизации.

На каждом этапе вам нужно будет уметь вычислять модульные степени с малыми показателями.

Вы в конечном итоге вычисляете мощность по модулю phi(m), затем мощность по модулю phi(phi(m)), затем мощность по модулю phi(phi(phi(m))) и т. д. Не требуется так много итераций, прежде чем повторяющийся phi функция равна 1, что означает, что вы сводите все к 0, и вы больше не получаете никаких изменений, увеличивая высоту башни.

Вот пример того типа, который включается в школьные математические соревнования, где участники должны заново открыть это и выполнить вручную. Какие две последние цифры числа 14^^2016?

14^^2016 mod 100 
= 14^T(14,2015) mod 100
= 14^(T(14,2015) mod lambda(100) [minimum 6]) mod 100
= 14^(T(14,2015 mod 20 [minimum 6]) mod 100

T(14,2015) mod 20 
= 14^T(14,2014) mod 20
= 14^(T(14,2014) mod 4 [minimum 4]) mod 20

T(14,2014) mod 4
= 14^T(14,2013) mod 4
= 14^(T(14,2013 mod 2 [minimum 2]) mod 4

T(14,2013) mod 2
= 14^T(14,2012) mod 2
= 14^(T(14,2012 mod 1 [minimum 1]) mod 2
= 14^(1) mod 2
= 14 mod 2
= 0

T(14,2014) mod 4 
= 14^(0 mod 2 [minimum 2]) mod 4
= 14^2 mod 4
= 0

T(14,2015) mod 20
= 14^(0 mod 4 [minimum 4]) mod 20 
= 14^4 mod 20
= 16

T(14,2016) mod 100
= 14^(16 mod 20 [minimum 6]) mod 100
= 14^16 mod 100
= 36

Итак, 14^14^14^...^14 оканчивается цифрами ...36.

person Douglas Zare    schedule 08.06.2015
comment
Можете ли вы дать часть рекурсивного алгоритма в псевдокоде со всеми условиями остановки рекурсии и с учетом случая, когда a и m не взаимно просты. - person JeanClaudeDaudin; 11.06.2015
comment
@bilbo: Причина, по которой я использовал x mod y [min k] вместо x mod y, заключалась в том, что мой ответ обрабатывает случай, когда a не является взаимно простым с m или с phi (m). Я никогда не предполагал, что a относительно просто с m. Строки Если T(a,b-1) › [log_2 m], то a^T(a,b-1) mod m = a^(T(a,b-1) mod phi(m) [минимум [ log_2 m]]), иначе просто вычислите a^T(a,b-1) mod m. опишите алгоритм. - person Douglas Zare; 12.06.2015
comment
Я не понимаю, как вычислить T(a,b-1) без переполнения для проверки T(a,b-1) › [log_2 m]. Рекурсивная функция, которую я вычисляю, это T1(a,b,totient(m),log_2(m)) но я не вижу, как включить тест T(a,b-1) › [log_2 m] - person JeanClaudeDaudin; 12.06.2015
comment
Если b›=1, то T(a,b) ›= a. Если это не позволяет вам сравнить T (a, b) с log_2 m, тогда возьмите логарифмическую базу a обеих сторон, чтобы вы сравнили T (a, b-1) с log_a (log_2 m). Примените это рекурсивно. - person Douglas Zare; 12.06.2015
comment
@DouglasZare, не могли бы вы объяснить это предложение по модулю m [минимум x] или использовать min + mod (a-min,m) до тех пор, пока a›min. Я пытался реализовать этот алгоритм с помощью Eulers totient, и в большинстве моих тестовых случаев это удалось, но не во всех, и особенно в вашем примере, а также, но, поскольку у меня нет реализации лямбда-функции Кармайкла, трудно сравнить результаты. - person Kaveh Hadjari; 12.12.2018
comment
@Kaveh: Что вы имеете в виду, что мой пример не работает? - person Douglas Zare; 13.12.2018
comment
@DouglasZare: Извините, если я неясен: я поместил свою реализацию на repl.it в коде Python: repl. it/repls/UnusualRingedVirtualmachines , В конце он запускает ваш пример, но на выходе получается 16, а не 36, как в вашем примере, поэтому я, должно быть, что-то упустил в вашем объяснении, подсказка будет очень кстати. Спасибо! - person Kaveh Hadjari; 13.12.2018
comment
Починил это. Что у меня не сработало, так это этот шаг: a ^ (T (a, b-1) mod phi (m) [минимум [log_2 m]]). Я изменил его на это: a^T = a^(phi(m) + (T(a,b-1) mod phi(m)) (mod m) в соответствии с решением этого SO-вопроса: stackoverflow.com /questions/21367824/ .. И это сделало это. - person Kaveh Hadjari; 17.12.2018