libzahl

big integer library
git clone git://git.suckless.org/libzahl
Log | Files | Refs | README | LICENSE

commit f9fac01b221cd41af5352d95a45ba43b47460a41
parent c9c9a5b8fe7cdde58d2e3b6b21332c4cbd32b9b3
Author: Mattias Andrée <maandree@kth.se>
Date:   Fri, 29 Jul 2016 12:34:29 +0200

Add exercise: [HMP32] Modular tetration

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
Mdoc/exercises.tex | 130++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 126 insertions(+), 4 deletions(-)

diff --git a/doc/exercises.tex b/doc/exercises.tex @@ -232,7 +232,7 @@ rather than -\item {[$\RHD$M15]} \textbf{Modular left-shift} +\item {[\textit{$\RHD$M15}]} \textbf{Modular left-shift} Implement a function that calculates $2^a \text{ mod } b$, using \texttt{zmod} and @@ -242,7 +242,7 @@ parameters are unique pointers. -\item {[$\RHD$08]} \textbf{Modular left-shift, extended} +\item {[\textit{$\RHD$08}]} \textbf{Modular left-shift, extended} {\small\textit{You should already have solved ``Modular left-shift'' before you solve this @@ -253,7 +253,7 @@ to accept negative $b$ and non-unique pointers. -\item {[13]} \textbf{The totient} +\item {[\textit{13}]} \textbf{The totient} The totient of $n$ is the number of integer $a$, $0 < a < n$ that are relatively prime to $n$. @@ -271,6 +271,25 @@ and $\varphi(1) = 1$. +\item {[\textit{HMP32}]} \textbf{Modular tetration} + +Implement the function + +\vspace{-1em} +\begin{alltt} + void modtetra(z_t r, z_t b, unsigned long n, z_t m); +\end{alltt} +\vspace{-1em} + +\noindent +which calculates $r = {}^n{}b \text{ mod } m$, where +${}^0{}b = 1$, ${}^1{}b = b$, ${}^2{}b = b^b$, +${}^3{}b = b^{b^b}$, ${}^b{}b = b^{b^{b^b}}$, and so on. +You can assume $b > 0$ and $m > 0$. You can also assume +\texttt{r}, \texttt{b}, and \texttt{m} are mutually +unique pointers. + + \end{enumerate} @@ -621,7 +640,8 @@ need to evaluate $2^{2^{64}}$. \vspace{-1em} \begin{alltt} -void modlsh(z_t r, z_t a, z_t b) +void +modlsh(z_t r, z_t a, z_t b) \{ z_t t, at; size_t s = zbits(b); @@ -679,5 +699,107 @@ then, $\varphi(n) = \varphi|n|$. +\item \textbf{Modular tetration} + +Let \texttt{totient} be Euler's totient function. +It is described in the problem ``The totient''. + +We need two help function: \texttt{tetra(r, b, n)} +which calculated $r = {}^n{}b$, and \texttt{cmp\_tetra(a, b, n)} +which is compares $a$ to ${}^n{}b$. + +\vspace{-1em} +\begin{alltt} +void +tetra(z_t r, z_t b, unsigned long n) +\{ + zsetu(r, 1); + while (n--) + pow(r, b, r); +\} +\end{alltt} +\vspace{-1em} + +\vspace{-1em} +\begin{alltt} +int +cmp_tetra(z_t a, z_t b, unsigned long n) +\{ + z_t B; + int cmp; + + if (!n || !zcmpu(b, 1)) + return zcmpu(a, 1); + if (n == 1) + return zcmp(a, b); + if (zcmp(a, b) >= 0) + return +1; + + zinit(B); + zsetu(B, 1); + while (n) \{ + zpow(B, b, B); + if (zcmp(a, B) < 0) \{ + zfree(B); + return -1; + \} + \} + cmp = zcmp(a, B); + zfree(B); + return cmp; + +\} +\end{alltt} +\vspace{-1em} + +\texttt{tetra} can generate unmaintainably huge +numbers. Will however only call \texttt{tetra} +when this is not the case. + +\vspace{-1em} +\begin{alltt} +void +modtetra(z_t r, z_t b, unsigned long n, z_t m) +\{ + z_t t, temp; + + if (n <= 1) \{ + if (n) + zsetu(r, zcmpu(m, 1)); + else + zmod(r, b, m); + return; + \} + + zmod(r, b, m); + if (zcmpu(r, 1) <= 0) + return; + + zinit(t); + zinit(temp); + + t = totient(m); + zgcd(temp, b, m); + + if (!zcmpu(temp, 1)) \{ + modtetra(temp, b, n - 1, t); + zmodpow(r, r, temp, m); + \} else if (cmp_tetra(t, b, n - 1) > 0) \{ + temp = tetra(b, n - 1); + zpowmod(r, r, temp, m); + \} else \{ + modtetra(temp, b, n - 1, t); + zmodpow(temp, r, temp, m); + zmodpow(r, r, t, m); + zmodmul(r, r, temp, m); + \} + + zfree(temp); + zfree(t); +\} +\end{alltt} +\vspace{-1em} + + \end{enumerate}