Miscellaneous stuff - libzahl - big integer library | |
git clone git://git.suckless.org/libzahl | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 16a001c8fe4e5ca99d5aafdd8ed02a35f09b6caa | |
parent c98c0af42f56d0859d6f3f5e3743945906c681c8 | |
Author: Mattias Andrée <[email protected]> | |
Date: Fri, 13 May 2016 04:38:09 +0200 | |
Miscellaneous stuff | |
Signed-off-by: Mattias Andrée <[email protected]> | |
Diffstat: | |
M Makefile | 6 +++++- | |
M TODO | 4 ++++ | |
M doc/arithmetic.tex | 5 +++-- | |
A doc/bit-operations.tex | 56 +++++++++++++++++++++++++++++… | |
M doc/libzahl.tex | 4 ++++ | |
A doc/not-implemented.tex | 554 +++++++++++++++++++++++++++++… | |
A doc/number-theory.tex | 35 +++++++++++++++++++++++++++++… | |
A doc/random-numbers.tex | 28 ++++++++++++++++++++++++++++ | |
M src/zmodmul.c | 1 + | |
M src/zmodpow.c | 2 ++ | |
M src/zmodpowu.c | 5 +++-- | |
M src/zpow.c | 2 ++ | |
M src/zpowu.c | 5 +++-- | |
13 files changed, 700 insertions(+), 7 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
@@ -78,7 +78,11 @@ TEXSRC =\ | |
doc/libzahls-design.tex\ | |
doc/get-started.tex\ | |
doc/miscellaneous.tex\ | |
- doc/arithmetic.tex | |
+ doc/arithmetic.tex\ | |
+ doc/bit-operations.tex\ | |
+ doc/number-theory.tex\ | |
+ doc/random-numbers.tex\ | |
+ doc/not-implemented.tex | |
HDR_PUBLIC = zahl.h $(HDR_SEMIPUBLIC) | |
HDR = $(HDR_PUBLIC) $(HDR_PRIVATE) | |
diff --git a/TODO b/TODO | |
@@ -4,6 +4,10 @@ It uses optimised division algorithm that requires that d|n. | |
Add zsets_radix | |
Add zstr_radix | |
+Can zmodpowu and zmodpow be improved using some other algorithm? | |
+Is it worth implementing precomputed optimal | |
+ addition-chain exponentiation in zpowu? | |
+ | |
Test big endian | |
Test always having .used > 0 for zero | |
Test negative/non-negative instead of sign | |
diff --git a/doc/arithmetic.tex b/doc/arithmetic.tex | |
@@ -186,8 +186,9 @@ can be expressed as a simple formula | |
\vspace{-1em} | |
\[ \hspace*{-0.4cm} | |
- a^b = \prod_{i = 0}^{\lceil \log_2 b \rceil} | |
- \left ( a^{2^i} \right )^{\left \lfloor {\displaystyle{b \over 2^i}} \hspa… | |
+ a^b = | |
+ \prod_{k \in \textbf{Z}_{+} ~:~ \left \lfloor {b \over 2^k} \hspace*{-1ex}… | |
+ a^{2^k} | |
\] | |
\noindent | |
diff --git a/doc/bit-operations.tex b/doc/bit-operations.tex | |
@@ -0,0 +1,56 @@ | |
+\chapter{Bit operations} | |
+\label{chap:Bit operations} | |
+ | |
+TODO | |
+ | |
+\vspace{1cm} | |
+\minitoc | |
+ | |
+ | |
+\newpage | |
+\section{Boundary} | |
+\label{sec:Boundary} | |
+ | |
+TODO % zbits zlsb | |
+ | |
+ | |
+\newpage | |
+\section{Logic} | |
+\label{sec:Logic} | |
+ | |
+TODO % zand zor zxor znot | |
+ | |
+ | |
+\newpage | |
+\section{Shift} | |
+\label{sec:Shift} | |
+ | |
+TODO % zlsh zrsh | |
+ | |
+ | |
+\newpage | |
+\section{Truncation} | |
+\label{sec:Truncation} | |
+ | |
+TODO % ztrunc | |
+ | |
+ | |
+\newpage | |
+\section{Split} | |
+\label{sec:Split} | |
+ | |
+TODO % zsplit | |
+ | |
+ | |
+\newpage | |
+\section{Bit manipulation} | |
+\label{sec:Bit manipulation} | |
+ | |
+TODO % zbset | |
+ | |
+ | |
+\newpage | |
+\section{Bit test} | |
+\label{sec:Bit test} | |
+ | |
+TODO % zbtest | |
diff --git a/doc/libzahl.tex b/doc/libzahl.tex | |
@@ -82,6 +82,10 @@ all copies or substantial portions of the Document. | |
\input doc/get-started.tex | |
\input doc/miscellaneous.tex | |
\input doc/arithmetic.tex | |
+\input doc/bit-operations.tex | |
+\input doc/number-theory.tex | |
+\input doc/random-numbers.tex | |
+\input doc/not-implemented.tex | |
\appendix | |
diff --git a/doc/not-implemented.tex b/doc/not-implemented.tex | |
@@ -0,0 +1,554 @@ | |
+\chapter{Not implemented} | |
+\label{chap:Not implemented} | |
+ | |
+In this chapter we maintain a list of | |
+features we have choosen not to implement, | |
+but would fit into libzahl had we not have | |
+our priorities straight. Functions listed | |
+herein will only be implemented if there | |
+is shown that it would be overwhelmingly | |
+advantageous. | |
+ | |
+\vspace{1cm} | |
+\minitoc | |
+ | |
+ | |
+\newpage | |
+\section{Extended greatest common divisor} | |
+\label{sec:Extended greatest common divisor} | |
+ | |
+\begin{alltt} | |
+void | |
+extgcd(z_t bézout_coeff_1, z_t bézout_coeff_2, z_t gcd | |
+ z_t quotient_1, z_t quotient_2, z_t a, z_t b) | |
+\{ | |
+#define old_r gcd | |
+#define old_s bézout_coeff_1 | |
+#define old_t bézout_coeff_2 | |
+#define s quotient_2 | |
+#define t quotient_1 | |
+ z_t r, q, qs, qt; | |
+ int odd = 0; | |
+ zinit(r), zinit(q), zinit(qs), zinit(qt); | |
+ zset(r, b), zset(old_r, a); | |
+ zseti(s, 0), zseti(old_s, 1); | |
+ zseti(t, 1), zseti(old_t, 0); | |
+ while (!zzero(r)) \{ | |
+ odd ^= 1; | |
+ zdivmod(q, old_r, old_r, r), zswap(old_r, r); | |
+ zmul(qs, q, s), zsub(old_s, old_s, qs); | |
+ zmul(qt, q, t), zsub(old_t, old_t, qt); | |
+ zswap(old_s, s), zswap(old_t, t); | |
+ \} | |
+ odd ? abs(s, s) : abs(t, t); | |
+ zfree(r), zfree(q), zfree(qs), zfree(qt); | |
+\} | |
+\end{alltt} | |
+ | |
+ | |
+\newpage | |
+\section{Least common multiple} | |
+\label{sec:Least common multiple} | |
+ | |
+\( \displaystyle{ | |
+ \mbox{lcm}(a, b) = {\lvert a \cdot b \rvert \over \mbox{gcd}(a, b)} | |
+}\) | |
+ | |
+ | |
+\newpage | |
+\section{Modular multiplicative inverse} | |
+\label{sec:Modular multiplicative inverse} | |
+ | |
+\begin{alltt} | |
+int | |
+modinv(z_t inv, z_t a, z_t m) | |
+\{ | |
+ z_t x, _1, _2, _3, gcd, mabs, apos; | |
+ int invertible, aneg = zsignum(a) < 0; | |
+ zinit(x), zinit(_1), zinit(_2), zinit(_3), zinit(gcd); | |
+ *mabs = *m; | |
+ zabs(mabs, mabs); | |
+ if (aneg) \{ | |
+ zinit(apos); | |
+ zset(apos, a); | |
+ if (zcmpmag(apos, mabs)) | |
+ zmod(apos, apos, mabs); | |
+ zadd(apos, mabs, apos); | |
+ \} | |
+ extgcd(inv, _1, _2, _3, gcd, apos, mabs); | |
+ if ((invertible = !zcmpi(gcd, 1))) \{ | |
+ if (zsignum(inv) < 0) | |
+ (zsignum(m) < 0 ? zsub : zadd)(x, x, m); | |
+ zswap(x, inv); | |
+ \} | |
+ if (aneg) | |
+ zfree(apos); | |
+ zfree(x), zfree(_1), zfree(_2), zfree(_3), zfree(gcd); | |
+ return invertible; | |
+\} | |
+\end{alltt} | |
+ | |
+ | |
+\newpage | |
+\section{Random prime number generation} | |
+\label{sec:Random prime number generation} | |
+ | |
+TODO | |
+ | |
+ | |
+\newpage | |
+\section{Symbols} | |
+\label{sec:Symbols} | |
+ | |
+\subsection{Legendre symbol} | |
+\label{sec:Legendre symbol} | |
+ | |
+TODO | |
+ | |
+ | |
+\subsection{Jacobi symbol} | |
+\label{sec:Jacobi symbol} | |
+ | |
+TODO | |
+ | |
+ | |
+\subsection{Kronecker symbol} | |
+\label{sec:Kronecker symbol} | |
+ | |
+TODO | |
+ | |
+ | |
+\subsection{Power residue symbol} | |
+\label{sec:Power residue symbol} | |
+ | |
+TODO | |
+ | |
+ | |
+\subsection{Pochhammer \emph{k}-symbol} | |
+\label{sec:Pochhammer k-symbol} | |
+ | |
+\( \displaystyle{ | |
+ (x)_{n,k} = \prod_{i = 1}^n (x + (i - 1)k) | |
+}\) | |
+ | |
+ | |
+\newpage | |
+\section{Logarithm} | |
+\label{sec:Logarithm} | |
+ | |
+TODO | |
+ | |
+ | |
+\newpage | |
+\section{Roots} | |
+\label{sec:Roots} | |
+ | |
+TODO | |
+ | |
+ | |
+\newpage | |
+\section{Modular roots} | |
+\label{sec:Modular roots} | |
+ | |
+TODO % Square: Cipolla's algorithm, Pocklington's algorithm, Tonelli–Shanks … | |
+ | |
+ | |
+\newpage | |
+\section{Combinatorial} | |
+\label{sec:Combinatorial} | |
+ | |
+\subsection{Factorial} | |
+\label{sec:Factorial} | |
+ | |
+\( \displaystyle{ | |
+ n! = \left \lbrace \begin{array}{ll} | |
+ \displaystyle{\prod_{i = 0}^n i} & \textrm{if}~ n \ge 0 \\ | |
+ \textrm{undefined} & \textrm{otherwise} | |
+ \end{array} \right . | |
+}\) | |
+\vspace{1em} | |
+ | |
+This can be implemented much more efficently | |
+than using the naïve method, and is a very | |
+important function for many combinatorial | |
+applications, therefore it may be implemented | |
+in the future if the demand is high enough. | |
+ | |
+ | |
+\subsection{Subfactorial} | |
+\label{sec:Subfactorial} | |
+ | |
+\( \displaystyle{ | |
+ !n = \left \lbrace \begin{array}{ll} | |
+ n(!(n - 1)) + (-1)^n & \textrm{if}~ n > 0 \\ | |
+ 1 & \textrm{if}~ n = 0 \\ | |
+ \textrm{undefined} & \textrm{otherwise} | |
+ \end{array} \right . = | |
+ n! \sum_{i = 0}^n {(-1)^i \over i!} | |
+}\) | |
+ | |
+ | |
+\subsection{Alternating factorial} | |
+\label{sec:Alternating factorial} | |
+ | |
+\( \displaystyle{ | |
+ \mbox{af}(n) = \sum_{i = 1}^n {(-1)^{n - i} i!} | |
+}\) | |
+ | |
+ | |
+\subsection{Multifactorial} | |
+\label{sec:Multifactorial} | |
+ | |
+\( \displaystyle{ | |
+ n!^{(k)} = \left \lbrace \begin{array}{ll} | |
+ 1 & \textrm{if}~ n = 0 \\ | |
+ n & \textrm{if}~ 0 < n \le k \\ | |
+ n((n - k)!^{(k)}) & \textrm{if}~ n > k \\ | |
+ \textrm{undefined} & \textrm{otherwise} | |
+ \end{array} \right . | |
+}\) | |
+ | |
+ | |
+\subsection{Quadruple factorial} | |
+\label{sec:Quadruple factorial} | |
+ | |
+\( \displaystyle{ | |
+ (4n - 2)!^{(4)} | |
+}\) | |
+ | |
+ | |
+\subsection{Superfactorial} | |
+\label{sec:Superfactorial} | |
+ | |
+\( \displaystyle{ | |
+ \mbox{sf}(n) = \prod_{k = 1}^n k^{1 + n - k} | |
+}\), undefined for $n < 0$. | |
+ | |
+ | |
+\subsection{Hyperfactorial} | |
+\label{sec:Hyperfactorial} | |
+ | |
+\( \displaystyle{ | |
+ H(n) = \prod_{k = 1}^n k^k | |
+}\), undefined for $n < 0$. | |
+ | |
+ | |
+\subsection{Raising factorial} | |
+\label{sec:Raising factorial} | |
+ | |
+\( \displaystyle{ | |
+ x^{(n)} = {(x + n - 1)! \over (x - 1)!} | |
+}\), undefined for $n < 0$. | |
+ | |
+ | |
+\subsection{Failing factorial} | |
+\label{sec:Failing factorial} | |
+ | |
+\( \displaystyle{ | |
+ (x)_n = {x! \over (x - n)!} | |
+}\), undefined for $n < 0$. | |
+ | |
+ | |
+\subsection{Primorial} | |
+\label{sec:Primorial} | |
+ | |
+\( \displaystyle{ | |
+ n\# = \prod_{\lbrace i \in \textbf{P} ~:~ i \le n \rbrace} i | |
+}\) | |
+\vspace{1em} | |
+ | |
+\noindent | |
+\( \displaystyle{ | |
+ p_n\# = \prod_{i \in \textbf{P}_{\pi(n)}} i | |
+}\) | |
+ | |
+ | |
+\subsection{Gamma function} | |
+\label{sec:Gamma function} | |
+ | |
+$\Gamma(n) = (n - 1)!$, undefined for $n \le 0$. | |
+ | |
+ | |
+\subsection{K-function} | |
+\label{sec:K-function} | |
+ | |
+\( \displaystyle{ | |
+ K(n) = \left \lbrace \begin{array}{ll} | |
+ \displaystyle{\prod_{i = 1}^{n - 1} i^i} & \textrm{if}~ n \ge 0 \\ | |
+ 1 & \textrm{if}~ n = -1 \\ | |
+ 0 & \textrm{otherwise (result is truncated)} | |
+ \end{array} \right . | |
+}\) | |
+ | |
+ | |
+\subsection{Binomial coefficient} | |
+\label{sec:Binomial coefficient} | |
+ | |
+\( \displaystyle{ | |
+ {n \choose k} = {n! \over k!(n - k)!} | |
+ = {1 \over (n - k)!} \prod_{i = k + 1}^n i | |
+ = {1 \over k!} \prod_{i = n - k + 1}^n i | |
+}\) | |
+ | |
+ | |
+\subsection{Catalan number} | |
+\label{sec:Catalan number} | |
+ | |
+\( \displaystyle{ | |
+ C_n = \left . {2n \choose n} \middle / (n + 1) \right . | |
+}\) | |
+ | |
+ | |
+\subsection{Fuss–Catalan number} | |
+\label{sec:Fuss-Catalan number} % not en dash | |
+ | |
+\( \displaystyle{ | |
+ A_m(p, r) = {r \over mp + r} {mp + r \choose m} | |
+}\) | |
+ | |
+ | |
+\newpage | |
+\section{Fibonacci numbers} | |
+\label{sec:Fibonacci numbers} | |
+ | |
+Fibonacci numbers can be computed efficiently | |
+using the following algorithm: | |
+ | |
+\begin{alltt} | |
+ static void | |
+ fib_ll(z_t f, z_t g, z_t n) | |
+ \{ | |
+ z_t a, k; | |
+ int odd; | |
+ if (zcmpi(n, 1) <= 1) \{ | |
+ zseti(f, !zzero(n)); | |
+ zseti(f, zzero(n)); | |
+ return; | |
+ \} | |
+ zinit(a), zinit(k); | |
+ zrsh(k, n, 1); | |
+ if (zodd(n)) \{ | |
+ odd = zodd(k); | |
+ fib_ll(a, g, k); | |
+ zadd(f, a, a); | |
+ zadd(k, f, g); | |
+ zsub(f, f, g); | |
+ zmul(f, f, k); | |
+ zseti(k, odd ? -2 : +2); | |
+ zadd(f, f, k); | |
+ zadd(g, g, g); | |
+ zadd(g, g, a); | |
+ zmul(g, g, a); | |
+ \} else \{ | |
+ fib_ll(g, a, k); | |
+ zadd(f, a, a); | |
+ zadd(f, f, g); | |
+ zmul(f, f, g); | |
+ zsqr(a, a); | |
+ zsqr(g, g); | |
+ zadd(g, a); | |
+ \} | |
+ zfree(k), zfree(a); | |
+ \} | |
+ | |
+ void | |
+ fib(z_t f, z_t n) | |
+ \{ | |
+ z_t tmp, k; | |
+ zinit(tmp), zinit(k); | |
+ zset(k, n); | |
+ fib_ll(f, tmp, k); | |
+ zfree(k), zfree(tmp); | |
+ \} | |
+\end{alltt} | |
+ | |
+\noindent | |
+This algorithm is based on the rules | |
+ | |
+\vspace{1em} | |
+\( \displaystyle{ | |
+ F_{2k + 1} = 4F_k^2 - F_{k - 1}^2 + 2(-1)^k = (2F_k + F_{k-1})(2F_k - F_{k… | |
+}\) | |
+\vspace{1em} | |
+ | |
+\( \displaystyle{ | |
+ F_{2k} = F_k \cdot (F_k + 2F_{k - 1}) | |
+}\) | |
+\vspace{1em} | |
+ | |
+\( \displaystyle{ | |
+ F_{2k - 1} = F_k^2 + F_{k - 1}^2 | |
+}\) | |
+\vspace{1em} | |
+ | |
+\noindent | |
+Each call to {\tt fib\_ll} returns $F_n$ and $F_{n - 1}$ | |
+for any input $n$. $F_{k}$ is only correctly returned | |
+for $k \ge 0$. $F_n$ and $F_{n - 1}$ is used for | |
+calculating $F_{2n}$ or $F_{2n + 1}$. The algorithm | |
+can be speed up with a larger lookup table than one | |
+covering just the base cases. Alternatively, a naïve | |
+calculation could be used for sufficiently small input. | |
+ | |
+ | |
+\newpage | |
+\section{Lucas numbers} | |
+\label{sec:Lucas numbers} | |
+ | |
+Lucas numbers can be calculated by utilising | |
+{\tt fib\_ll} from \secref{sec:Fibonacci numbers}: | |
+ | |
+\begin{alltt} | |
+ void | |
+ lucas(z_t l, z_t n) | |
+ \{ | |
+ z_t k; | |
+ int odd; | |
+ if (zcmp(n, 1) <= 0) \{ | |
+ zset(l, 1 + zzero(n)); | |
+ return; | |
+ \} | |
+ zinit(k); | |
+ zrsh(k, n, 1); | |
+ if (zeven(n)) \{ | |
+ lucas(l, k); | |
+ zsqr(l, l); | |
+ zseti(k, zodd(k) ? +2 : -2); | |
+ zadd(l, k); | |
+ \} else \{ | |
+ odd = zodd(k); | |
+ fib_ll(l, k, k); | |
+ zadd(l, l, l); | |
+ zadd(l, l, k); | |
+ zmul(l, l, k); | |
+ zseti(k, 5); | |
+ zmul(l, l, k); | |
+ zseti(k, odd ? +4 : -4); | |
+ zadd(l, l, k); | |
+ \} | |
+ zfree(k); | |
+ \} | |
+\end{alltt} | |
+ | |
+\noindent | |
+This algorithm is based on the rules | |
+ | |
+\vspace{1em} | |
+\( \displaystyle{ | |
+ L_{2k} = L_k^2 - 2(-1)^k | |
+}\) | |
+\vspace{1ex} | |
+ | |
+\( \displaystyle{ | |
+ L_{2k + 1} = 5F_{k - 1} \cdot (2F_k + F_{k - 1}) - 4(-1)^k | |
+}\) | |
+\vspace{1em} | |
+ | |
+\noindent | |
+Alternatively, the function can be implemented | |
+trivially using the rule | |
+ | |
+\vspace{1em} | |
+\( \displaystyle{ | |
+ L_k = F_k + 2F_{k - 1} | |
+}\) | |
+ | |
+ | |
+\newpage | |
+\section{Bit operation} | |
+\label{sec:Bit operation unimplemented} | |
+ | |
+\subsection{Bit scanning} | |
+\label{sec:Bit scanning} | |
+ | |
+Scanning for the next set or unset bit can be | |
+trivially implemented using {\tt zbtest}. A | |
+more efficient, although not optimally efficient, | |
+implementation would be | |
+ | |
+\begin{alltt} | |
+ size_t | |
+ bscan(z_t a, size_t whence, int direction, int value) | |
+ \{ | |
+ size_t ret; | |
+ z_t t; | |
+ zinit(t); | |
+ value ? zset(t, a) : znot(t, a); | |
+ ret = direction < 0 | |
+ ? (ztrunc(t, t, whence + 1), zbits(t) - 1) | |
+ : (zrsh(t, t, whence), zlsb(t) + whence); | |
+ zfree(t); | |
+ return ret; | |
+ \} | |
+\end{alltt} | |
+ | |
+ | |
+\subsection{Population count} | |
+\label{sec:Population count} | |
+ | |
+The following function can be used to compute | |
+the population count, the number of set bits, | |
+in an integer, counting the sign bit: | |
+ | |
+\begin{alltt} | |
+ size_t | |
+ popcount(z_t a) | |
+ \{ | |
+ size_t i, ret = zsignum(a) < 0; | |
+ for (i = 0; i < a->used; i++) \{ | |
+ ret += __builtin_popcountll(a->chars[i]); | |
+ \} | |
+ return ret; | |
+ \} | |
+\end{alltt} | |
+ | |
+\noindent | |
+It requires a compiler extension, if missing, | |
+there are other ways to computer the population | |
+count for a word: manually bit-by-bit, or with | |
+a fully unrolled | |
+ | |
+\begin{alltt} | |
+ int s; | |
+ for (s = 1; s < 64; s <<= 1) | |
+ w = (w >> s) + w; | |
+\end{alltt} | |
+ | |
+ | |
+\subsection{Hamming distance} | |
+\label{sec:Hamming distance} | |
+ | |
+A simple way to compute the Hamming distance, | |
+the number of differing bits, between two number | |
+is with the function | |
+ | |
+\begin{alltt} | |
+ size_t | |
+ hammdist(z_t a, z_t b) | |
+ \{ | |
+ size_t ret; | |
+ z_t t; | |
+ zinit(t); | |
+ zxor(t, a, b); | |
+ ret = popcount(t); | |
+ zfree(t); | |
+ return ret; | |
+ \} | |
+\end{alltt} | |
+ | |
+\noindent | |
+The performance of this function could | |
+be improve by comparing character by | |
+character manually with using {\tt zxor}. | |
+ | |
+ | |
+\subsection{Character retrieval} | |
+\label{sec:Character retrieval} | |
+ | |
+\begin{alltt} | |
+ uint64_t | |
+ getu(z_t a) | |
+ \{ | |
+ return zzero(a) ? 0 : a->chars[0]; | |
+ \} | |
+\end{alltt} | |
diff --git a/doc/number-theory.tex b/doc/number-theory.tex | |
@@ -0,0 +1,35 @@ | |
+\chapter{Number theory} | |
+\label{chap:Number theory} | |
+ | |
+TODO | |
+ | |
+\vspace{1cm} | |
+\minitoc | |
+ | |
+ | |
+\newpage | |
+\section{Odd or even} | |
+\label{sec:Odd or even} | |
+ | |
+TODO % zodd zeven zodd_nonzero zeven_nonzero | |
+ | |
+ | |
+\newpage | |
+\section{Signum} | |
+\label{sec:Signum} | |
+ | |
+TODO % zsignum zzero | |
+ | |
+ | |
+\newpage | |
+\section{Greatest common divisor} | |
+\label{sec:Greatest common divisor} | |
+ | |
+TODO % zgcd | |
+ | |
+ | |
+\newpage | |
+\section{Primality test} | |
+\label{sec:Primality test} | |
+ | |
+TODO % zptest | |
diff --git a/doc/random-numbers.tex b/doc/random-numbers.tex | |
@@ -0,0 +1,28 @@ | |
+\chapter{Random numbers} | |
+\label{chap:Random numbers} | |
+ | |
+TODO | |
+ | |
+\vspace{1cm} | |
+\minitoc | |
+ | |
+ | |
+\newpage | |
+\section{Generation} | |
+\label{sec:Generation} | |
+ | |
+TODO | |
+ | |
+ | |
+\newpage | |
+\section{Devices} | |
+\label{sec:Devices} | |
+ | |
+TODO | |
+ | |
+ | |
+\newpage | |
+\section{Distributions} | |
+\label{sec:Distributions} | |
+ | |
+TODO | |
diff --git a/src/zmodmul.c b/src/zmodmul.c | |
@@ -6,6 +6,7 @@ void | |
zmodmul(z_t a, z_t b, z_t c, z_t d) | |
{ | |
/* TODO Montgomery modular multiplication */ | |
+ /* TODO Kochanski multiplication */ | |
if (unlikely(a == d)) { | |
zset(libzahl_tmp_modmul, d); | |
zmul(a, b, c); | |
diff --git a/src/zmodpow.c b/src/zmodpow.c | |
@@ -12,6 +12,8 @@ zmodpow(z_t a, z_t b, z_t c, z_t d) | |
size_t i, j, n, bits; | |
zahl_char_t x; | |
+ /* TODO use zmodpowu when possible */ | |
+ | |
if (unlikely(zsignum(c) <= 0)) { | |
if (zzero(c)) { | |
if (check(zzero(b))) | |
diff --git a/src/zmodpowu.c b/src/zmodpowu.c | |
@@ -25,10 +25,11 @@ zmodpowu(z_t a, z_t b, unsigned long long int c, z_t d) | |
zmod(tb, b, d); | |
zset(td, d); | |
- zsetu(a, 1); | |
if (c & 1) | |
- zmodmul(a, a, tb, td); | |
+ zset(a, tb); | |
+ else | |
+ zsetu(a, 1); | |
while (c >>= 1) { | |
zmodsqr(tb, tb, td); | |
if (c & 1) | |
diff --git a/src/zpow.c b/src/zpow.c | |
@@ -14,6 +14,8 @@ zpow(z_t a, z_t b, z_t c) | |
* 7↑19 = 7↑10011₂ = 7↑2⁰ ⋅ 7↑2¹ ⋅ 7↑2⁴ where a�… | |
*/ | |
+ /* TODO use zpowu when possible */ | |
+ | |
size_t i, j, n, bits; | |
zahl_char_t x; | |
int neg; | |
diff --git a/src/zpowu.c b/src/zpowu.c | |
@@ -21,10 +21,11 @@ zpowu(z_t a, z_t b, unsigned long long int c) | |
neg = znegative(b) && (c & 1); | |
zabs(tb, b); | |
- zsetu(a, 1); | |
if (c & 1) | |
- zmul_ll(a, a, tb); | |
+ zset(a, tb); | |
+ else | |
+ zsetu(a, 1); | |
while (c >>= 1) { | |
zsqr_ll(tb, tb); | |
if (c & 1) |