Project Euler 282 asks for the modular sum
$$\sum_{n=0}^{6} A(n,n)\pmod{14^8},$$
where \(A(m,n)\) is the standard Ackermann function
$$A(0,n)=n+1,$$
$$A(m,0)=A(m-1,1)\quad (m\ge1),$$
$$A(m,n)=A(m-1,A(m,n-1))\quad (m,n\ge1).$$
The modulus is
$$M=14^8=1475789056.$$
The final residue is intentionally omitted; this page explains why the C++ solution can compute it without ever building the astronomically large raw Ackermann values.
Starting from the definition, one gets the standard low-level identities:
$$A(0,n)=n+1,$$
$$A(1,n)=n+2,$$
$$A(2,n)=2n+3,$$
$$A(3,n)=2^{n+3}-3.$$
Therefore the diagonal values needed in the sum begin as
$$A(0,0)=1,\qquad A(1,1)=3,\qquad A(2,2)=7,\qquad A(3,3)=61.$$
These are exactly the constants returned by solve_n0(), solve_n1(), solve_n2(), and solve_n3().
Because
$$A(3,n)=2^{n+3}-3,$$
the next level satisfies
$$A(4,n+1)=A(3,A(4,n))=2^{A(4,n)+3}-3.$$
This is exactly the recursion of a power tower. Using Knuth's notation,
$$A(4,n)=2\uparrow\uparrow(n+3)-3,$$
where
$$2\uparrow\uparrow1=2,\qquad 2\uparrow\uparrow(h+1)=2^{\,2\uparrow\uparrow h}.$$
In particular, the \(n=4\) diagonal term is
$$A(4,4)=2\uparrow\uparrow7-3.$$
This is why the code computes
$$\texttt{hyper\_tower\_2(7,M)}-3 \pmod M$$
inside solve_n4().
The same pattern continues:
$$A(5,n)=2\uparrow\uparrow\uparrow(n+3)-3,$$
$$A(6,n)=2\uparrow\uparrow\uparrow\uparrow(n+3)-3,$$
and so on.
So the last two needed diagonal terms, \(A(5,5)\) and \(A(6,6)\), are not merely “very large”; they are far beyond any direct representation. The only sensible target is their residue modulo \(M\).
hyper_tower_2(h,m) computesThe recursive helper does not compute the actual tower \(2\uparrow\uparrow h\). It computes only its residue modulo \(m\):
$$T_h(m):=2\uparrow\uparrow h \pmod m.$$
For small heights the values are explicit:
$$T_0(m)=1,\qquad T_1(m)=2,\qquad T_2(m)=4,\qquad T_3(m)=16,\qquad T_4(m)=65536,$$
all taken modulo \(m\). These base cases are hard-coded in the function.
For large heights, we want
$$2^{E}\pmod m,$$
where \(E=2\uparrow\uparrow(h-1)\) is itself enormous. The classical coprime reduction says that modulo an odd modulus one may reduce exponents modulo \(\varphi(m)\). Here the base is \(2\), and our moduli along the recursion are not always coprime to \(2\), so one has to be careful.
The code uses the standard “lifted exponent” strategy:
1. compute the upper exponent modulo \(\varphi(m)\);
2. add one full totient period;
3. exponentiate modulo \(m\).
Formally, for the huge towers occurring in this problem, it evaluates
$$2^{\,e+\varphi(m)}\pmod m,$$
where
$$e=T_{h-1}(\varphi(m)).$$
This is exactly what the code does through
$$\texttt{eff\_exponent = exponent\_val + phi}.$$
This lift is not being used as a blind universal theorem for tiny exponents. It is safe here because all tower heights entering the recursive branch are already huge.
The modulus is
$$M=14^8=2^8\cdot 7^8.$$
For the \(2^8\) part, once the exponent is at least \(8\), we already have
$$2^E\equiv 0\pmod{2^8}.$$
For the odd part \(7^8\), the base \(2\) is coprime, so Euler reduction modulo
$$\varphi(7^8)=6\cdot 7^7$$
is valid.
Adding \(\varphi(m)\) guarantees that the reconstructed exponent is safely “large enough” for the \(2\)-power part while keeping the correct residue information for the odd part. Since the actual exponents in the problem are vastly larger than \(8\), this lifted reduction matches the true tower residue.
An important phenomenon is that the residues
$$2\uparrow\uparrow h \pmod M$$
eventually stabilize. In fact, with the recursion used by the code, the residue stops changing once the tower height is large enough. A direct check shows that the values are already constant from height \(11\) onward.
That means:
every sufficiently tall power tower of 2 has the same residue modulo \(M\).
This is the key reason the gigantic terms \(A(5,5)\) and \(A(6,6)\) become tractable.
We have
$$A(5,5)+3=2\uparrow\uparrow\uparrow 8,$$
which means “a tetration whose height is itself already enormous.” Likewise \(A(6,6)+3\) is vastly larger still.
Since tower residues modulo \(M\) have already stabilized by modest height, both of these Ackermann values land in the same stabilized residue class. Therefore the code is allowed to replace each of them by
$$2\uparrow\uparrow 200 \pmod M$$
as a safe surrogate. The particular choice \(200\) is not mathematically special; it is simply far beyond the stabilization threshold.
That is why solve_large_n() is called twice, once for the \(n=5\) term and once for the \(n=6\) term.
The problem asks for
$$S=\sum_{n=0}^{6}A(n,n)\pmod M.$$
The implementation splits this into:
four exact small constants for \(n=0,1,2,3\);
one genuine tetration term for \(n=4\), namely \(2\uparrow\uparrow7-3\);
two identical stabilized huge-level residues for \(n=5\) and \(n=6\).
So the entire problem is reduced to a few modular tower evaluations, not to raw Ackermann growth.
1) Fast modular power. power() uses binary exponentiation with 128-bit intermediate multiplication.
2) Totient computation. get_phi() factors the current modulus on the fly and returns \(\varphi(m)\).
3) Tower recursion. hyper_tower_2(height,m) evaluates \(2\uparrow\uparrow\text{height}\pmod m\) by recurring into modulus \(\varphi(m)\) and then lifting the exponent by one totient.
4) Ackermann layers. solve_n0() through solve_n3() return exact constants; solve_n4() returns the \(A(4,4)\) residue; solve_large_n() returns the stabilized residue used for both \(A(5,5)\) and \(A(6,6)\).
5) Final sum. The main function launches the seven pieces independently, collects them, and sums modulo \(M\).
Each modular exponentiation costs \(O(\log e)\). The recursion depth is controlled by the totient chain of the modulus, and the tower height is replaced by small explicit heights or by a safe stabilized surrogate. So the runtime is tiny compared with the impossible cost of direct Ackermann evaluation, and memory usage is essentially constant.
Project Euler 282 verlangt die modulare Summe
$$\sum_{n=0}^{6}A(n,n)\pmod{14^8},$$
wobei \(A(m,n)\) die Standard-Ackermannfunktion ist:
$$A(0,n)=n+1,$$
$$A(m,0)=A(m-1,1)\quad(m\ge1),$$
$$A(m,n)=A(m-1,A(m,n-1))\quad(m,n\ge1).$$
Das Modul lautet
$$M=14^8=1475789056.$$
Die finale Restklasse wird hier nicht genannt; wichtig ist, wie der Code die riesigen Ackermann-Werte auf einige modulare Turmrechnungen reduziert.
Aus der Definition folgen die bekannten Identitäten
$$A(0,n)=n+1,$$
$$A(1,n)=n+2,$$
$$A(2,n)=2n+3,$$
$$A(3,n)=2^{n+3}-3.$$
Daraus ergeben sich auf der Diagonale sofort
$$A(0,0)=1,\qquad A(1,1)=3,\qquad A(2,2)=7,\qquad A(3,3)=61.$$
Genau diese Werte liefern solve_n0() bis solve_n3().
Wegen
$$A(3,n)=2^{n+3}-3$$
gilt für die nächste Ebene
$$A(4,n+1)=A(3,A(4,n))=2^{A(4,n)+3}-3.$$
Das ist genau die Rekursion eines Potenzturms. In Knuth-Notation:
$$A(4,n)=2\uparrow\uparrow(n+3)-3,$$
wobei
$$2\uparrow\uparrow1=2,\qquad 2\uparrow\uparrow(h+1)=2^{\,2\uparrow\uparrow h}.$$
Insbesondere ist
$$A(4,4)=2\uparrow\uparrow7-3.$$
Darum berechnet solve_n4() genau den Term
$$\texttt{hyper\_tower\_2(7,M)}-3 \pmod M.$$
Das Muster setzt sich fort:
$$A(5,n)=2\uparrow\uparrow\uparrow(n+3)-3,$$
$$A(6,n)=2\uparrow\uparrow\uparrow\uparrow(n+3)-3.$$
Damit sind \(A(5,5)\) und \(A(6,6)\) unvorstellbar groß. Sinnvoll ist nur noch ihre Restklasse modulo \(M\).
hyper_tower_2(h,m) tatsächlich auswertetDie Hilfsfunktion berechnet nicht den echten Turm \(2\uparrow\uparrow h\), sondern nur seinen Rest modulo \(m\):
$$T_h(m):=2\uparrow\uparrow h \pmod m.$$
Für kleine Höhen sind die Werte direkt bekannt:
$$T_0(m)=1,\qquad T_1(m)=2,\qquad T_2(m)=4,\qquad T_3(m)=16,\qquad T_4(m)=65536,$$
jeweils modulo \(m\). Diese Basisfälle sind im Code explizit eingebaut.
Für große Höhen möchten wir
$$2^E\pmod m$$
berechnen, wobei \(E=2\uparrow\uparrow(h-1)\) selbst gewaltig ist. Für ungerade Moduli darf man Exponenten modulo \(\varphi(m)\) reduzieren. Hier ist die Basis aber \(2\), also nicht immer teilerfremd zum aktuellen Modul.
Der Code verwendet daher die übliche „angehobene Exponenten“-Strategie:
erst den oberen Exponenten modulo \(\varphi(m)\) berechnen,
dann eine volle Totient-Periode addieren,
und schließlich modulo \(m\) potenzieren.
Formal wird also
$$2^{\,e+\varphi(m)}\pmod m$$
mit
$$e=T_{h-1}(\varphi(m))$$
ausgewertet. Genau das steckt im Code in
$$\texttt{eff\_exponent = exponent\_val + phi}.$$
Das ist hier keine blinde Allgemeinaussage für kleine Exponenten. Es ist sicher, weil alle Türme, die in diesen Rekursionszweig gelangen, bereits riesig sind.
Das Modul faktorisiert als
$$M=14^8=2^8\cdot 7^8.$$
Für den \(2^8\)-Anteil genügt bereits
$$E\ge 8,$$
damit
$$2^E\equiv0\pmod{2^8}.$$
Für den ungeraden Anteil \(7^8\) ist \(2\) teilerfremd, also darf der Exponent modulo
$$\varphi(7^8)=6\cdot 7^7$$
reduziert werden. Das Hinzufügen von \(\varphi(m)\) stellt sicher, dass der rekonstruierte Exponent für den Zweieranteil groß genug bleibt, während die richtige Information für den ungeraden Anteil erhalten bleibt.
Die Reste
$$2\uparrow\uparrow h \pmod M$$
werden ab hinreichender Höhe konstant. Mit der im Code verwendeten Rekursion stabilisiert sich der Wert bereits ab Höhe \(11\).
Das bedeutet:
jeder ausreichend hohe Zweierturm hat modulo \(M\) denselben Rest.
Genau dadurch werden die gigantischen Terme \(A(5,5)\) und \(A(6,6)\) überhaupt behandelbar.
Es gilt
$$A(5,5)+3=2\uparrow\uparrow\uparrow 8,$$
also eine Tetration, deren Höhe selbst schon astronomisch ist. \(A(6,6)+3\) ist noch ungleich größer.
Da sich die Turmreste modulo \(M\) aber schon ab kleiner Höhe stabilisieren, fallen beide Werte in dieselbe stabile Restklasse. Deshalb darf der Code beide durch
$$2\uparrow\uparrow 200 \pmod M$$
ersetzen. Die Höhe \(200\) ist nicht speziell; sie liegt einfach weit jenseits der Stabilisierungsschwelle.
Gesucht ist
$$S=\sum_{n=0}^{6}A(n,n)\pmod M.$$
Die Implementierung zerlegt dies in:
vier kleine exakte Konstanten für \(n=0,1,2,3\);
einen echten Tetrationsterm für \(n=4\), nämlich \(2\uparrow\uparrow7-3\);
zwei identische stabilisierte Großterme für \(n=5\) und \(n=6\).
1) Schnelle Modpotenz. power() verwendet binäre Exponentiation mit 128-Bit-Zwischenprodukten.
2) Totient-Berechnung. get_phi() faktorisiert den aktuellen Modulus und liefert \(\varphi(m)\).
3) Turmrekursion. hyper_tower_2(height,m) berechnet \(2\uparrow\uparrow\text{height}\pmod m\), indem rekursiv auf \(\varphi(m)\) gewechselt und danach der Exponent um eine Totient-Periode angehoben wird.
4) Ackermann-Schichten. solve_n0() bis solve_n3() liefern exakte Konstanten; solve_n4() liefert den \(A(4,4)\)-Rest; solve_large_n() liefert den stabilisierten Großrest für \(A(5,5)\) und \(A(6,6)\).
5) Endsumme. In main() werden die sieben Bausteine separat berechnet und modulo \(M\) addiert.
Jede modulare Potenzierung kostet \(O(\log e)\). Die Rekursionstiefe wird durch die Totient-Kette des Moduls begrenzt, und die effektiven Turmhöhen werden durch kleine exakte Basisfälle oder eine stabile Ersatzhöhe abgeschnitten. Damit bleibt die Laufzeit winzig, verglichen mit jeder direkten Ackermann-Auswertung, und der Speicherbedarf ist praktisch konstant.
Project Euler 282,
$$\sum_{n=0}^{6} A(n,n)\pmod{14^8}$$
toplamını ister; burada \(A(m,n)\) standart Ackermann fonksiyonudur:
$$A(0,n)=n+1,$$
$$A(m,0)=A(m-1,1)\quad(m\ge1),$$
$$A(m,n)=A(m-1,A(m,n-1))\quad(m,n\ge1).$$
Modül
$$M=14^8=1475789056$$
olur. Nihai kalıntı burada verilmez; amaç, kodun dev Ackermann değerlerini nasıl küçük bir modüler üs kulesi hesabına indirdiğini açıklamaktır.
Tanımdan şu klasik özdeşlikler çıkar:
$$A(0,n)=n+1,$$
$$A(1,n)=n+2,$$
$$A(2,n)=2n+3,$$
$$A(3,n)=2^{n+3}-3.$$
Bu yüzden diyagonalda hemen
$$A(0,0)=1,\qquad A(1,1)=3,\qquad A(2,2)=7,\qquad A(3,3)=61$$
elde edilir. Kodda solve_n0() ile solve_n3() tam olarak bu sabitleri döndürür.
\(A(3,n)=2^{n+3}-3\) olduğundan
$$A(4,n+1)=A(3,A(4,n))=2^{A(4,n)+3}-3$$
yazılır. Bu, tam olarak üs kulesi özyinelemesidir. Knuth ok gösterimiyle:
$$A(4,n)=2\uparrow\uparrow(n+3)-3,$$
burada
$$2\uparrow\uparrow1=2,\qquad 2\uparrow\uparrow(h+1)=2^{\,2\uparrow\uparrow h}.$$
Özellikle
$$A(4,4)=2\uparrow\uparrow7-3$$
olur. Bu yüzden solve_n4() içinde
$$\texttt{hyper\_tower\_2(7,M)}-3 \pmod M$$
hesaplanır.
Örüntü devam eder:
$$A(5,n)=2\uparrow\uparrow\uparrow(n+3)-3,$$
$$A(6,n)=2\uparrow\uparrow\uparrow\uparrow(n+3)-3.$$
Dolayısıyla \(A(5,5)\) ve \(A(6,6)\) “çok büyük” değil, pratik olarak temsil edilemez kadar büyük sayılardır. Tek makul hedef bunların mod \(M\) altındaki kalıntılarıdır.
hyper_tower_2(h,m) gerçekte ne hesaplar?Bu yardımcı fonksiyon, gerçek \(2\uparrow\uparrow h\) değerini kurmaz; yalnızca onun mod \(m\) kalıntısını hesaplar:
$$T_h(m):=2\uparrow\uparrow h \pmod m.$$
Küçük yükseklikler için değerler doğrudan bilinir:
$$T_0(m)=1,\qquad T_1(m)=2,\qquad T_2(m)=4,\qquad T_3(m)=16,\qquad T_4(m)=65536,$$
tabii hepsi mod \(m\) altında. Kodun base case’leri bunları açıkça kullanır.
Yüksek kulelerde hesaplamak istediğimiz şey
$$2^E\pmod m$$
şeklindedir; burada \(E=2\uparrow\uparrow(h-1)\) zaten devasa büyüktür. Taban \(2\) olduğundan modül her zaman eş-asal olmayabilir; bu yüzden sıradan Euler indirgemesini körlemesine uygulamak yetmez.
Kod şu “kaldırılmış üs” stratejisini kullanır:
1. üstteki üssü \(\varphi(m)\) modunda hesapla,
2. bir tam totient periyodu ekle,
3. sonra mod \(m\) altında üsle.
Formel olarak, büyük kuleler için
$$2^{\,e+\varphi(m)}\pmod m$$
hesaplanır; burada
$$e=T_{h-1}(\varphi(m)).$$
Koddaki
$$\texttt{eff\_exponent = exponent\_val + phi}$$
satırı tam olarak budur.
Bu düzeltme, küçük üsler için evrensel bir sihirli kural olarak kullanılmıyor. Burada güvenli olmasının sebebi, bu dala giren bütün kule yüksekliklerinin zaten aşırı büyük olmasıdır.
Modülün çarpanlara ayrılması
$$M=14^8=2^8\cdot 7^8$$
şeklindedir. \(2^8\) kısmı için üs
$$E\ge 8$$
olduğu anda
$$2^E\equiv0\pmod{2^8}$$
olur. Tek sayılı kısım olan \(7^8\) için ise taban \(2\) eş-asaldır; dolayısıyla üs,
$$\varphi(7^8)=6\cdot 7^7$$
modunda indirgenebilir.
\(\varphi(m)\) eklemek, yeniden kurulan üssün \(2\)-adic kısım için yeterince büyük kalmasını sağlarken, tek sayılı kısım için gerekli modüler bilgiyi de korur. Bu problemde gerçek üsler zaten 8’in çok çok üzerindedir; dolayısıyla bu kaldırma doğru kalıntıyı verir.
Şu kalıntılar
$$2\uparrow\uparrow h \pmod M$$
yeterince büyük \(h\) için sabitlenir. Kodun kullandığı özyineleme ile bu stabilizasyonun yükseklik \(11\) civarında oluştuğu doğrudan görülebilir.
Yani:
yeterince yüksek bütün 2 tabanlı üs kuleleri mod \(M\) altında aynı kalıntıya iner.
İşte \(A(5,5)\) ve \(A(6,6)\) terimlerini yönetilebilir yapan şey budur.
Şuna dikkat edin:
$$A(5,5)+3=2\uparrow\uparrow\uparrow 8.$$
Bu, yüksekliği kendi başına astronomik olan bir tetrasyon anlamına gelir. \(A(6,6)+3\) ise bundan da çok daha büyüktür.
Fakat mod \(M\) altında kule kalıntıları zaten küçük bir yükseklikten sonra sabitlendiği için, bu iki değer aynı kararlı kalıntı sınıfına düşer. Bu yüzden kod her ikisini de güvenli bir vekil olarak
$$2\uparrow\uparrow 200 \pmod M$$
ile temsil eder. \(200\) sayısının özel bir anlamı yoktur; yalnızca stabilizasyon eşiğinin çok üstündedir.
Bu nedenle solve_large_n() iki kez çağrılır: biri \(A(5,5)\), biri \(A(6,6)\) için.
Aranan ifade
$$S=\sum_{n=0}^{6}A(n,n)\pmod M$$
olduğundan, implementasyon bunu şu parçalara ayırır:
\(n=0,1,2,3\) için dört küçük sabit;
\(n=4\) için tek gerçek tetrasyon terimi, yani \(2\uparrow\uparrow7-3\);
\(n=5\) ve \(n=6\) için iki adet aynı stabilize büyük-terim kalıntısı.
Böylece bütün problem, gerçek Ackermann büyümesini üretmeden birkaç modüler kule hesabına indirgenmiş olur.
1) Hızlı modüler üs alma. power(), 128-bit ara çarpımlarla binary exponentiation uygular.
2) Totient hesabı. get_phi() mevcut modülü çarpanlarına ayırıp \(\varphi(m)\) döndürür.
3) Kule özyinelemesi. hyper_tower_2(height,m), \(2\uparrow\uparrow\text{height}\pmod m\) değerini, \(\varphi(m)\)’ye inip sonra üssü bir totient periyodu kadar kaldırarak hesaplar.
4) Ackermann katmanları. solve_n0()-solve_n3() tam sabitleri, solve_n4() \(A(4,4)\) kalıntısını, solve_large_n() ise \(A(5,5)\) ve \(A(6,6)\) için ortak stabilize kalıntıyı üretir.
5) Son toplam. main() yedi bileşeni ayrı hesaplatır ve mod \(M\) altında toplar.
Her modüler üs alma \(O(\log e)\) zamandadır. Özyineleme derinliği modülün totient zinciriyle sınırlıdır; kule yükseklikleri ya küçük kapalı durumlarla ya da stabilize güvenli vekillerle kesildiği için toplam süre çok küçüktür. Doğrudan Ackermann hesaplamasıyla karşılaştırıldığında bu yaklaşım pratikte sabit maliyetlidir.
Project Euler 282 pide la suma modular
$$\sum_{n=0}^{6}A(n,n)\pmod{14^8},$$
donde \(A(m,n)\) es la función de Ackermann estándar:
$$A(0,n)=n+1,$$
$$A(m,0)=A(m-1,1)\quad(m\ge1),$$
$$A(m,n)=A(m-1,A(m,n-1))\quad(m,n\ge1).$$
El módulo es
$$M=14^8=1475789056.$$
Aquí no se muestra el residuo final; interesa entender cómo el código sustituye valores de Ackermann imposibles de construir por unas pocas evaluaciones modulares de torres de potencias.
De la definición se obtienen las identidades clásicas
$$A(0,n)=n+1,$$
$$A(1,n)=n+2,$$
$$A(2,n)=2n+3,$$
$$A(3,n)=2^{n+3}-3.$$
Por tanto, en la diagonal aparecen inmediatamente
$$A(0,0)=1,\qquad A(1,1)=3,\qquad A(2,2)=7,\qquad A(3,3)=61.$$
Éstos son los valores exactos que devuelven solve_n0() hasta solve_n3().
Como
$$A(3,n)=2^{n+3}-3,$$
la siguiente capa satisface
$$A(4,n+1)=A(3,A(4,n))=2^{A(4,n)+3}-3.$$
Eso es exactamente la recursión de una torre de potencias. En notación de Knuth,
$$A(4,n)=2\uparrow\uparrow(n+3)-3,$$
donde
$$2\uparrow\uparrow1=2,\qquad 2\uparrow\uparrow(h+1)=2^{\,2\uparrow\uparrow h}.$$
En particular,
$$A(4,4)=2\uparrow\uparrow7-3.$$
Por eso solve_n4() calcula
$$\texttt{hyper\_tower\_2(7,M)}-3 \pmod M.$$
El patrón continúa:
$$A(5,n)=2\uparrow\uparrow\uparrow(n+3)-3,$$
$$A(6,n)=2\uparrow\uparrow\uparrow\uparrow(n+3)-3.$$
Así, \(A(5,5)\) y \(A(6,6)\) ya no son simplemente enormes; están mucho más allá de cualquier representación directa. Solo tiene sentido su residuo módulo \(M\).
hyper_tower_2(h,m)La función auxiliar no construye la torre real \(2\uparrow\uparrow h\). Solo calcula su residuo módulo \(m\):
$$T_h(m):=2\uparrow\uparrow h \pmod m.$$
Para alturas pequeñas, los valores son explícitos:
$$T_0(m)=1,\qquad T_1(m)=2,\qquad T_2(m)=4,\qquad T_3(m)=16,\qquad T_4(m)=65536,$$
siempre tomados módulo \(m\). Estos casos base están codificados directamente.
Para alturas grandes queremos evaluar
$$2^E\pmod m,$$
donde \(E=2\uparrow\uparrow(h-1)\) es gigantesco. Para módulos impares, se puede reducir el exponente módulo \(\varphi(m)\). Aquí la base es \(2\), así que no siempre es coprima con el módulo.
Por eso el código usa la estrategia estándar de “exponente levantado”:
1. calcular el exponente superior módulo \(\varphi(m)\);
2. sumar una vuelta completa de la función totiente;
3. exponentiar módulo \(m\).
Formalmente, para estas torres enormes se evalúa
$$2^{\,e+\varphi(m)}\pmod m,$$
con
$$e=T_{h-1}(\varphi(m)).$$
Eso es exactamente la línea
$$\texttt{eff\_exponent = exponent\_val + phi}.$$
No se está usando como una afirmación universal para exponentes pequeños. Aquí es correcto porque todas las torres que entran en esa rama ya son enormes.
El módulo se factoriza como
$$M=14^8=2^8\cdot 7^8.$$
Para la parte \(2^8\), basta con que
$$E\ge 8$$
para tener
$$2^E\equiv0\pmod{2^8}.$$
Para la parte impar \(7^8\), la base \(2\) es coprima, así que puede reducirse el exponente módulo
$$\varphi(7^8)=6\cdot 7^7.$$
Sumar \(\varphi(m)\) garantiza que el exponente reconstruido siga siendo suficientemente grande para la parte \(2\)-ádica, mientras conserva la información correcta para la parte impar. Como los exponentes reales del problema son muchísimo mayores que \(8\), este levantamiento produce el residuo correcto.
Los residuos
$$2\uparrow\uparrow h \pmod M$$
acaban estabilizándose. Con la recursión implementada por el código, el valor ya deja de cambiar a partir de la altura \(11\).
Eso significa que:
cualquier torre suficientemente alta de base 2 tiene el mismo residuo módulo \(M\).
Ésta es la idea clave que hace manejables \(A(5,5)\) y \(A(6,6)\).
Se tiene
$$A(5,5)+3=2\uparrow\uparrow\uparrow 8,$$
es decir, una tetración cuya altura ya es astronómica. \(A(6,6)+3\) es muchísimo mayor todavía.
Como los residuos de torres módulo \(M\) ya se han estabilizado a alturas modestas, ambos valores caen en la misma clase residual estable. Por eso el código puede reemplazarlos por
$$2\uparrow\uparrow 200 \pmod M$$
como altura sustituta segura. El número \(200\) no tiene nada mágico; simplemente está muy por encima del umbral de estabilización.
La cantidad pedida es
$$S=\sum_{n=0}^{6}A(n,n)\pmod M.$$
La implementación la divide en:
cuatro constantes pequeñas exactas para \(n=0,1,2,3\);
un único término genuino de tetración para \(n=4\), a saber \(2\uparrow\uparrow7-3\);
dos residuos gigantes estabilizados e idénticos para \(n=5\) y \(n=6\).
1) Potencia modular rápida. power() usa exponenciación binaria con multiplicación intermedia de 128 bits.
2) Función totiente. get_phi() factoriza el módulo actual y devuelve \(\varphi(m)\).
3) Recursión de torres. hyper_tower_2(height,m) evalúa \(2\uparrow\uparrow\text{height}\pmod m\) recurriendo al módulo \(\varphi(m)\) y levantando luego el exponente en una totiente.
4) Capas de Ackermann. solve_n0() a solve_n3() devuelven constantes exactas; solve_n4() devuelve el residuo de \(A(4,4)\); solve_large_n() devuelve el residuo estabilizado usado para \(A(5,5)\) y \(A(6,6)\).
5) Suma final. La función principal calcula por separado los siete bloques y los suma módulo \(M\).
Cada exponenciación modular cuesta \(O(\log e)\). La profundidad recursiva queda controlada por la cadena de totientes del módulo, y las alturas efectivas de las torres se reemplazan por casos base pequeños o por una altura sustituta ya estabilizada. Por eso el tiempo es minúsculo comparado con cualquier intento de expandir Ackermann directamente, y la memoria usada es esencialmente constante.
Project Euler 282 要求计算
$$\sum_{n=0}^{6}A(n,n)\pmod{14^8},$$
其中 \(A(m,n)\) 是标准 Ackermann 函数:
$$A(0,n)=n+1,$$
$$A(m,0)=A(m-1,1)\quad(m\ge1),$$
$$A(m,n)=A(m-1,A(m,n-1))\quad(m,n\ge1).$$
模数是
$$M=14^8=1475789056.$$
这里不直接给出最终余数;重点是解释代码为何能在完全不构造巨大 Ackermann 值的前提下得到正确的模结果。
由定义可以推出经典恒等式:
$$A(0,n)=n+1,$$
$$A(1,n)=n+2,$$
$$A(2,n)=2n+3,$$
$$A(3,n)=2^{n+3}-3.$$
因此对角线上前几项立即得到
$$A(0,0)=1,\qquad A(1,1)=3,\qquad A(2,2)=7,\qquad A(3,3)=61.$$
这正是代码中 solve_n0() 到 solve_n3() 返回的常数。
因为
$$A(3,n)=2^{n+3}-3,$$
所以下一层满足
$$A(4,n+1)=A(3,A(4,n))=2^{A(4,n)+3}-3.$$
这正是幂塔递推。用 Knuth 箭号表示,
$$A(4,n)=2\uparrow\uparrow(n+3)-3,$$
其中
$$2\uparrow\uparrow1=2,\qquad 2\uparrow\uparrow(h+1)=2^{\,2\uparrow\uparrow h}.$$
特别地,
$$A(4,4)=2\uparrow\uparrow7-3.$$
因此 solve_n4() 正是在计算
$$\texttt{hyper\_tower\_2(7,M)}-3 \pmod M.$$
这个模式继续向上:
$$A(5,n)=2\uparrow\uparrow\uparrow(n+3)-3,$$
$$A(6,n)=2\uparrow\uparrow\uparrow\uparrow(n+3)-3.$$
因此 \(A(5,5)\) 和 \(A(6,6)\) 已经远远超出任何直接表示范围,唯一合理目标就是它们模 \(M\) 的余数。
hyper_tower_2(h,m) 真正计算的是什么这个辅助函数并不去构造真实的 \(2\uparrow\uparrow h\),而只计算它对 \(m\) 的余数:
$$T_h(m):=2\uparrow\uparrow h \pmod m.$$
对于较小高度,值可直接写出:
$$T_0(m)=1,\qquad T_1(m)=2,\qquad T_2(m)=4,\qquad T_3(m)=16,\qquad T_4(m)=65536,$$
都按模 \(m\) 取值。代码里把这些作为 base case。
当高度很大时,我们要算的是
$$2^E\pmod m,$$
其中 \(E=2\uparrow\uparrow(h-1)\) 本身已经极大。对奇模数时,可以把指数模 \(\varphi(m)\) 约化;但这里底数是 \(2\),不一定总与当前模数互素,所以不能不加说明地直接套用。
代码采用的是常见的“抬高指数”策略:
1. 先在 \(\varphi(m)\) 下递归计算上层指数;
2. 再加上一整圈 totient 周期;
3. 最后对 \(m\) 做快速幂。
形式上就是对巨大幂塔计算
$$2^{\,e+\varphi(m)}\pmod m,$$
其中
$$e=T_{h-1}(\varphi(m)).$$
这正对应代码中的
$$\texttt{eff\_exponent = exponent\_val + phi}.$$
这里并不是把它当成对任意小指数都成立的万能定理来用。它之所以安全,是因为进入这个递归分支的所有幂塔都已经极高。
模数分解为
$$M=14^8=2^8\cdot 7^8.$$
对 \(2^8\) 这一部分,只要指数满足
$$E\ge 8,$$
就已经有
$$2^E\equiv0\pmod{2^8}.$$
而对奇数部分 \(7^8\),底数 \(2\) 与它互素,所以指数可以模
$$\varphi(7^8)=6\cdot 7^7$$
约化。
加上 \(\varphi(m)\) 可以确保重建出的指数对 \(2\)-进部分足够大,同时对奇数部分保留正确的同余信息。由于本题中的真实指数远远大于 \(8\),这种“抬高”与真实幂塔余数一致。
序列
$$2\uparrow\uparrow h \pmod M$$
在高度足够大后会稳定下来。按代码采用的递归方式,到了高度 \(11\) 左右就已经不再变化。
这意味着:
任何足够高的 2 幂塔,在模 \(M\) 下都有同一个余数。
这正是 \(A(5,5)\) 和 \(A(6,6)\) 变得可处理的核心原因。
注意
$$A(5,5)+3=2\uparrow\uparrow\uparrow 8,$$
也就是“高度本身已经天文级别”的 tetration。至于 \(A(6,6)+3\),则更是远大得多。
但由于模 \(M\) 下幂塔余数在较小高度后就稳定,因此这两个值都会落入同一个稳定余数类。于是代码可以把它们都安全地替换成
$$2\uparrow\uparrow 200 \pmod M$$
作为代理高度。这里的 \(200\) 没有特殊数学意义,只是远远超过稳定阈值。
题目要的是
$$S=\sum_{n=0}^{6}A(n,n)\pmod M.$$
实现中把它拆成:
\(n=0,1,2,3\) 的四个小常数;
\(n=4\) 的一个真实 tetration 项,即 \(2\uparrow\uparrow7-3\);
\(n=5\) 与 \(n=6\) 的两个相同稳定大项余数。
这样整个问题就变成了少量模幂塔计算,而不是直接面对 Ackermann 的原始爆炸性增长。
1) 快速幂。 power() 用二进制快速幂和 128 位中间乘法实现模幂计算。
2) Totient 计算。 get_phi() 对当前模数做因子分解并返回 \(\varphi(m)\)。
3) 幂塔递归。 hyper_tower_2(height,m) 通过递归到 \(\varphi(m)\) 并在最后把指数抬高一个 totient 周期,来计算 \(2\uparrow\uparrow\text{height}\pmod m\)。
4) Ackermann 各层。 solve_n0() 到 solve_n3() 返回精确小常数,solve_n4() 返回 \(A(4,4)\) 的模余数,solve_large_n() 返回 \(A(5,5)\) 和 \(A(6,6)\) 共用的稳定余数。
5) 最终求和。 主函数把七个部分分别算出后,在模 \(M\) 下求和。
每次模幂计算的代价是 \(O(\log e)\)。递归深度由模数的 totient 链控制,而幂塔高度要么落在很小的显式基例中,要么被安全地替换成已经稳定的代理高度。因此运行时间极小,内存也基本是常数级,远远优于任何直接展开 Ackermann 的做法。
Project Euler 282 требует вычислить
$$\sum_{n=0}^{6}A(n,n)\pmod{14^8},$$
где \(A(m,n)\) — стандартная функция Аккермана:
$$A(0,n)=n+1,$$
$$A(m,0)=A(m-1,1)\quad(m\ge1),$$
$$A(m,n)=A(m-1,A(m,n-1))\quad(m,n\ge1).$$
Модуль равен
$$M=14^8=1475789056.$$
Окончательный остаток здесь не приводится; цель — объяснить, как программа заменяет чудовищные значения Аккермана несколькими модульными вычислениями башен степеней.
Из определения следуют стандартные тождества
$$A(0,n)=n+1,$$
$$A(1,n)=n+2,$$
$$A(2,n)=2n+3,$$
$$A(3,n)=2^{n+3}-3.$$
Следовательно, по диагонали сразу получаем
$$A(0,0)=1,\qquad A(1,1)=3,\qquad A(2,2)=7,\qquad A(3,3)=61.$$
Именно эти константы возвращают solve_n0()–solve_n3().
Поскольку
$$A(3,n)=2^{n+3}-3,$$
то следующая ступень удовлетворяет
$$A(4,n+1)=A(3,A(4,n))=2^{A(4,n)+3}-3.$$
Это ровно рекурсия башни степеней. В нотации Кнута:
$$A(4,n)=2\uparrow\uparrow(n+3)-3,$$
где
$$2\uparrow\uparrow1=2,\qquad 2\uparrow\uparrow(h+1)=2^{\,2\uparrow\uparrow h}.$$
В частности,
$$A(4,4)=2\uparrow\uparrow7-3.$$
Поэтому solve_n4() считает именно
$$\texttt{hyper\_tower\_2(7,M)}-3 \pmod M.$$
Дальше шаблон продолжается:
$$A(5,n)=2\uparrow\uparrow\uparrow(n+3)-3,$$
$$A(6,n)=2\uparrow\uparrow\uparrow\uparrow(n+3)-3.$$
Поэтому \(A(5,5)\) и \(A(6,6)\) уже настолько велики, что их нельзя даже мысленно “посчитать напрямую”. Реальный объект вычисления — только остаток по модулю \(M\).
hyper_tower_2(h,m)Эта вспомогательная функция не строит настоящий \(2\uparrow\uparrow h\). Она вычисляет только его остаток по модулю \(m\):
$$T_h(m):=2\uparrow\uparrow h \pmod m.$$
Для малых высот значения известны явно:
$$T_0(m)=1,\qquad T_1(m)=2,\qquad T_2(m)=4,\qquad T_3(m)=16,\qquad T_4(m)=65536,$$
все по модулю \(m\). Эти базовые случаи и зашиты в коде.
Для больших высот нужно вычислять
$$2^E\pmod m,$$
где \(E=2\uparrow\uparrow(h-1)\) само по себе огромно. Для нечётных модулей можно сокращать показатель по \(\varphi(m)\). Но здесь основание равно \(2\), так что взаимная простота соблюдается не всегда.
Поэтому программа использует стандартную стратегию “поднятого показателя”:
1. вычислить верхний показатель по модулю \(\varphi(m)\);
2. прибавить один полный тотентный период;
3. возвести в степень по модулю \(m\).
То есть фактически для гигантских башен считается
$$2^{\,e+\varphi(m)}\pmod m,$$
где
$$e=T_{h-1}(\varphi(m)).$$
Это и есть строка
$$\texttt{eff\_exponent = exponent\_val + phi}.$$
Здесь это не используется как универсальная формула для маленьких показателей. Корректность обеспечивается тем, что все башни, попадающие в рекурсивную ветвь, уже чрезвычайно высоки.
Модуль раскладывается как
$$M=14^8=2^8\cdot 7^8.$$
Для части \(2^8\) достаточно, чтобы
$$E\ge 8,$$
тогда
$$2^E\equiv0\pmod{2^8}.$$
Для нечётной части \(7^8\) число \(2\) взаимно просто с модулем, значит показатель можно редуцировать по
$$\varphi(7^8)=6\cdot 7^7.$$
Прибавление \(\varphi(m)\) гарантирует, что восстановленный показатель остаётся “достаточно большим” для двоичной части и одновременно хранит правильную информацию для нечётной части. А в нашей задаче истинные показатели несравнимо больше \(8\).
Последовательность остатков
$$2\uparrow\uparrow h \pmod M$$
при больших \(h\) стабилизируется. Для рекурсии, используемой в коде, это происходит уже примерно с высоты \(11\).
Значит:
любая достаточно высокая башня из двоек имеет один и тот же остаток по модулю \(M\).
Это и позволяет работать с \(A(5,5)\) и \(A(6,6)\).
Имеем
$$A(5,5)+3=2\uparrow\uparrow\uparrow 8,$$
то есть тетрацию, высота которой сама уже астрономична. \(A(6,6)+3\) ещё намного больше.
Но так как остатки башен по модулю \(M\) стабилизируются на малых высотах, оба этих значения попадают в один и тот же стабильный класс остатков. Поэтому код может безопасно подставить вместо них
$$2\uparrow\uparrow 200 \pmod M$$
как суррогатную высоту. Число \(200\) не имеет особого математического смысла — оно просто намного выше порога стабилизации.
Нужно вычислить
$$S=\sum_{n=0}^{6}A(n,n)\pmod M.$$
Программа разбивает это на:
четыре малые точные константы для \(n=0,1,2,3\);
один настоящий тетрационный член для \(n=4\), а именно \(2\uparrow\uparrow7-3\);
два одинаковых стабилизированных огромных члена для \(n=5\) и \(n=6\).
1) Быстрое модульное возведение в степень. power() использует бинарное возведение в степень и 128-битные промежуточные произведения.
2) Вычисление тотента. get_phi() факторизует текущий модуль и возвращает \(\varphi(m)\).
3) Рекурсия башен. hyper_tower_2(height,m) вычисляет \(2\uparrow\uparrow\text{height}\pmod m\), рекурсируя к модулю \(\varphi(m)\) и затем поднимая показатель на одну тотентную длину.
4) Слои Аккермана. solve_n0()–solve_n3() возвращают точные константы; solve_n4() даёт остаток для \(A(4,4)\); solve_large_n() возвращает стабилизированный остаток, используемый и для \(A(5,5)\), и для \(A(6,6)\).
5) Финальная сумма. В main() семь компонент вычисляются отдельно и суммируются по модулю \(M\).
Каждое модульное возведение в степень стоит \(O(\log e)\). Глубина рекурсии ограничена тотентной цепочкой модуля, а реальные высоты башен заменяются либо явными малыми базами, либо безопасной стабилизированной высотой. Поэтому время работы ничтожно по сравнению с невозможной прямой оценкой Аккермана, а память практически постоянна.
تطلب مسألة Project Euler 282 حساب
$$\sum_{n=0}^{6}A(n,n)\pmod{14^8},$$
حيث \(A(m,n)\) هي دالة Ackermann القياسية:
$$A(0,n)=n+1,$$
$$A(m,0)=A(m-1,1)\quad(m\ge1),$$
$$A(m,n)=A(m-1,A(m,n-1))\quad(m,n\ge1).$$
والمودولو هو
$$M=14^8=1475789056.$$
لا نعرض الباقي النهائي هنا؛ المهم هو فهم كيف يحول الكود قيم Ackermann الهائلة إلى عدد قليل من حسابات أبراج الأسس المعيارية.
من التعريف نحصل على الهويات المعروفة
$$A(0,n)=n+1,$$
$$A(1,n)=n+2,$$
$$A(2,n)=2n+3,$$
$$A(3,n)=2^{n+3}-3.$$
ومن ثم تكون القيم القطرية الأولى
$$A(0,0)=1,\qquad A(1,1)=3,\qquad A(2,2)=7,\qquad A(3,3)=61.$$
وهذه هي بالضبط الثوابت التي تعيدها الدوال solve_n0() حتى solve_n3().
بما أن
$$A(3,n)=2^{n+3}-3,$$
فإن المستوى التالي يحقق
$$A(4,n+1)=A(3,A(4,n))=2^{A(4,n)+3}-3.$$
وهذا هو بالضبط تكرار برج قوى. وبترميز Knuth:
$$A(4,n)=2\uparrow\uparrow(n+3)-3,$$
حيث
$$2\uparrow\uparrow1=2,\qquad 2\uparrow\uparrow(h+1)=2^{\,2\uparrow\uparrow h}.$$
وعلى وجه الخصوص
$$A(4,4)=2\uparrow\uparrow7-3.$$
ولهذا تحسب solve_n4() المقدار
$$\texttt{hyper\_tower\_2(7,M)}-3 \pmod M.$$
يستمر النمط على النحو الآتي:
$$A(5,n)=2\uparrow\uparrow\uparrow(n+3)-3,$$
$$A(6,n)=2\uparrow\uparrow\uparrow\uparrow(n+3)-3.$$
إذن \(A(5,5)\) و\(A(6,6)\) ليسا “كبيرين جدًا” فقط، بل خارجين تمامًا عن أي تمثيل مباشر عملي. الشيء المعقول الوحيد هو حساب الباقي modulo \(M\).
hyper_tower_2(h,m) فعلًا؟هذه الدالة لا تبني القيمة الحقيقية لـ \(2\uparrow\uparrow h\)، بل تحسب فقط بقاياها modulo \(m\):
$$T_h(m):=2\uparrow\uparrow h \pmod m.$$
أما الارتفاعات الصغيرة فلها قيم صريحة:
$$T_0(m)=1,\qquad T_1(m)=2,\qquad T_2(m)=4,\qquad T_3(m)=16,\qquad T_4(m)=65536,$$
كل ذلك modulo \(m\). وهذه الحالات الأساسية موجودة صراحة في الكود.
عند الارتفاعات الكبيرة نريد حساب
$$2^E\pmod m,$$
حيث \(E=2\uparrow\uparrow(h-1)\) هائل بدوره. في المودولات الفردية يمكن اختزال الأس modulo \(\varphi(m)\)، لكن هنا الأساس هو \(2\)، وبالتالي لا توجد المرافقة التوافقية دائمًا.
لهذا يستخدم الكود استراتيجية “الأس المرفوع” المعتادة:
1. احسب الأس العلوي modulo \(\varphi(m)\)،
2. أضف دورة totient كاملة،
3. ثم ارفع \(2\) إلى هذا الأس modulo \(m\).
أي أنه يحسب فعليًا، في هذه الأبراج الضخمة،
$$2^{\,e+\varphi(m)}\pmod m,$$
حيث
$$e=T_{h-1}(\varphi(m)).$$
وهذا هو بالضبط ما يفعله السطر
$$\texttt{eff\_exponent = exponent\_val + phi}.$$
ليست هذه حيلة عامة لكل أس صغير. هي صحيحة هنا لأن كل الأبراج التي تصل إلى هذا الفرع التكراري كبيرة جدًا أصلًا.
نفكك المودولو:
$$M=14^8=2^8\cdot 7^8.$$
بالنسبة للجزء \(2^8\)، يكفي أن يكون
$$E\ge 8$$
كي نحصل على
$$2^E\equiv0\pmod{2^8}.$$
أما بالنسبة للجزء الفردي \(7^8\)، فإن \(2\) أولي معه، ولذا يمكن اختزال الأس modulo
$$\varphi(7^8)=6\cdot 7^7.$$
إضافة \(\varphi(m)\) تضمن أن يظل الأس المعاد بناؤه “كبيرًا بما يكفي” للجزء الثنائي، مع الاحتفاظ بالمعلومة الصحيحة للجزء الفردي. وبما أن الأسس الحقيقية في هذه المسألة أكبر بكثير من \(8\)، فإن هذه الرفعة تعطي الباقي الصحيح.
تتثبت المتتالية
$$2\uparrow\uparrow h \pmod M$$
عند ارتفاع كافٍ. وباستخدام التكرار الموجود في الكود، يصل هذا الاستقرار تقريبًا عند الارتفاع \(11\).
أي إن:
كل برج قوى عالٍ بما يكفي للأساس 2 يمتلك الباقي نفسه modulo \(M\).
وهذا هو السبب الحاسم الذي يجعل \(A(5,5)\) و\(A(6,6)\) قابلين للمعالجة.
لدينا
$$A(5,5)+3=2\uparrow\uparrow\uparrow 8,$$
أي tetration يكون ارتفاعها نفسه هائلًا. أما \(A(6,6)+3\) فهو أكبر بكثير من ذلك.
لكن بما أن بقايا الأبراج modulo \(M\) تستقر عند ارتفاع صغير نسبيًا، فإن هاتين القيمتين تسقطان في الفئة المستقرة نفسها. لذلك يستطيع الكود أن يستبدلهما بأمان بـ
$$2\uparrow\uparrow 200 \pmod M$$
كارتفاع بديل. والعدد \(200\) ليس له معنى خاص، بل هو فقط أعلى بكثير من عتبة الاستقرار.
الكمية المطلوبة هي
$$S=\sum_{n=0}^{6}A(n,n)\pmod M.$$
وتفككها الخوارزمية إلى:
أربع ثوابت صغيرة دقيقة لـ \(n=0,1,2,3\)،
وحدّ tetration حقيقي واحد لـ \(n=4\)، أي \(2\uparrow\uparrow7-3\)،
وحدّين هائلين مستقرين ومتماثلين لـ \(n=5\) و\(n=6\).
1) الرفع السريع للأس. تستخدم power() الرفع الثنائي مع نواتج وسيطة 128-بت.
2) حساب \(\varphi\). تقوم get_phi() بتحليل المودولو الحالي وإرجاع \(\varphi(m)\).
3) تكرار الأبراج. تحسب hyper_tower_2(height,m) القيمة \(2\uparrow\uparrow\text{height}\pmod m\) عبر النزول إلى \(\varphi(m)\) ثم رفع الأس بمقدار totient واحد.
4) طبقات Ackermann. تعطي solve_n0() إلى solve_n3() ثوابت دقيقة، وتعيد solve_n4() بقايا \(A(4,4)\)، وتعيد solve_large_n() الباقي المستقر المستخدم لكل من \(A(5,5)\) و\(A(6,6)\).
5) الجمع النهائي. تحسب الدالة الرئيسية المكونات السبع كلًّا على حدة ثم تجمعها modulo \(M\).
كل عملية أس معياري تكلف \(O(\log e)\). ويظل عمق التكرار محدودًا بسلسلة totient الخاصة بالمودولو، بينما تُستبدل الارتفاعات الفعلية للأبراج إما بحالات أساسية صغيرة أو بارتفاع آمن مستقر. لذلك يبقى الزمن صغيرًا جدًا مقارنة بأي محاولة مباشرة لتوليد قيم Ackermann، كما أن الذاكرة تكاد تكون ثابتة.