├── .gitignore ├── INSTALL ├── LICENSE ├── Makefile ├── README ├── STATUS ├── TODO ├── bench ├── benchmark-func.c ├── benchmark-zrand.c ├── benchmark.c ├── libgmp.h ├── libhebimath.h ├── libtfm.h ├── libtommath.h ├── merge-benchmark-func.py ├── merge-benchmark.py ├── plot.py ├── util.c └── util.h ├── config.mk ├── doc ├── arithmetic.tex ├── bit-operations.tex ├── exercises.tex ├── get-started.tex ├── libzahl.tex ├── libzahls-design.tex ├── miscellaneous.tex ├── not-implemented.tex ├── number-theory.tex ├── random-numbers.tex ├── refsheet.tex └── what-is-libzahl.tex ├── examples ├── 01-sum.c ├── 02-prod.c ├── 03-avg.c └── 04-median.c ├── man ├── libzahl.7 ├── zabs.3 ├── zadd.3 ├── zand.3 ├── zbits.3 ├── zbset.3 ├── zbtest.3 ├── zcmp.3 ├── zcmpi.3 ├── zcmpmag.3 ├── zcmpu.3 ├── zdiv.3 ├── zdivmod.3 ├── zerror.3 ├── zeven.3 ├── zeven_nonzero.3 ├── zfree.3 ├── zgcd.3 ├── zinit.3 ├── zload.3 ├── zlsb.3 ├── zlsh.3 ├── zmod.3 ├── zmodmul.3 ├── zmodpow.3 ├── zmodpowu.3 ├── zmodsqr.3 ├── zmul.3 ├── zneg.3 ├── znot.3 ├── zodd.3 ├── zodd_nonzero.3 ├── zor.3 ├── zperror.3 ├── zpow.3 ├── zpowu.3 ├── zptest.3 ├── zrand.3 ├── zrsh.3 ├── zsave.3 ├── zset.3 ├── zseti.3 ├── zsets.3 ├── zsetu.3 ├── zsetup.3 ├── zsignum.3 ├── zsplit.3 ├── zsqr.3 ├── zstr.3 ├── zstr_length.3 ├── zsub.3 ├── zswap.3 ├── ztrunc.3 ├── zunsetup.3 ├── zxor.3 └── zzero.3 ├── src ├── allocator.c ├── internals.h ├── zadd.c ├── zand.c ├── zbset.c ├── zdivmod.c ├── zerror.c ├── zfree.c ├── zgcd.c ├── zload.c ├── zlsh.c ├── zmodmul.c ├── zmodpow.c ├── zmodpowu.c ├── zmodsqr.c ├── zmul.c ├── znot.c ├── zor.c ├── zperror.c ├── zpow.c ├── zpowu.c ├── zptest.c ├── zrand.c ├── zrsh.c ├── zsets.c ├── zsetup.c ├── zsqr.c ├── zstr.c ├── zstr_length.c ├── zsub.c ├── ztrunc.c ├── zunsetup.c └── zxor.c ├── test-generate.py ├── test.c ├── zahl.h └── zahl ├── inlines.h ├── internals.h └── memory.h /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | \#*\# 3 | .\#* 4 | *.swo 5 | *.swp 6 | *.orig 7 | *.bak 8 | *.o 9 | *.su 10 | *.a 11 | *.so 12 | /test 13 | /test-random.c 14 | /benchmark 15 | /benchmark-zrand 16 | /benchmark-func 17 | *.aux 18 | *.log 19 | *.out 20 | *.pdf 21 | *.ps 22 | *.dvi 23 | *.idx 24 | *.maf 25 | *.mtc* 26 | *.toc 27 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Configure libzahl 2 | ================= 3 | 4 | libzahl is configured by editing config.mk. You may choose 5 | to make a copy of config.mk, and reference the copy with 6 | CONFIG when running make. For example: 7 | cp config.mk my-config.mk 8 | # edit my-config.mk 9 | make CONFIG=my-config.mk 10 | 11 | Unless you are compiling for Linux you may have to add 12 | -D'FAST_RANDOM_PATHNAME=""' 13 | (/dev/urandom on Linux) and 14 | -D'SECURE_RANDOM_PATHNAME=""' 15 | (/dev/random on Linux) to CPPFLAGS. 16 | 17 | If you are using a C standard library where the higher bits have higher 18 | entropy in the lower bits in rand(3) (as historically was the case), 19 | remove -DGOOD_RAND from CPPFLAGS. 20 | 21 | If you don't care if your program crashes on failure, you can add 22 | -DZAHL_UNSAFE to CPPFLAGS. This will give you a marginal performance 23 | boost. You should also add, preferably, 24 | #define ZAHL_UNSAFE 25 | before including in your program if you are doing this. 26 | 27 | If your CPU does not support indirect jumps (computed jumps) you should 28 | add -DZAHL_ISA_MISSING_INDIRECT_JUMP to CPPFLAGS, and preferably add 29 | #define ZAHL_ISA_MISSING_INDIRECT_JUMP 30 | before including in your program. 31 | 32 | libzahl contains some (very little) assembly code. In the event 33 | that the used instructions are not supported on your machine, please 34 | report it, and in the meanwhile add -DZAHL_NO_ASM to CPPFLAGS. You 35 | may also have to do this if you are compiling with a compiler that 36 | does not support extended inline assembly. You may also have to add 37 | #define ZAHL_NO_ASM 38 | to your program before includeing 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | © 2016 Mattias Andrée 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CONFIG = config.mk 2 | include $(CONFIG) 3 | 4 | HDR_SEMIPUBLIC =\ 5 | zahl/inlines.h\ 6 | zahl/internals.h\ 7 | zahl/memory.h 8 | 9 | HDR_PRIVATE =\ 10 | src/internals.h 11 | 12 | FUN =\ 13 | zadd\ 14 | zand\ 15 | zbset\ 16 | zdivmod\ 17 | zerror\ 18 | zfree\ 19 | zgcd\ 20 | zload\ 21 | zlsh\ 22 | zmodmul\ 23 | zmodpow\ 24 | zmodpowu\ 25 | zmodsqr\ 26 | zmul\ 27 | znot\ 28 | zor\ 29 | zperror\ 30 | zpow\ 31 | zpowu\ 32 | zptest\ 33 | zrand\ 34 | zrsh\ 35 | zsets\ 36 | zsetup\ 37 | zsqr\ 38 | zstr\ 39 | zstr_length\ 40 | zsub\ 41 | ztrunc\ 42 | zunsetup\ 43 | zxor 44 | 45 | INLINE_FUN =\ 46 | zabs\ 47 | zbits\ 48 | zbtest\ 49 | zcmp\ 50 | zcmpi\ 51 | zcmpmag\ 52 | zcmpu\ 53 | zdiv\ 54 | zeven\ 55 | zeven_nonzero\ 56 | zinit\ 57 | zlsb\ 58 | zmod\ 59 | zneg\ 60 | zodd\ 61 | zodd_nonzero\ 62 | zsave\ 63 | zset\ 64 | zseti\ 65 | zsetu\ 66 | zsignum\ 67 | zsplit\ 68 | zswap\ 69 | zzero 70 | 71 | DOC =\ 72 | refsheet.pdf\ 73 | libzahl.pdf 74 | 75 | TEXSRC =\ 76 | doc/libzahl.tex\ 77 | doc/what-is-libzahl.tex\ 78 | doc/libzahls-design.tex\ 79 | doc/get-started.tex\ 80 | doc/miscellaneous.tex\ 81 | doc/arithmetic.tex\ 82 | doc/bit-operations.tex\ 83 | doc/number-theory.tex\ 84 | doc/random-numbers.tex\ 85 | doc/not-implemented.tex\ 86 | doc/exercises.tex 87 | 88 | HDR_PUBLIC = zahl.h $(HDR_SEMIPUBLIC) 89 | HDR = $(HDR_PUBLIC) $(HDR_PRIVATE) 90 | OBJ = $(FUN:=.o) allocator.o 91 | MAN3 = $(FUN:=.3) $(INLINE_FUN:=.3) 92 | MAN7 = libzahl.7 93 | 94 | VPATH = src 95 | 96 | BENCHMARK_LIB_ = libzahl.a 97 | BENCHMARK_LIB_zahl = libzahl.a 98 | BENCHMARK_LIB_libzahl = libzahl.a 99 | BENCHMARK_LIB_tommath = -ltommath 100 | BENCHMARK_LIB_libtommath = -ltommath 101 | BENCHMARK_LIB_gmp = -lgmp 102 | BENCHMARK_LIB_libgmp = -lgmp 103 | BENCHMARK_LIB_tfm = libtfm.a 104 | BENCHMARK_LIB_libtfm = libtfm.a 105 | BENCHMARK_LIB_hebimath = libhebimath.a 106 | BENCHMARK_LIB_libhebimath = libhebimath.a 107 | 108 | BENCHMARK_DEP_ = libzahl.a 109 | BENCHMARK_DEP_zahl = libzahl.a 110 | BENCHMARK_DEP_libzahl = libzahl.a 111 | BENCHMARK_DEP_tommath = bench/libtommath.h 112 | BENCHMARK_DEP_libtommath = bench/libtommath.h 113 | BENCHMARK_DEP_gmp = bench/libgmp.h 114 | BENCHMARK_DEP_libgmp = bench/libgmp.h 115 | BENCHMARK_DEP_tfm = bench/libtfm.h 116 | BENCHMARK_DEP_libtfm = bench/libtfm.h 117 | BENCHMARK_DEP_hebimath = bench/libhebimath.h 118 | BENCHMARK_DEP_libhebimath = bench/libhebimath.h 119 | 120 | BENCHMARK_CPP_tommath = '-DBENCHMARK_LIB="libtommath.h"' 121 | BENCHMARK_CPP_libtommath = '-DBENCHMARK_LIB="libtommath.h"' 122 | BENCHMARK_CPP_gmp = '-DBENCHMARK_LIB="libgmp.h"' 123 | BENCHMARK_CPP_libgmp = '-DBENCHMARK_LIB="libgmp.h"' 124 | BENCHMARK_CPP_tfm = '-DBENCHMARK_LIB="libtfm.h"' 125 | BENCHMARK_CPP_libtfm = '-DBENCHMARK_LIB="libtfm.h"' 126 | BENCHMARK_CPP_hebimath = '-DBENCHMARK_LIB="libhebimath.h"' 127 | BENCHMARK_CPP_libhebimath = '-DBENCHMARK_LIB="libhebimath.h"' 128 | 129 | BENCHMARK_C_hebimath = -static 130 | BENCHMARK_C_libhebimath = -static 131 | 132 | CPPFLAGS += $(BENCHMARK_CPP_$(BENCHMARK_LIB)) 133 | 134 | CFLAGS_WITHOUT_O = $$(printf '%s\n' $(CFLAGS) | sed '/^-O.*$$/d') 135 | 136 | 137 | all: libzahl.a $(DOC) 138 | 139 | .o: .c $(HDR) $(CONFIG) 140 | $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< 141 | 142 | libzahl.a: $(OBJ) 143 | $(AR) -rcs $@ $? 144 | 145 | test-random.c: test-generate.py 146 | ./test-generate.py > test-random.c 147 | 148 | test: test.c libzahl.a test-random.c 149 | $(CC) $(LDFLAGS) $(CFLAGS_WITHOUT_O) -O0 $(CPPFLAGS) -o $@ test.c libzahl.a 150 | 151 | benchmark: bench/benchmark.c bench/util.c bench/util.h $(BENCHMARK_DEP_$(BENCHMARK_LIB)) 152 | $(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ bench/benchmark.c bench/util.c \ 153 | $(BENCHMARK_LIB_$(BENCHMARK_LIB)) $(BENCHMARK_C_$(BENCHMARK_LIB)) 154 | 155 | benchmark-func: bench/benchmark-func.c bench/util.c bench/util.h $(BENCHMARK_DEP_$(BENCHMARK_LIB)) 156 | $(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ bench/benchmark-func.c bench/util.c \ 157 | $(BENCHMARK_LIB_$(BENCHMARK_LIB)) $(BENCHMARK_C_$(BENCHMARK_LIB)) 158 | 159 | benchmark-zrand: bench/benchmark-zrand.c bench/util.c bench/util.h libzahl.a 160 | $(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ bench/benchmark-zrand.c bench/util.c libzahl.a 161 | 162 | refsheet.pdf: doc/refsheet.tex 163 | pdflatex doc/refsheet.tex /dev/null 166 | 167 | libzahl.pdf: $(TEXSRC) 168 | pdflatex doc/libzahl.tex /dev/null 171 | 172 | check: test 173 | ./test 174 | 175 | install: libzahl.a 176 | mkdir -p -- "$(DESTDIR)$(EXECPREFIX)/lib" 177 | mkdir -p -- "$(DESTDIR)$(PREFIX)/include/zahl" 178 | mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man3" 179 | mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man7" 180 | mkdir -p -- "$(DESTDIR)$(DOCPREFIX)/libzahl" 181 | @if test -n "$(DESTDIR)"; then \ 182 | cd man && test -d "$(DESTDIR)$(MANPREFIX)/man7" || \ 183 | (printf '\n\n!! DESTDIR must be an absolute path. !!\n\n\n' ; exit 1) \ 184 | fi 185 | cp -- libzahl.a "$(DESTDIR)$(EXECPREFIX)/lib" 186 | cp -- zahl.h "$(DESTDIR)$(PREFIX)/include" 187 | cp -- $(HDR_SEMIPUBLIC) "$(DESTDIR)$(PREFIX)/include/zahl" 188 | cd man && cp -- $(MAN3) "$(DESTDIR)$(MANPREFIX)/man3" 189 | cd man && cp -- $(MAN7) "$(DESTDIR)$(MANPREFIX)/man7" 190 | cp -- $(DOC) "$(DESTDIR)$(DOCPREFIX)/libzahl" 191 | 192 | uninstall: 193 | -rm -- "$(DESTDIR)$(EXECPREFIX)/lib/libzahl.a" 194 | -cd -- "$(DESTDIR)$(PREFIX)/include" && rm $(HDR_PUBLIC) 195 | -rmdir -- "$(DESTDIR)$(PREFIX)/include/zahl" 196 | -cd -- "$(DESTDIR)$(MANPREFIX)/man3" && rm $(MAN3) 197 | -cd -- "$(DESTDIR)$(MANPREFIX)/man7" && rm $(MAN7) 198 | -cd -- "$(DESTDIR)$(DOCPREFIX)/libzahl" && rm $(DOC) 199 | -rmdir -- "$(DESTDIR)$(DOCPREFIX)/libzahl" 200 | 201 | clean: 202 | -rm -- *.o *.su *.a *.so test test-random.c 2>/dev/null 203 | -rm -- benchmark benchmark-zrand benchmark-func 2>/dev/null 204 | -rm -- *.aux *.log *.out *.idx *.maf *.mtc* *.toc 2>/dev/null 205 | -rm -- refsheet.pdf refsheet.dvi refsheet.ps 2>/dev/null 206 | -rm -- libzahl.pdf libzahl.dvi libzahl.ps 2>/dev/null 207 | 208 | .PHONY: all check clean install uninstall 209 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | NAME 2 | libzahl - Big integer library 3 | 4 | ETYMOLOGY 5 | The bold uppercase 'Z' which represents the set of 6 | all integers is derived from the german word 'Zahlen', 7 | whose singular is 'Zahl'. 8 | 9 | DESCRIPTION 10 | libzahl is a C library for arbitrary size integers, 11 | that aims to be usable for robust programs, and be 12 | fast. 13 | 14 | libzahl will accomplish this by using long jumps 15 | when an error is detected, rather than letting the 16 | caller also perform a check. This shall make the 17 | code in the user program cleaner too. libzahl will 18 | use dedicated temporary bignum integers whether 19 | possible, and necessary, for its internal calculations. 20 | libzahl will not deallocate allocations, but rather 21 | cache them for reuse. 22 | 23 | With the exception of functions working with strings, 24 | all output parameters are before the input parameters. 25 | 26 | RATIONALE 27 | GMP MP cannot be used for robust programs. LibTomMath 28 | is too slow, probably because of all memory allocations, 29 | and has a nonintuitive API. TomsFastMath has an a 30 | nonintuitive API, has limited precision (selected at 31 | compile-time), and has limited functionality. All the 32 | above are also bloated. Hebimath is promising, but I 33 | think it can be done better. 34 | 35 | NOTES 36 | libzahl is currently not thread-safe. 37 | -------------------------------------------------------------------------------- /STATUS: -------------------------------------------------------------------------------- 1 | Optimisation progress for libzahl. Benchmarks are done in the 2 | range 1 to 4097 bits. So far all benchmarks on libzahl are 3 | done with the following combinations of cc and libc: 4 | 5 | gcc + glibc 6 | gcc + musl 7 | clang + glibc 8 | 9 | Benchmarks on the other libraries are done with gcc and glibc. 10 | 11 | All benchmarks are done on an x86-64 (specifically an Intel 12 | Core 2 Quad CPU Q9300), without any extensions turned on 13 | during compilation, and without any use of extensions in 14 | assembly code. The benchmarks are performed with Linux as 15 | the OS's kernel with 50 µs timer slack, and the benchmarking 16 | processes are fixed to one CPU. 17 | 18 | 19 | The following functions are probably implemented optimally: 20 | 21 | zset .................... always fastest 22 | zseti(a, +) ............. tomsfastmath is faster 23 | zseti(a, -) ............. tomsfastmath is faster 24 | zsetu ................... tomsfastmath is faster 25 | zswap ................... always fastest 26 | zzero ................... always fastest (shared with gmp) 27 | zsignum ................. always fastest (shared with gmp) 28 | zeven ................... always fastest (shared with gmp) 29 | zodd .................... always fastest (shared with gmp) 30 | zeven_nonzero ........... always fastest (shared with gmp) 31 | zodd_nonzero ............ always fastest (shared with gmp) 32 | zbtest .................. always fastest 33 | zsave ................... always fastest 34 | zload ................... always fastest 35 | 36 | 37 | The following functions are probably implemented optimally, but 38 | depends on other functions or call-cases for better performance: 39 | 40 | zneg(a, b) .............. always fastest 41 | zabs(a, b) .............. always fastest 42 | ztrunc(a, b, c) ......... always fastest 43 | zbset(a, b, 1) .......... always fastest 44 | zbset(a, b, 0) .......... always fastest 45 | zbset(a, b, -1) ......... always fastest 46 | zsplit .................. alternating with gmp for fastest, but gmp is a bit faster on average 47 | 48 | 49 | The following functions are probably implemented close to 50 | optimally, further optimisation should not be a priority: 51 | 52 | zadd_unsigned ........... fastest after ~140 (depends on cc and libc) compared against zadd too 53 | ztrunc(a, a, b) ......... fastest until ~100, then 77 % (gcc) or 68 % (clang) of tomsfastmath 54 | zbset(a, a, 1) .......... always fastest 55 | zbset(a, a, 0) .......... always fastest 56 | zbset(a, a, -1) ......... always fastest (only marginally faster than gmp with clang) 57 | zlsb .................... always fastest <> 58 | zlsh .................... not too fast anymore 59 | zand .................... fastest after ~400, tomsfastmath before 60 | zor ..................... fastest after ~1150, tomsfastmath before 61 | zxor .................... alternative with gmp after ~700, tomsfastmath before (musl), a bit slow with glibc 62 | znot .................... always fastest 63 | 64 | 65 | The following functions require structural changes for 66 | further optimisations: 67 | 68 | zneg(a, a) .............. always fastest (shared with gmp (gcc)) 69 | zabs(a, a) .............. 34 % (clang) or 8 % (gcc) of tomsfastmath 70 | 71 | 72 | The following functions are probably implemented optimally 73 | or close to optimally, except they contain some code that 74 | should not be necessary after some bugs have been fixed: 75 | 76 | zbits ................... always fastest 77 | zcmpi(a, +) ............. always fastest 78 | zcmpi(a, -) ............. always fastest 79 | zcmpu ................... always fastest 80 | 81 | 82 | It may be possible optimise the following functions 83 | further: 84 | 85 | zadd .................... fastest after ~90 (clang), ~260 (gcc+musl), or ~840 (gcc+glibc) (gcc+glibc is slow) 86 | zcmp .................... almost always fastest (musl), almost always slowest (glibc) <> 87 | zcmpmag ................. always fastest <> 88 | 89 | 90 | The following functions could be optimised further: 91 | 92 | zrsh .................... gmp is almost always faster; also tomsfastmath after ~3000 (gcc+glibc) or ~2800 (clang) 93 | zsub_unsigned ........... always fastest (compared against zsub too) 94 | zsub .................... always fastest (slower with gcc+glibc than gcc+musl or clang) 95 | 96 | 97 | The following functions could probably be optimised further, 98 | but their performance can be significantly improved by 99 | optimising their dependencies: 100 | 101 | zmul .................... slowest 102 | zsqr .................... slowest 103 | zstr_length(a, 10) ...... gmp is faster (clang is faster than gcc, musl is faster than glibc) 104 | zstr(a, b, n) ........... slowest 105 | 106 | 107 | musl has more stable performance than glibc. clang is better at 108 | inlining than gcc. (Which is better at optimising must be judged 109 | on a per-function basis.) 110 | 111 | 112 | 113 | {{{ [out of date legacy area, this being phased out] 114 | Optimisation progress for libzahl, compared to other big integer 115 | libraries. These comparisons are for 152-bit integers. Functions 116 | in parenthesis the right column are functions that needs 117 | optimisation to improve the peformance of the function in the 118 | left column. Double-parenthesis means there may be a better way 119 | to do it. Inside square-brackets, there are some comments on 120 | multi-bit comparisons. 121 | 122 | zgcd .................... 21 % of gmp (zcmpmag) 123 | zmodmul(big mod) ........ slowest ((zmul, zmod)) 124 | zmodsqr(big mod) ........ slowest ((zmul, zmod)) 125 | zmodmul(tiny mod) ....... slowest ((zmul)) 126 | zmodsqr(tiny mod) ....... slowest ((zmul)) 127 | zpow .................... slowest (zmul, zsqr) 128 | zpowu ................... slowest (zmul, zsqr) 129 | zmodpow ................. slowest (zmul, zsqr. zmod) 130 | zmodpowu ................ slowest (zmul, zsqr, zmod) 131 | zsets ................... 13 % of gmp 132 | zrand(default uniform) .. 51 % of gmp 133 | zptest .................. slowest (zrand, zmodpow, zsqr, zmod) 134 | zdiv(big denum) ......... tomsfastmath is faster (zdivmod) 135 | zmod(big denum) ......... fastest (zdivmod) 136 | zdivmod(big denum) ...... fastest 137 | zdiv(tiny denum) ........ slowest 138 | zmod(tiny denum) ........ slowest 139 | zdivmod(tiny denum) ..... slowest 140 | }}} 141 | 142 | 143 | 144 | Note, some corresponding functions are not implemented in 145 | some other libraries. In such cases, they have been implemented 146 | in the translation layers (found under bench/). Those 147 | implementations are often suboptimal, but probably in style 148 | with what you would write if you need that functionality. 149 | Note further, if for example, you want do perform addition 150 | and you know that your operands are non-negative, you would 151 | choose zadd_unsigned in libzahl, but if you are using a 152 | library that does not have the corrsponding function, you are 153 | better of with the regular addition (zadd). This is however 154 | reflected in the comment column. 155 | 156 | Also note, TomsFastMath does not support arbitrarily large 157 | integers, the limit is set at compile-time, which gives is 158 | a significant performance advantage. Furthermore, no failure 159 | check is done with GMP. Additionally, hebimath has been 160 | excluded from these comparison because it is not fully 161 | operational. 162 | 163 | Also note, NOT does not mean the same thing in all libraries, 164 | for example in GMP it means (-x - 1), thus, znot does not 165 | use GMP's NOT in the translations layer. 166 | 167 | 168 | The following optimisation flags have been tested: 169 | 170 | -O0 ...................... Bad 171 | -O1 ...................... Bad 172 | -O2 ...................... Not so good 173 | -O3 ...................... Good 174 | -fno-builtin ............. Bad 175 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | GMP has mpz_divexact(q,n,d), we should have zdiv_exact(q,n,d). 2 | It uses optimised division algorithm that requires that d|n. 3 | 4 | Add zsets_radix 5 | Add zstr_radix 6 | 7 | Can zmodpowu and zmodpow be improved using some other algorithm? 8 | Is it worth implementing precomputed optimal 9 | addition-chain exponentiation in zpowu? 10 | 11 | Test big endian 12 | Test always having .used > 0 for zero 13 | Test negative/non-negative instead of sign 14 | Test long .sign 15 | Test always having .chars % 4 == 0 16 | Test reusing objects in the temp-stack 17 | 18 | Test optimisation of zmul: 19 | bc = [(Hb * Hc) << (m2 << 1)] 20 | + [(Hb * Hc) << m2] 21 | - [(Hb - Lb)(Hc - Lc) << m2] 22 | + [(Lb * Lc) << m2] 23 | + (Lb * Lc) 24 | 25 | Would zmul be faster if we split only one of the 26 | factors until they are both approximately the same 27 | size? 28 | 29 | Add entropy test for zrand. 30 | 31 | Should zmodpowu, zmodpow, zmodmul, and zmodsqr be removed? 32 | I need to research how important these are. 33 | They are important for cryptography, but we do not care about that. 34 | They are important for discrete/abstract mathematics, but bignum probably isn't in those cases? 35 | 36 | Add CPU-warmup loop to benchmarks. 37 | If ondemand scaling is available but not set, set it. 38 | If the current frequency is not the minimum, run a 39 | catch-fire loop until the CPU is throttled to the 40 | minimum frequency. 41 | This loop shall be done after help variables have 42 | been assigned values, as this can help the warmup. 43 | 44 | benchmark with worst case, average case, and best case input. 45 | 46 | zadd, zsub: benchmark both dense and sparse integers. 47 | 48 | Feedback on error handling: 49 | http://bbs.progrider.org/prog/read/1457215529/31,47 50 | -------------------------------------------------------------------------------- /bench/benchmark-zrand.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | 4 | #define BENCHMARK(INSTRUCTION, FAST)\ 5 | do {\ 6 | i = FAST ? 1000000L : 1000L;\ 7 | TIC;\ 8 | while (i--) {\ 9 | INSTRUCTION;\ 10 | }\ 11 | TOC;\ 12 | printf("%s: %s %s\n",\ 13 | #INSTRUCTION, STIME, FAST ? "µs" : "ms");\ 14 | } while (0) 15 | 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | z_t r, n; 21 | jmp_buf jmp; 22 | size_t i; 23 | 24 | benchmark_init(); 25 | 26 | if (setjmp(jmp)) { 27 | zperror(argv[0]); 28 | return 1; 29 | } 30 | zsetup(jmp); 31 | zinit(r); 32 | zinit(n); 33 | 34 | zsetu(n, 1); 35 | zlsh(n, n, 64000L - 1L); 36 | zset(r, n); 37 | 38 | BENCHMARK(zrand(r, FAST_RANDOM, MODUNIFORM, n), 0); 39 | BENCHMARK(zrand(r, LIBC_RAND_RANDOM, MODUNIFORM, n), 0); 40 | BENCHMARK(zrand(r, LIBC_RANDOM_RANDOM, MODUNIFORM, n), 0); 41 | BENCHMARK(zrand(r, LIBC_RAND48_RANDOM, MODUNIFORM, n), 0); 42 | 43 | zfree(r); 44 | zfree(n); 45 | zunsetup(); 46 | return 0; 47 | (void) argc; 48 | } 49 | -------------------------------------------------------------------------------- /bench/benchmark.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | 4 | #define BENCHMARK(INSTRUCTION, FAST)\ 5 | do {\ 6 | i = FAST ? 1000000L : 1000L;\ 7 | TIC;\ 8 | while (i--) {\ 9 | (void)INSTRUCTION;\ 10 | }\ 11 | TOC;\ 12 | printf("%s: %s %s (152 bits)\n",\ 13 | #INSTRUCTION, STIME, FAST ? "µs" : "ms");\ 14 | } while (0) 15 | 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | char buf[2000]; 21 | z_t a, b, c, d, tiny; 22 | jmp_buf jmp; 23 | size_t i; 24 | 25 | benchmark_init(); 26 | 27 | if (setjmp(jmp)) { 28 | zperror(argv[0]); 29 | return 1; 30 | } 31 | zsetup(jmp); 32 | zinit(a); 33 | zinit(b); 34 | zinit(c); 35 | zinit(d); 36 | zinit(tiny); 37 | 38 | zsets(a, "5495468234592964023447280368442884381000481887"); 39 | zsets(b, "4781084818570683458641843084358135840548636081"); 40 | zsets(tiny, "5"); 41 | 42 | BENCHMARK(zset(c, a), 1); 43 | BENCHMARK(zseti(c, 1000000000LL), 1); 44 | BENCHMARK(zsetu(c, 1000000000ULL), 1); 45 | BENCHMARK(zneg(c, a), 1); 46 | BENCHMARK(zneg(a, a), 1); 47 | BENCHMARK(zabs(c, a), 1); 48 | BENCHMARK(zabs(a, a), 1); 49 | BENCHMARK(zadd_unsigned(c, a, b), 1); 50 | BENCHMARK(zsub_unsigned(c, a, b), 1); 51 | BENCHMARK(zadd(c, a, b), 1); 52 | BENCHMARK(zsub(c, a, b), 1); 53 | BENCHMARK(zand(c, a, b), 1); 54 | BENCHMARK(zor(c, a, b), 1); 55 | BENCHMARK(zxor(c, a, b), 1); 56 | BENCHMARK(znot(c, a), 1); 57 | BENCHMARK(zeven(a), 1); 58 | BENCHMARK(zodd(a), 1); 59 | BENCHMARK(zeven_nonzero(a), 1); 60 | BENCHMARK(zodd_nonzero(a), 1); 61 | BENCHMARK(zzero(a), 1); 62 | BENCHMARK(zsignum(a), 1); 63 | BENCHMARK(zbits(a), 1); 64 | BENCHMARK(zlsb(a), 1); 65 | BENCHMARK(zswap(a, b), 1); 66 | BENCHMARK(zlsh(c, a, 76), 1); 67 | BENCHMARK(zrsh(c, a, 76), 1); 68 | BENCHMARK(ztrunc(c, a, 76), 1); 69 | BENCHMARK(ztrunc(c, c, 76), 1); 70 | BENCHMARK(zsplit(c, d, a, 76), 1); 71 | BENCHMARK(zcmpmag(a, b), 1); 72 | BENCHMARK(zcmp(a, b), 1); 73 | BENCHMARK(zcmpi(a, 1000000000LL), 1); 74 | BENCHMARK(zcmpi(a, -1000000000LL), 1); 75 | BENCHMARK(zcmpu(a, 1000000000ULL), 1); 76 | BENCHMARK(zbset(c, a, 76, 1), 1); 77 | BENCHMARK(zbset(a, a, 76, 1), 1); 78 | BENCHMARK(zbset(c, a, 76, 0), 1); 79 | BENCHMARK(zbset(c, c, 76, 0), 1); 80 | BENCHMARK(zbset(c, a, 76, -1), 1); 81 | BENCHMARK(zbset(a, a, 76, -1), 1); 82 | BENCHMARK(zbtest(a, 76), 1); 83 | #ifndef HEBIMATH /* These take too long in hebimath because of inefficient division. */ 84 | BENCHMARK(zgcd(c, a, b), 0); 85 | #endif 86 | BENCHMARK(zmul(c, a, b), 0); 87 | BENCHMARK(zmul(c, a, a), 0); 88 | BENCHMARK(zsqr(c, a), 0); 89 | #ifndef HEBIMATH /* Ditto. */ 90 | zsets(d, "1484298084218938358480511181388394862858002249"); 91 | BENCHMARK(zmodmul(c, a, b, d), 0); 92 | BENCHMARK(zmodmul(c, a, a, d), 0); 93 | BENCHMARK(zmodsqr(c, a, d), 0); 94 | BENCHMARK(zmodmul(c, a, b, tiny), 0); 95 | BENCHMARK(zmodmul(c, a, a, tiny), 0); 96 | BENCHMARK(zmodsqr(c, a, tiny), 0); 97 | zsets(d, "12"); 98 | BENCHMARK(zpow(c, a, d), 0); /* Memory corruption when using hebimath. */ 99 | BENCHMARK(zpowu(c, a, 12), 0); /* Memory corruption when using hebimath. */ 100 | BENCHMARK(zmodpow(c, a, d, b), 0); 101 | BENCHMARK(zmodpowu(c, a, 12, b), 0); 102 | #endif 103 | BENCHMARK(zsets(c, "5495468234592964023447280368442884381000481887"), 0); 104 | BENCHMARK(zstr_length(a, 10), 0); 105 | BENCHMARK(zstr(a, buf, 0), 0); 106 | BENCHMARK(zstr(a, buf, sizeof(buf) - 1), 0); 107 | BENCHMARK(zrand(c, DEFAULT_RANDOM, QUASIUNIFORM, a), 0); 108 | BENCHMARK(zrand(c, DEFAULT_RANDOM, UNIFORM, a), 0); 109 | BENCHMARK(zrand(c, DEFAULT_RANDOM, MODUNIFORM, a), 0); 110 | BENCHMARK(zptest(d, a, 5), 0); 111 | BENCHMARK(zsave(a, buf), 1); 112 | BENCHMARK(zload(a, buf), 1); 113 | BENCHMARK(zdiv(c, a, b), 1); 114 | BENCHMARK(zmod(c, a, b), 1); 115 | BENCHMARK(zdivmod(c, d, a, b), 1); 116 | #ifndef HEBIMATH /* Ditto. */ 117 | BENCHMARK(zdiv(c, a, tiny), 0); 118 | BENCHMARK(zmod(c, a, tiny), 0); 119 | BENCHMARK(zdivmod(c, d, a, tiny), 0); 120 | #endif 121 | 122 | zfree(a); 123 | zfree(b); 124 | zfree(c); 125 | zfree(d); 126 | zfree(tiny); 127 | zunsetup(); 128 | return 0; 129 | (void) argc; 130 | } 131 | -------------------------------------------------------------------------------- /bench/libgmp.h: -------------------------------------------------------------------------------- 1 | #define __GMP_NO_ATTRIBUTE_CONST_PURE 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define BIGINT_LIBRARY "GMP" 12 | 13 | typedef mpz_t z_t; 14 | 15 | static z_t _0, _1, _a, _b; 16 | static FILE *_fbuf; 17 | static gmp_randstate_t _randstate; 18 | 19 | static inline void 20 | zsetup(jmp_buf env) 21 | { 22 | static char buf[1000]; 23 | (void) env; 24 | mpz_init_set_ui(_0, 0); 25 | mpz_init_set_ui(_1, 1); 26 | mpz_init(_a); 27 | mpz_init(_b); 28 | _fbuf = fmemopen(buf, sizeof(buf), "r+"); 29 | gmp_randinit_mt(_randstate); 30 | } 31 | 32 | static inline void 33 | zunsetup(void) 34 | { 35 | mpz_clear(_0); 36 | mpz_clear(_1); 37 | mpz_clear(_a); 38 | mpz_clear(_b); 39 | fclose(_fbuf); 40 | gmp_randclear(_randstate); 41 | } 42 | 43 | #define FAST_RANDOM 0 44 | #define SECURE_RANDOM 0 45 | #define DEFAULT_RANDOM 0 46 | #define FASTEST_RANDOM 0 47 | #define LIBC_RAND_RANDOM 0 48 | #define LIBC_RANDOM_RANDOM 0 49 | #define LIBC_RAND48_RANDOM 0 50 | #define QUASIUNIFORM 0 51 | #define UNIFORM 1 52 | #define MODUNIFORM 2 53 | 54 | #define zperror(x) ((void)0) 55 | #define zinit mpz_init 56 | #define zfree mpz_clear 57 | 58 | #define zset mpz_set 59 | #define zneg mpz_neg 60 | #define zabs mpz_abs 61 | #define zadd_unsigned(r, a, b) (zabs(_a, a), zabs(_b, b), mpz_add(r, _a, _b)) 62 | #define zsub_unsigned(r, a, b) (zabs(_a, a), zabs(_b, b), mpz_sub(r, _a, _b)) 63 | #define zadd mpz_add 64 | #define zsub mpz_sub 65 | #define zand mpz_and 66 | #define zor mpz_ior 67 | #define zxor mpz_xor 68 | #define zbtest mpz_tstbit 69 | #define zeven_nonzero zeven 70 | #define zodd_nonzero zodd 71 | #define zzero(a) (!mpz_sgn(a)) 72 | #define zsignum mpz_sgn 73 | #define zbits(a) mpz_sizeinbase(a, 2) 74 | #define zlsb(a) mpz_scan1(a, 0) 75 | #define zswap mpz_swap 76 | #define zlsh mpz_mul_2exp 77 | #define zrsh mpz_tdiv_q_2exp 78 | #define ztrunc mpz_tdiv_r_2exp 79 | #define zcmpmag mpz_cmpabs 80 | #define zcmp mpz_cmp 81 | #define zcmpi(a, b) (zseti(_b, b), zcmp(a, _b)) 82 | #define zcmpu(a, b) (zsetu(_b, b), zcmp(a, _b)) 83 | #define zgcd mpz_gcd 84 | #define zmul mpz_mul 85 | #define zsqr(r, a) mpz_mul(r, a, a) 86 | #define zmodmul(r, a, b, m) (zmul(r, a, b), zmod(r, r, m)) 87 | #define zmodsqr(r, a, m) (zsqr(r, a), zmod(r, r, m)) 88 | #define zpow(r, a, b) mpz_pow_ui(r, a, mpz_get_ui(b)) 89 | #define zpowu mpz_pow_ui 90 | #define zmodpow mpz_powm 91 | #define zmodpowu mpz_powm_ui 92 | #define zsets(a, s) mpz_set_str(a, s, 10) 93 | #define zstr_length(a, b) (mpz_sizeinbase(a, 10) + (zsignum(a) < 0)) 94 | #define zstr(a, s, n) (mpz_get_str(s, 10, a)) 95 | #define zptest(w, a, t) mpz_probab_prime_p(a, t) /* Note, the witness is not returned. */ 96 | #define zdiv mpz_tdiv_q 97 | #define zmod mpz_tdiv_r 98 | #define zdivmod mpz_tdiv_qr 99 | 100 | static inline int 101 | zeven(z_t a) 102 | { 103 | return mpz_even_p(a); 104 | } 105 | 106 | static inline int 107 | zodd(z_t a) 108 | { 109 | return mpz_odd_p(a); 110 | } 111 | 112 | static inline void 113 | zsetu(z_t r, unsigned long long int val) 114 | { 115 | uint32_t high = (uint32_t)(val >> 32); 116 | uint32_t low = (uint32_t)val; 117 | 118 | if (high) { 119 | mpz_set_ui(r, high); 120 | mpz_set_ui(_a, low); 121 | zlsh(r, r, 32); 122 | zadd(r, r, _a); 123 | } else { 124 | mpz_set_ui(r, low); 125 | } 126 | 127 | } 128 | 129 | static inline void 130 | zseti(z_t r, long long int val) 131 | { 132 | if (val >= 0) { 133 | zsetu(r, (unsigned long long int)val); 134 | } else { 135 | zsetu(r, (unsigned long long int)-val); 136 | zneg(r, r); 137 | } 138 | } 139 | 140 | static inline void 141 | znot(z_t r, z_t a) 142 | { 143 | size_t bits = zbits(a); 144 | mpz_set_ui(_b, 0); 145 | mpz_setbit(_b, bits); 146 | zsub(_b, _b, _1); 147 | zxor(r, a, _b); 148 | zneg(r, r); 149 | } 150 | 151 | static inline void 152 | zsplit(z_t high, z_t low, z_t a, size_t brk) 153 | { 154 | if (low == a) { 155 | zrsh(high, a, brk); 156 | ztrunc(low, a, brk); 157 | } else { 158 | ztrunc(low, a, brk); 159 | zrsh(high, a, brk); 160 | } 161 | } 162 | 163 | static inline void 164 | zbset(z_t r, z_t a, size_t bit, int mode) 165 | { 166 | if (r != a) 167 | zset(r, a); 168 | if (mode > 0) 169 | mpz_setbit(r, bit); 170 | else if (mode == 0) 171 | mpz_clrbit(r, bit); 172 | else 173 | mpz_combit(r, bit); 174 | } 175 | 176 | static inline size_t 177 | zsave(z_t a, void *buffer) 178 | { 179 | size_t n = mpz_out_raw(_fbuf, a); 180 | (void)buffer; 181 | fseek(_fbuf, -(long)n, SEEK_CUR); 182 | return n; 183 | } 184 | 185 | static inline size_t 186 | zload(z_t a, const void *buffer) 187 | { 188 | size_t n = mpz_inp_raw(a, _fbuf); 189 | (void)buffer; 190 | fseek(_fbuf, -(long)n, SEEK_CUR); 191 | return n; 192 | } 193 | 194 | static inline void 195 | zrand(z_t r, int dev, int dist, z_t n) 196 | { 197 | size_t bits; 198 | (void) dev; 199 | 200 | if (zzero(n)) { 201 | mpz_set_ui(r, 0); 202 | return; 203 | } 204 | if (zsignum(n) < 0) { 205 | return; 206 | } 207 | 208 | switch (dist) { 209 | case QUASIUNIFORM: 210 | bits = zbits(n); 211 | mpz_urandomb(r, _randstate, bits); 212 | zadd(r, r, _1); 213 | zmul(r, r, n); 214 | zrsh(r, r, bits); 215 | break; 216 | 217 | case UNIFORM: /* Note, n is exclusive in this implementation. */ 218 | mpz_urandomm(r, _randstate, n); 219 | break; 220 | 221 | case MODUNIFORM: 222 | bits = zbits(n); 223 | mpz_urandomb(r, _randstate, bits); 224 | if (zcmp(r, n) > 0) 225 | zsub(r, r, n); 226 | break; 227 | 228 | default: 229 | abort(); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /bench/libtommath.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define BIGINT_LIBRARY "libtommath" 9 | 10 | #define FAST_RANDOM 0 11 | #define SECURE_RANDOM 0 12 | #define DEFAULT_RANDOM 0 13 | #define FASTEST_RANDOM 0 14 | #define LIBC_RAND_RANDOM 0 15 | #define LIBC_RANDOM_RANDOM 0 16 | #define LIBC_RAND48_RANDOM 0 17 | #define QUASIUNIFORM 0 18 | #define UNIFORM 1 19 | #define MODUNIFORM 2 20 | 21 | typedef mp_int z_t[1]; 22 | 23 | static z_t _0, _1, _a, _b; 24 | static int _tmp, error; 25 | static jmp_buf jbuf; 26 | 27 | #ifdef ZAHL_UNSAFE 28 | # define try(expr) (expr) 29 | #else 30 | # define try(expr) do if ((error = (expr))) longjmp(jbuf, 1); while (0) 31 | #endif 32 | 33 | static inline void 34 | zsetup(jmp_buf env) 35 | { 36 | *jbuf = *env; 37 | try(mp_init_set_int(_0, 0)); 38 | try(mp_init_set_int(_1, 1)); 39 | try(mp_init(_a)); 40 | try(mp_init(_b)); 41 | } 42 | 43 | static inline void 44 | zunsetup(void) 45 | { 46 | mp_clear(_0); 47 | mp_clear(_1); 48 | mp_clear(_a); 49 | mp_clear(_b); 50 | } 51 | 52 | static inline void 53 | zperror(const char *str) 54 | { 55 | if (str && *str) 56 | fprintf(stderr, "%s: %s\n", str, mp_error_to_string(error)); 57 | else 58 | fprintf(stderr, "%s\n", mp_error_to_string(error)); 59 | } 60 | 61 | static inline void 62 | zinit(z_t a) 63 | { 64 | try(mp_init(a)); 65 | } 66 | 67 | static inline void 68 | zfree(z_t a) 69 | { 70 | mp_clear(a); 71 | } 72 | 73 | static inline void 74 | zset(z_t r, z_t a) 75 | { 76 | try(mp_copy(a, r)); 77 | } 78 | 79 | static inline void 80 | zneg(z_t r, z_t a) 81 | { 82 | try(mp_neg(a, r)); 83 | } 84 | 85 | static inline void 86 | zabs(z_t r, z_t a) 87 | { 88 | try(mp_abs(a, r)); 89 | } 90 | 91 | static inline void 92 | zadd(z_t r, z_t a, z_t b) 93 | { 94 | try(mp_add(a, b, r)); 95 | } 96 | 97 | static inline void 98 | zsub(z_t r, z_t a, z_t b) 99 | { 100 | try(mp_sub(a, b, r)); 101 | } 102 | 103 | static inline void 104 | zadd_unsigned(z_t r, z_t a, z_t b) 105 | { 106 | zabs(_a, a); 107 | zabs(_b, b); 108 | zadd(r, _a, _b); 109 | } 110 | 111 | static inline void 112 | zsub_unsigned(z_t r, z_t a, z_t b) 113 | { 114 | zabs(_a, a); 115 | zabs(_b, b); 116 | zsub(r, _a, _b); 117 | } 118 | 119 | static inline size_t 120 | zbits(z_t a) 121 | { 122 | return mp_count_bits(a); 123 | } 124 | 125 | static inline size_t 126 | zlsb(z_t a) 127 | { 128 | return mp_cnt_lsb(a); 129 | } 130 | 131 | static inline int 132 | zeven(z_t a) 133 | { 134 | return mp_iseven(a); 135 | } 136 | 137 | static inline int 138 | zodd(z_t a) 139 | { 140 | return mp_isodd(a); 141 | } 142 | 143 | static inline int 144 | zeven_nonzero(z_t a) 145 | { 146 | return zeven(a); 147 | } 148 | 149 | static inline int 150 | zodd_nonzero(z_t a) 151 | { 152 | return zodd(a); 153 | } 154 | 155 | static inline int 156 | zzero(z_t a) 157 | { 158 | return mp_iszero(a); 159 | } 160 | 161 | static inline void 162 | zand(z_t r, z_t a, z_t b) 163 | { 164 | try(mp_and(a, b, r)); 165 | } 166 | 167 | static inline void 168 | zor(z_t r, z_t a, z_t b) 169 | { 170 | try(mp_or(a, b, r)); 171 | } 172 | 173 | static inline void 174 | zxor(z_t r, z_t a, z_t b) 175 | { 176 | try(mp_xor(a, b, r)); 177 | } 178 | 179 | static inline void 180 | znot(z_t r, z_t a) 181 | { 182 | try(mp_2expt(_a, (int)zbits(a))); 183 | try(mp_sub_d(_a, 1, _a)); 184 | zand(r, a, _a); 185 | zneg(r, r); 186 | } 187 | 188 | static inline int 189 | zbtest(z_t a, size_t bit) 190 | { 191 | try(mp_2expt(_b, (int)bit)); 192 | zand(_b, a, _b); 193 | return !zzero(_b); 194 | } 195 | 196 | static inline void 197 | zbset(z_t r, z_t a, size_t bit, int mode) 198 | { 199 | if (mode > 0) { 200 | try(mp_2expt(_b, (int)bit)); 201 | zor(r, a, _b); 202 | } else if (mode < 0 || zbtest(a, bit)) { 203 | try(mp_2expt(_b, (int)bit)); 204 | zxor(r, a, _b); 205 | } 206 | } 207 | 208 | static inline void 209 | zswap(z_t a, z_t b) 210 | { 211 | mp_exch(a, b); 212 | } 213 | 214 | static inline void 215 | zlsh(z_t r, z_t a, size_t b) 216 | { 217 | try(mp_mul_2d(a, (int)b, r)); 218 | } 219 | 220 | static inline void 221 | zrsh(z_t r, z_t a, size_t b) 222 | { 223 | try(mp_div_2d(a, (int)b, r, 0)); 224 | } 225 | 226 | static inline void 227 | ztrunc(z_t r, z_t a, size_t b) 228 | { 229 | try(mp_mod_2d(a, (int)b, r)); 230 | } 231 | 232 | static inline void 233 | zsplit(z_t high, z_t low, z_t a, size_t brk) 234 | { 235 | if (low == a) { 236 | zrsh(high, a, brk); 237 | ztrunc(low, a, brk); 238 | } else { 239 | ztrunc(low, a, brk); 240 | zrsh(high, a, brk); 241 | } 242 | } 243 | 244 | static inline void 245 | zsetu(z_t r, unsigned long long int val) 246 | { 247 | try(mp_set_long_long(r, val)); 248 | } 249 | 250 | static inline void 251 | zseti(z_t r, long long int val) 252 | { 253 | if (val >= 0) { 254 | zsetu(r, (unsigned long long int)val); 255 | } else { 256 | zsetu(r, (unsigned long long int)-val); 257 | zneg(r, r); 258 | } 259 | } 260 | 261 | static inline int 262 | zcmpmag(z_t a, z_t b) 263 | { 264 | return mp_cmp_mag(a, b); 265 | } 266 | 267 | static inline int 268 | zcmp(z_t a, z_t b) 269 | { 270 | return mp_cmp(a, b); 271 | } 272 | 273 | static inline int 274 | zcmpi(z_t a, long long int b) 275 | { 276 | zseti(_b, b); 277 | return zcmp(a, _b); 278 | } 279 | 280 | static inline int 281 | zcmpu(z_t a, unsigned long long int b) 282 | { 283 | zsetu(_b, b); 284 | return zcmp(a, _b); 285 | } 286 | 287 | static inline int 288 | zsignum(z_t a) 289 | { 290 | return zcmp(a, _0); 291 | } 292 | 293 | static inline void 294 | zgcd(z_t r, z_t a, z_t b) 295 | { 296 | try(mp_gcd(a, b, r)); 297 | } 298 | 299 | static inline void 300 | zmul(z_t r, z_t a, z_t b) 301 | { 302 | try(mp_mul(a, b, r)); 303 | } 304 | 305 | static inline void 306 | zsqr(z_t r, z_t a) 307 | { 308 | try(mp_sqr(a, r)); 309 | } 310 | 311 | static inline void 312 | zmodmul(z_t r, z_t a, z_t b, z_t m) 313 | { 314 | try(mp_mulmod(a, b, m, r)); 315 | } 316 | 317 | static inline void 318 | zmodsqr(z_t r, z_t a, z_t m) 319 | { 320 | try(mp_sqrmod(a, m, r)); 321 | } 322 | 323 | static inline void 324 | zpow(z_t r, z_t a, z_t b) 325 | { 326 | try(mp_expt_d(a, (mp_digit)mp_get_int(b), r)); 327 | } 328 | 329 | static inline void 330 | zpowu(z_t r, z_t a, unsigned long long int b) 331 | { 332 | try(mp_expt_d(a, (mp_digit)b, r)); 333 | } 334 | 335 | static inline void 336 | zmodpow(z_t r, z_t a, z_t b, z_t m) 337 | { 338 | try(mp_exptmod(a, b, m, r)); 339 | } 340 | 341 | static inline void 342 | zmodpowu(z_t r, z_t a, unsigned long long int b, z_t m) 343 | { 344 | try(mp_set_int(_b, b)); 345 | try(mp_exptmod(a, _b, m, r)); 346 | } 347 | 348 | static inline void 349 | zsets(z_t a, const char *s) 350 | { 351 | try(mp_read_radix(a, s, 10)); 352 | } 353 | 354 | static inline size_t 355 | zstr_length(z_t a, size_t b) 356 | { 357 | try(mp_radix_size(a, b, &_tmp)); 358 | return _tmp; 359 | } 360 | 361 | static inline char * 362 | zstr(z_t a, char *s, size_t n) 363 | { 364 | try(mp_toradix(a, s, 10)); 365 | return s; 366 | (void) n; 367 | } 368 | 369 | static inline int 370 | zptest(z_t w, z_t a, int t) 371 | { 372 | try(mp_prime_is_prime(a, t, &_tmp)); 373 | return _tmp; 374 | (void) w; /* Note, the witness is not returned. */ 375 | } 376 | 377 | static inline size_t 378 | zsave(z_t a, char *b) 379 | { 380 | _tmp = !b ? mp_signed_bin_size(a) : mp_to_signed_bin(a, (unsigned char *)b); 381 | return _tmp; 382 | } 383 | 384 | static inline size_t 385 | zload(z_t a, const char *b) /* Note, requires that zsave was called directly prior. */ 386 | { 387 | return mp_read_signed_bin(a, (const unsigned char *)b, _tmp); 388 | } 389 | 390 | static inline void 391 | zdiv(z_t r, z_t a, z_t b) 392 | { 393 | try(mp_div(a, b, r, 0)); 394 | } 395 | 396 | static inline void 397 | zmod(z_t r, z_t a, z_t b) 398 | { 399 | try(mp_mod(a, b, r)); 400 | } 401 | 402 | static inline void 403 | zdivmod(z_t q, z_t r, z_t a, z_t b) 404 | { 405 | try(mp_div(a, b, q, r)); 406 | } 407 | 408 | static inline void 409 | zrand(z_t r, int dev, int dist, z_t n) 410 | { 411 | static int gave_up = 0; 412 | int bits; 413 | (void) dev; 414 | 415 | if (zzero(n)) { 416 | mp_zero(r); 417 | return; 418 | } 419 | if (zsignum(n) < 0) { 420 | return; 421 | } 422 | 423 | bits = zbits(n); 424 | 425 | switch (dist) { 426 | case QUASIUNIFORM: 427 | try(mp_rand(r, bits)); 428 | zadd(r, r, _1); 429 | zmul(r, r, n); 430 | zrsh(r, r, bits); 431 | break; 432 | 433 | case UNIFORM: 434 | if (!gave_up) { 435 | gave_up = 1; 436 | printf("I'm sorry, this is too difficult, I give up.\n"); 437 | } 438 | break; 439 | 440 | case MODUNIFORM: 441 | try(mp_rand(r, bits)); 442 | if (zcmp(r, n) > 0) 443 | zsub(r, r, n); 444 | break; 445 | 446 | default: 447 | abort(); 448 | } 449 | } 450 | -------------------------------------------------------------------------------- /bench/merge-benchmark-func.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # See LICENSE file for copyright and license details. 3 | 4 | 5 | # Invoke using `env SELECT_MIN=` to select the minimum value, 6 | # rather than concatenate. This applies to 1-dimensional data only. 7 | 8 | 9 | import sys, os 10 | 11 | line_count = None 12 | files = [] 13 | 14 | for path in sys.argv[1:]: 15 | with open(path, 'rb') as file: 16 | data = file.read() 17 | data = data.decode('utf-8', 'strict') 18 | if data[-1] == '\n': 19 | data = data[:-1] 20 | data = data.split('\n') 21 | if line_count is None: 22 | line_count = len(data) 23 | elif len(data) != line_count: 24 | print('%s: line count mismatch' % sys.argv[0], file = sys.stderr) 25 | sys.exit(1) 26 | files.append(data) 27 | 28 | dim = int(files[0][1]) 29 | skip = 1 + dim 30 | for i in range(skip): 31 | print(files[0][i]) 32 | 33 | if dim > 1: 34 | for i in range(skip, line_count): 35 | best_nsec = None 36 | best_line = None 37 | for lines in files: 38 | line = lines[i] 39 | nsec = int(line) 40 | if best_nsec is None or nsec < best_nsec: 41 | best_nsec, best_line = nsec, line 42 | print(best_line) 43 | elif 'SELECT_MIN' not in os.environ: 44 | for lines in files: 45 | for i in range(skip, line_count): 46 | print(lines[i]) 47 | else: 48 | best_nsec = None 49 | best_line = None 50 | for lines in files: 51 | for i in range(skip, line_count): 52 | line = lines[i] 53 | nsec = int(line) 54 | if best_nsec is None or nsec < best_nsec: 55 | best_nsec, best_line = nsec, line 56 | print(best_line) 57 | -------------------------------------------------------------------------------- /bench/merge-benchmark.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # See LICENSE file for copyright and license details. 3 | 4 | import sys 5 | 6 | line_count = None 7 | files = [] 8 | 9 | for path in sys.argv[1:]: 10 | with open(path, 'rb') as file: 11 | data = file.read() 12 | data = data.decode('utf-8', 'strict') 13 | if data[-1] == '\n': 14 | data = data[:-1] 15 | data = data.split('\n') 16 | if line_count is None: 17 | line_count = len(data) 18 | elif len(data) != line_count: 19 | print('%s: line count mismatch' % sys.argv[0], file = sys.stderr) 20 | sys.exit(1) 21 | files.append(data) 22 | 23 | for i in range(line_count): 24 | best_sec = None 25 | best_nsec = None 26 | best_line = None 27 | for lines in files: 28 | line = lines[i] 29 | [sec, nsec] = line.split(':')[1].split(' ')[1].split('.') 30 | [sec, nsec] = [int(sec), int(nsec)] 31 | if best_sec is None or sec < best_sec or (sec == best_sec and nsec < best_nsec): 32 | best_sec, best_nsec, best_line = sec, nsec, line 33 | print(best_line) 34 | -------------------------------------------------------------------------------- /bench/plot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # See LICENSE file for copyright and license details. 3 | 4 | 5 | # Invoke using `env XKCD_STYLE=` to for more a comical plot style. 6 | 7 | # Invoke using `env PER_BIT=` to divide all time values by the number 8 | # of bits that where processed. This applies to 2-dimensional data only. 9 | 10 | # Invoke using `env VIOLIN_STYLE=` to draw violin plots rather than 11 | # box plots. This applies to multisample 1-dimensional data only. 12 | # If used, used `env SHOW_MEAN=` will show that mean value in place 13 | # of the median value. 14 | 15 | # For multisample 1-dimensional, if `env VIOLIN_STYLE=` is not used 16 | # `env NOTCH_STYLE=`, `env PATCH_ARTIST`, and `env SHOW_MEAN` may be 17 | # applied. 18 | 19 | 20 | import sys, os 21 | import matplotlib.pyplot as plot 22 | 23 | xkcdstyle = 'XKCD_STYLE' in os.environ 24 | if xkcdstyle: 25 | plot.xkcd() 26 | fig = plot.figure() 27 | 28 | xint = lambda x : (float(x) if '.' in x else int(x)) 29 | 30 | multiple = 1 31 | smultiple = '' 32 | 33 | multiples = [1] * len(sys.argv[1:]) 34 | smultiples = [''] * len(sys.argv[1:]) 35 | paths = [None] * len(sys.argv[1:]) 36 | 37 | i = 0 38 | for arg in sys.argv[1:]: 39 | if arg.startswith('*'): 40 | multiples[i] = float(arg[1:]) 41 | smultiples[i] = ' * ' + arg[1:] 42 | else: 43 | paths[i] = arg 44 | i += 1 45 | 46 | multiples = multiples[:i] 47 | smultiples = smultiples[:i] 48 | paths = paths[:i] 49 | 50 | xpoints = [None] * i 51 | ypoints = [None] * i 52 | values = [None] * i 53 | labels = [None] * i 54 | 55 | for i, path in enumerate(paths): 56 | with open(path, 'rb') as file: 57 | lines = file.read() 58 | lines = lines.decode('utf-8', 'strict').split('\n') 59 | labels[i], dim, values[i] = lines[0] + smultiples[i], int(lines[1]), lines[2:] 60 | if dim > 1: 61 | xpoints[i], values[i] = values[i][0], values[i][1:] 62 | xpoints[i] = [int(x) for x in xpoints[i].split(' ')] 63 | xpoints[i][1] += 1 64 | xpoints[i] = list(range(*xpoints[i])) 65 | if dim > 2: 66 | ypoints[i], values[i] = values[i][0], values[i][1:] 67 | ypoints[i] = [int(x) for x in ypoints[i].split(' ')] 68 | ypoints[i][1] += 1 69 | ypoints[i] = list(range(*ypoints[i])) 70 | values[i] = [xint(v) * multiples[i] for v in values[i] if v != ''] 71 | if dim == 2: 72 | if 'PER_BIT' in os.environ: 73 | values[i] = [y / x for y, x in zip(values[i], xpoints[i])] 74 | 75 | data = [[[i], (values[i], xpoints[i], ypoints[i])] for i in range(len(values))] 76 | data.sort(key = lambda x : x[1]) 77 | merged, data = [data[0]], data[1:] 78 | for ([i], d) in data: 79 | if d == merged[-1][1]: 80 | merged[-1][0].append(i) 81 | else: 82 | merged.append(([i], d)) 83 | 84 | xpoints = [xpoints[i[0]] for (i, _) in merged] 85 | ypoints = [ypoints[i[0]] for (i, _) in merged] 86 | values = [values[i[0]] for (i, _) in merged] 87 | labels = [' & '.join(labels[j] for j in i) for (i, _) in merged] 88 | 89 | vmin = min(min(min(v) for v in values), 0) 90 | vmax = max(max(max(v) for v in values), 0) 91 | 92 | if dim == 1: 93 | plot.ylabel('time') 94 | if len(values[0]) == 1: 95 | plot.bar(range(len(values)), 96 | [vs[0] for vs in values], 97 | align = 'center', 98 | orientation = 'vertical', 99 | tick_label = labels) 100 | labels = None 101 | elif 'VIOLIN_STYLE' in os.environ: 102 | plot.violinplot(values, 103 | vert = True, 104 | showmeans = 'SHOW_MEAN' in os.environ, 105 | showmedians = 'SHOW_MEAN' not in os.environ, 106 | showextrema = True) 107 | else: 108 | plot.boxplot(values, 109 | vert = True, 110 | notch = 'NOTCH_STYLE' in os.environ, 111 | patch_artist = 'PATCH_ARTIST' in os.environ) 112 | if 'SHOW_MEAN' in os.environ: 113 | for i in range(len(values)): 114 | mean = sum(values[i]) / len(values[i]) 115 | plot.plot([i + 0.75, i + 1.25], [mean, mean]); 116 | if labels is not None: 117 | plot.setp(fig.axes, 118 | xticks = [x + 1 for x in range(len(values))], 119 | xticklabels = labels) 120 | elif dim == 2: 121 | for i in range(len(values)): 122 | plot.plot(xpoints[i], values[i], label = labels[i]) 123 | plot.legend(loc = 'best') 124 | plot.xlabel('bits') 125 | plot.ylabel('time') 126 | elif dim == 3: 127 | pass 128 | 129 | plot.ylim((vmin * 1.1, vmax * 1.1)) 130 | 131 | if not xkcdstyle: 132 | plot.grid(True) 133 | plot.show() 134 | -------------------------------------------------------------------------------- /bench/util.c: -------------------------------------------------------------------------------- 1 | #define COMPILING_UTIL_C 2 | #include "util.h" 3 | 4 | 5 | char timebuf[512]; 6 | unsigned long long int freq; 7 | 8 | 9 | void 10 | benchmark_init(void) 11 | { 12 | #if defined(__linux__) && defined(USE_RDTSC) 13 | cpu_set_t cpuset; 14 | FILE *f; 15 | char *line = 0; 16 | size_t size = 0; 17 | char path[PATH_MAX]; 18 | CPU_ZERO(&cpuset); 19 | CPU_SET(USE_CPU, &cpuset); 20 | sched_setaffinity(getpid(), sizeof(cpuset), &cpuset); 21 | sprintf(path, "/sys/devices/system/cpu/cpu%i/cpufreq/cpuinfo_max_freq", USE_CPU); 22 | f = fopen(path, "r"); 23 | if (getline(&line, &size, f) < 0) 24 | abort(); 25 | fclose(f); 26 | freq = strtoull(line, 0, 10); 27 | free(line); 28 | 29 | #elif defined(__linux__) 30 | cpu_set_t cpuset; 31 | CPU_ZERO(&cpuset); 32 | CPU_SET(USE_CPU, &cpuset); 33 | sched_setaffinity(getpid(), sizeof(cpuset), &cpuset); 34 | 35 | #else 36 | fprintf(stderr, "WARNING: Don't know how to set CPU affinity.\n"); 37 | 38 | #endif 39 | } 40 | -------------------------------------------------------------------------------- /bench/util.h: -------------------------------------------------------------------------------- 1 | #if defined(__linux__) 2 | # define _GNU_SOURCE 3 | # include 4 | #endif 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | 15 | #ifdef BENCHMARK_LIB 16 | # include BENCHMARK_LIB 17 | #else 18 | # include "../zahl.h" 19 | # define BIGINT_LIBRARY "libzahl" 20 | #endif 21 | 22 | #ifndef LIBRARY_SUFFIX 23 | # define LIBRARY_SUFFIX "" 24 | #endif 25 | 26 | #ifndef USE_CPU 27 | # define USE_CPU 0 28 | #endif 29 | 30 | 31 | #ifndef CLOCK_MONOTONIC_RAW 32 | # define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC 33 | #endif 34 | 35 | #ifdef __x86_64__ 36 | # define RDTSC_MAYBE_SUPPORTED 37 | #endif 38 | 39 | #if !defined(USE_RDTSC) && !defined(USE_CLOCK) && !defined(USE_GETTIME) 40 | # if 1 && defined(RDTSC_MAYBE_SUPPORTED) && defined(__linux__) 41 | # define USE_RDTSC 42 | # elif 1 43 | # define USE_CLOCK 44 | # else 45 | # define USE_GETTIME 46 | # endif 47 | #endif 48 | 49 | 50 | 51 | extern char timebuf[512]; 52 | extern unsigned long long int freq; 53 | 54 | #ifndef COMPILING_UTIL_C 55 | 56 | static struct timespec dur; 57 | 58 | # if defined(USE_RDTSC) && defined(__x86_64__) 59 | typedef unsigned long long int rdtsc_t; 60 | static unsigned int start_high, start_low, end_high, end_low; 61 | # define rdtsc_join(low, high) ((rdtsc_t)(low) | (((rdtsc_t)(high)) << 32)) 62 | # define TIC (rdtsc(&start_low, &start_high)) 63 | # define TOC\ 64 | do {\ 65 | rdtsc_t dur_cycles;\ 66 | double dur_seconds;\ 67 | rdtsc(&end_low, &end_high);\ 68 | dur_cycles = rdtsc_join(end_low, end_high);\ 69 | dur_cycles -= rdtsc_join(start_low, start_high);\ 70 | dur_seconds = (double)dur_cycles;\ 71 | dur_seconds /= 1000 * (double)freq;\ 72 | dur_seconds -= (double)(dur.tv_sec = (int)dur_seconds);\ 73 | dur.tv_nsec = (long int)(dur_seconds * 1000000000L);\ 74 | } while (0) 75 | static inline void 76 | rdtsc(unsigned int *low, unsigned int *high) 77 | { 78 | __asm__ __volatile__ ("rdtsc" : "=a"(*low), "=d"(*high)); 79 | } 80 | 81 | # elif defined(USE_CLOCK) 82 | static clock_t start, end; 83 | # define TIC (start = clock()) 84 | # define TOC\ 85 | do {\ 86 | end = clock();\ 87 | dur.tv_sec = (end - start) / 1000000ULL;\ 88 | dur.tv_nsec = ((end - start) % 1000000ULL) * 1000;\ 89 | } while (0) 90 | 91 | # elif defined(USE_GETTIME) 92 | static struct timespec start; 93 | # define TIC clock_gettime(CLOCK_MONOTONIC_RAW, &start) 94 | # define TOC\ 95 | do {\ 96 | clock_gettime(CLOCK_MONOTONIC_RAW, &dur);\ 97 | dur.tv_sec -= start.tv_sec;\ 98 | dur.tv_nsec -= start.tv_nsec;\ 99 | if (dur.tv_nsec < 0) {\ 100 | dur.tv_nsec += 1000000000L;\ 101 | dur.tv_sec -= 1;\ 102 | }\ 103 | } while (0) 104 | 105 | # endif 106 | 107 | 108 | # define TICKS ((unsigned long long int)(dur.tv_sec) * 1000000000ULL + (unsigned long long int)(dur.tv_nsec)) 109 | # define STIME (sprintf(timebuf, "%lli.%09li", (long long)(dur.tv_sec), dur.tv_nsec), timebuf) 110 | 111 | #endif 112 | 113 | 114 | void benchmark_init(void); 115 | -------------------------------------------------------------------------------- /config.mk: -------------------------------------------------------------------------------- 1 | # Please read INSTALL, section 'Configure libzahl'. 2 | 3 | VERSION = 1.1 4 | 5 | PREFIX = /usr/local 6 | EXECPREFIX = $(PREFIX) 7 | MANPREFIX = $(PREFIX)/share/man 8 | DOCPREFIX = $(PREFIX)/share/doc 9 | 10 | CC = cc 11 | AR = ar 12 | 13 | CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -DGOOD_RAND 14 | CFLAGS = -std=c99 -O3 -flto -Wall -pedantic 15 | LDFLAGS = -s 16 | -------------------------------------------------------------------------------- /doc/get-started.tex: -------------------------------------------------------------------------------- 1 | \chapter{Get started} 2 | \label{chap:Get started} 3 | 4 | In this chapter, you will learn the basics of libzahl. 5 | You should read the sections in order. 6 | 7 | \vspace{1cm} 8 | \minitoc 9 | 10 | 11 | % TODO add a section a linking and stuff here. 12 | 13 | 14 | \newpage 15 | \section{Initialisation} 16 | \label{sec:Initialisation} 17 | 18 | Before using libzahl, it must be initialised. When 19 | initialising, you must select a location whither libzahl 20 | long jumps on error. 21 | 22 | \begin{alltt} 23 | #include 24 | 25 | int 26 | main(void) 27 | \{ 28 | jmp_buf jmpenv; 29 | if (setjmp(jmpenv)) 30 | return 1; \textcolor{c}{/* \textrm{Exit on error} */} 31 | zsetup(jmpenv); 32 | \textcolor{c}{/* \textrm{\ldots} */} 33 | return 0; 34 | \} 35 | \end{alltt} 36 | 37 | {\tt zsetup} also initialises temporary variables used 38 | by libzahl's functions, and constants used by libzahl's 39 | functions. Furthermore, it initialises the memory pool 40 | and a stack which libzahl uses to keep track of temporary 41 | allocations that need to be pooled for use if a function 42 | fails. 43 | 44 | It is recommended to also uninitialise libzahl when you 45 | are done using it, for example before the program exits. 46 | 47 | \begin{alltt} 48 | \textcolor{c}{int 49 | main(void) 50 | \{ 51 | jmp_buf jmpenv; 52 | if (setjmp(jmpenv)) 53 | return 1; /* \textrm{Exit on error} */ 54 | zsetup(jmpenv); 55 | /* \textrm{\ldots} */} 56 | zunsetup(); 57 | \textcolor{c}{return 0; 58 | \}} 59 | \end{alltt} 60 | 61 | {\tt zunsetup} frees all memory that has been reclaimed to 62 | the memory pool, and all memory allocated by {\tt zsetup}. 63 | Note that this does not free integers that are still 64 | in use. It is possible to simply call {\tt zunsetup} 65 | directly followed by {\tt zsetup} to free all pooled 66 | memory. 67 | 68 | 69 | \newpage 70 | \section{Exceptional conditions} 71 | \label{sec:Exceptional conditions} 72 | 73 | Exceptional conditions, casually called `errors', 74 | are treated in libzahl using long jumps. 75 | 76 | \begin{alltt} 77 | int 78 | main(int argc, char *argv[]) 79 | \{ 80 | jmp_buf jmpenv; 81 | if (setjmp(jmpenv)) 82 | return 1; \textcolor{c}{/* \textrm{Exit on error} */} 83 | zsetup(jmpenv); 84 | return 0; 85 | \} 86 | \end{alltt} 87 | 88 | Just exiting on error is not a particularly good 89 | idea. Instead, you may want to print an error message. 90 | This is done with {\tt zperror}. 91 | 92 | \begin{alltt} 93 | if (setjmp(jmpenv)) \{ 94 | zperror(\textcolor{c}{*argv}); 95 | \textcolor{c}{return 1;} 96 | \} 97 | \end{alltt} 98 | 99 | \noindent 100 | {\tt zperror} works just like {\tt perror}. It 101 | outputs an error description to standard error. 102 | A line break is printed at the end of the message. 103 | If the argument passed to {\tt zperror} is neither 104 | {\tt NULL} nor an empty string, it is printed in 105 | front of the description, with a colon and a 106 | space separating the passed string and the description. 107 | For example, {\tt zperror("my-app")} may output 108 | 109 | \begin{verbatim} 110 | my-app: Cannot allocate memory 111 | \end{verbatim} 112 | 113 | libzahl also provides {\tt zerror}. Calling this 114 | function will provide you with an error code and 115 | a textual description. 116 | 117 | \begin{alltt} 118 | \textcolor{c}{if (setjmp(jmpenv)) \{} 119 | const char *description; 120 | zerror(&description); 121 | fprintf(stderr, "\%s: \%s\verb|\|n", *argv, description); 122 | \textcolor{c}{return 1;} 123 | \textcolor{c}{\}} 124 | \end{alltt} 125 | 126 | \noindent 127 | This code behaves like the example above that 128 | calls {\tt zperror}. If you are interested in the 129 | error code, you instead look at the return value. 130 | 131 | \begin{alltt} 132 | \textcolor{c}{if (setjmp(jmpenv)) \{} 133 | enum zerror e = zerror(NULL); 134 | switch (e) \{ 135 | case ZERROR_ERRNO_SET: 136 | perror(""); 137 | \textcolor{c}{return 1;} 138 | case ZERROR_0_POW_0: 139 | fprintf(stderr, "Indeterminate form: 0^0\verb|\|n"); 140 | \textcolor{c}{return 1;} 141 | case ZERROR_0_DIV_0: 142 | fprintf(stderr, "Indeterminate form: 0/0\verb|\|n"); 143 | \textcolor{c}{return 1;} 144 | case ZERROR_DIV_0: 145 | fprintf(stderr, "Do not divide by zero, dummy\verb|\|n"); 146 | \textcolor{c}{return 1;} 147 | case ZERROR_NEGATIVE: 148 | fprintf(stderr, "Undefined (negative input)\verb|\|n"); 149 | \textcolor{c}{return 1;} 150 | case ZERROR_INVALID_RADIX: 151 | fprintf(stderr, "Radix must be at least 2\verb|\|n"); 152 | \textcolor{c}{return 1;} 153 | default: 154 | zperror(""); 155 | \textcolor{c}{return 1;} 156 | \} 157 | \textcolor{c}{\}} 158 | \end{alltt} 159 | 160 | To change the point whither libzahl's functions 161 | jump, call {\tt setjmp} and {\tt zsetup} again. 162 | 163 | \begin{alltt} 164 | jmp_buf jmpenv; 165 | if (setjmp(jmpenv)) \{ 166 | \textcolor{c}{/* \textrm{\ldots} */} 167 | \} 168 | zsetup(jmpenv); 169 | \textcolor{c}{/* \textrm{\ldots} */} 170 | if (setjmp(jmpenv)) \{ 171 | \textcolor{c}{/* \textrm{\ldots} */} 172 | \} 173 | zsetup(jmpenv); 174 | \end{alltt} 175 | 176 | 177 | \newpage 178 | \section{Create an integer} 179 | \label{sec:Create an integer} 180 | 181 | To do any real work with libzahl, we need integers. The 182 | data type for a big integer in libzahl is {\tt z\_t} 183 | \psecref{sec:Integer structure}. Before a {\tt z\_t} 184 | can be assigned a value, it must be initialised. 185 | 186 | \begin{alltt} 187 | z_t a; 188 | \textcolor{c}{/* \textrm{\ldots} */ 189 | zsetup(jmpenv);} 190 | zinit(a); 191 | \textcolor{c}{/* \textrm{\ldots} */ 192 | zunsetup();} 193 | \end{alltt} 194 | 195 | \noindent 196 | {\tt zinit(a)} is actually a less cumbersome and optimised 197 | alternative to calling {\tt memset(a, 0, sizeof(z\_t))}. 198 | It sets the values of two members: {\tt .alloced} and 199 | {\tt .chars}, to 0 and {\tt NULL}. This is necessary, 200 | otherwise the memory allocated could be fooled to deallocate 201 | a false pointer, causing the program to abort. 202 | 203 | Once the reference has been initialised, you may assign it 204 | a value. The simplest way to do this is by calling 205 | 206 | \begin{alltt} 207 | void zseti(z_t a, int64_t value); 208 | \end{alltt} 209 | 210 | \noindent 211 | For example {\tt zseti(a, 1)}, assignes the value 1 to 212 | the {\tt z\_t} {\tt a}. 213 | 214 | When you are done using a big integer reference, you should 215 | call {\tt zfree} to let libzahl know that it should pool 216 | the allocation of the {\tt .chars} member. 217 | 218 | \begin{alltt} 219 | z_t a; 220 | zinit(a); 221 | \textcolor{c}{/* \textrm{\ldots} */} 222 | zfree(a); \textcolor{c}{/* \textrm{before \texttt{zunsetup}} */} 223 | \end{alltt} 224 | 225 | \noindent 226 | Instead of calling {\tt zfree(a)}, it is possible — but 227 | strongly discouraged — to call {\tt free(a->chars)}. 228 | Note however, by doing so, the allocation is not pooled 229 | for reuse. 230 | 231 | If you plan to reuse the variable later, you need to 232 | reinitialise it by calling {\tt zinit} again. 233 | 234 | Alternatives to {\tt zseti} include \psecref{sec:Assignment}: 235 | 236 | \begin{alltt} 237 | void zsetu(z_t a, uint64_t value); 238 | void zsets(z_t a, const char *value); 239 | void zset(z_t a, z_t value); \textcolor{c}{/* \textrm{copy \texttt{value} into \texttt{a}} */} 240 | \end{alltt} 241 | -------------------------------------------------------------------------------- /doc/libzahl.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt,b5paper,openright,fleqn]{book} 2 | \special{papersize=176mm,250mm} 3 | \usepackage[utf8]{inputenc} 4 | \usepackage[T1]{fontenc} 5 | \usepackage{algorithmic, algorithm, colonequals, alltt} 6 | \usepackage{amsmath, amssymb, mathtools, MnSymbol, mathrsfs, esvect, wasysym} 7 | \usepackage{tipa, color, graphicx} 8 | \usepackage{shorttoc, minitoc} 9 | \usepackage{enumitem} 10 | \usepackage[english]{babel} 11 | \selectlanguage{english} 12 | \definecolor{linkcolour}{RGB}{112, 0, 0} 13 | \definecolor{urlcolour}{RGB}{0, 0, 112} 14 | \usepackage[unicode,pdfencoding=auto]{hyperref} 15 | \hypersetup{ 16 | pdfborder={0 0 0}, 17 | colorlinks=true, 18 | linkcolor=linkcolour, 19 | urlcolor=urlcolour, 20 | linktoc=all, 21 | pdfsubject={Computer science}, 22 | pdfauthor={Mattias Andrée}, 23 | pdftitle={libzahl}, 24 | pdfkeywords={libzahl, big integer, big number, bigint, bignum, multiple-precision, arbitrary precision} 25 | } 26 | \hypersetup{linktocpage} 27 | \usepackage{makeidx} 28 | \makeindex 29 | \usepackage{geometry} 30 | \geometry{margin=1in} 31 | \usepackage{microtype} 32 | \DisableLigatures{encoding = *, family = *} % NB! disables -- and --- 33 | % I really dislike fi- and ff-ligatures, just like look so wrong. 34 | \frenchspacing % i.e. non-American spacing: i.e. no extra space after sentences, 35 | % this also means that periods do not have to be context-marked. 36 | 37 | \newcommand{\chapref}[1]{\hyperref[#1]{Chapter~\ref*{#1} [\nameref*{#1}], page \pageref*{#1}}} 38 | \newcommand{\secref}[1]{\hyperref[#1]{Section~\ref*{#1} [\nameref*{#1}], page \pageref*{#1}}} 39 | \newcommand{\appxref}[1]{\hyperref[#1]{Appendix~\ref*{#1} [\nameref*{#1}], page \pageref*{#1}}} 40 | \newcommand{\pchapref}[1]{(see \hyperref[#1]{Chapter~\ref*{#1} [\nameref*{#1}], page \pageref*{#1}})} 41 | \newcommand{\psecref}[1]{(see \hyperref[#1]{Section~\ref*{#1} [\nameref*{#1}], page \pageref*{#1}})} 42 | \newcommand{\pappxref}[1]{(see \hyperref[#1]{Appendix~\ref*{#1} [\nameref*{#1}], page \pageref*{#1}})} 43 | \definecolor{c}{rgb}{0.45, 0.45, 0.45} 44 | 45 | \begin{document} 46 | 47 | \frontmatter 48 | 49 | \title{{\Huge \bf libzahl version 1.1}} 50 | \author{} 51 | \date{\vspace{3in}} 52 | \maketitle 53 | 54 | \thispagestyle{empty} 55 | \null 56 | \vfill 57 | \noindent 58 | Copyright \copyright{} 2016 $~$ Mattias Andrée $\langle$\href{mailto:maandree@kth.se}{\texttt{maandree@kth.se}}$\rangle$ 59 | \vspace{1ex} 60 | 61 | \noindent 62 | {\small 63 | Permission to use, copy, modify, and/or distribute this document for any 64 | purpose with or without fee is hereby granted, provided that the above 65 | copyright notice and this permission notice appear in all copies.} 66 | \newpage 67 | 68 | 69 | % Conventionally, most words in a title in English should start with 70 | % uppercase. I believe that this is inconsistent stupidity, pardon my 71 | % Klatchian. There is not consensus of which words should not start 72 | % with lowercase or even if any shall start with lowercase. There is 73 | % also no consensus on how long the title should be before only the 74 | % first word should start with uppercase. It is only generally (but 75 | % not always) agreed that most words should start with uppercase and 76 | % when the title is too long only the first word start with uppercase. 77 | % I believe that is is better to stick with the Swedish convention: 78 | % It should look just like a sentience except it may not end with a 79 | % period unless that is part of an ellipsis or an abbreviation. 80 | % I would also like to use straight apostrophes, like in French, (and 81 | % reserve the curved ones for quotes), but that is just too painful in 82 | % LaTeX, so I will only be do so for French words. Most style guides 83 | % for English will be followed. They will only be broken if they are 84 | % stupid or inferior. For example, I will never write ‘CPU's’ for 85 | % plural of CPU — that's just stupid, — only for genitive, nor 86 | % will I write ‘CPUs’ for plural of CPU, because it is inferior to 87 | % ‘CPU:s’. 88 | 89 | 90 | \shorttoc{Short contents}{0} 91 | \setcounter{tocdepth}{2} 92 | \dominitoc 93 | \tableofcontents 94 | 95 | 96 | \mainmatter 97 | 98 | \input doc/what-is-libzahl.tex 99 | \input doc/libzahls-design.tex 100 | \input doc/get-started.tex 101 | \input doc/miscellaneous.tex 102 | \input doc/arithmetic.tex 103 | \input doc/bit-operations.tex 104 | \input doc/number-theory.tex 105 | \input doc/random-numbers.tex 106 | \input doc/not-implemented.tex 107 | \input doc/exercises.tex 108 | 109 | 110 | \appendix 111 | 112 | 113 | \backmatter 114 | 115 | \addcontentsline{toc}{chapter}{Index} 116 | \printindex 117 | 118 | \end{document} 119 | -------------------------------------------------------------------------------- /doc/libzahls-design.tex: -------------------------------------------------------------------------------- 1 | \chapter{libzahl's design} 2 | \label{chap:libzahl's design} 3 | 4 | In this chapter, the design of libzahl is discussed. 5 | 6 | \vspace{1cm} 7 | \minitoc 8 | 9 | 10 | \newpage 11 | \section{Memory pool} 12 | \label{sec:Memory pool} 13 | 14 | Allocating memory dynamically is an expensive operation. 15 | To improve performance, libzahl never deallocates memory 16 | before the library is uninitialised, instead it pools 17 | memory, that is no longer needed, for reuse. 18 | 19 | Because of the memory pooling, this is a pattern to the 20 | allocation sizes. In an allocation, a power of two 21 | elements, plus a few elements that are discussed in 22 | \secref{sec:Integer structure}, are allocated. That is, 23 | the number multiplied by the size of an element. 24 | Powers of two (growth factor 2) is not the most memory 25 | efficient way to do this, but it is the simplest and 26 | performance efficient. This power of two (sans the few 27 | extra elements) is used to calculate — getting the index 28 | of the only set bit — the index of the bucket in 29 | which the allocation is stored when pooled. The buckets 30 | are dynamic arrays with the growth factor 1.5. The 31 | growth factor 1.5 is often used for dynamic arrays, it 32 | is a good compromise between memory usage and performance. 33 | 34 | libzahl also avoids allocating memory by having a set 35 | of temporary variables predefined. 36 | 37 | 38 | \newpage 39 | \section{Error handling} 40 | \label{sec:Error handling} 41 | 42 | In C, it is traditional to return a sentiel value 43 | in case an error has occurred, and set the value 44 | of a global variable to describe the error that 45 | has occurred. The programmer can choose whether to 46 | check for errors, ignore errors where it does not 47 | matter, or simple ignore errors altogether and let 48 | the program eventually crash. This is a simple 49 | technique that gives the programmer a better 50 | understanding of what can happen. A great advantage 51 | C has over most programming languages. 52 | 53 | Another technique is to use long jumps on error. 54 | This technique is not too common, but is has one 55 | significant advantage. Error-checks need only be 56 | preformed where the error can first be detected. 57 | There is no need to check the return value at every 58 | function return. This leads to cleaner code, if 59 | there are many functions that can raise exceptional 60 | conditions, and greater performance under some 61 | conditions. This is why this technique is sometimes 62 | used in high-performance libraries. libzahl uses 63 | this technique. 64 | 65 | Rather than writing 66 | 67 | \begin{alltt} 68 | if (zadd(a, b, c)) 69 | goto out; 70 | \end{alltt} 71 | 72 | \noindent 73 | or a bit cleaner, if there are a lot of calls, 74 | 75 | \begin{alltt} 76 | #define TRY(...) do if (__VA_ARGS__) goto out; while (0) 77 | \textcolor{c}{/* \textrm{\ldots} */} 78 | TRY(zadd(a, b, c)); 79 | \end{alltt} 80 | 81 | \noindent 82 | we write 83 | 84 | \begin{alltt} 85 | jmp_buf env; 86 | if (setjmp(env)) 87 | goto out; 88 | zsetup(env); 89 | \textcolor{c}{/* \textrm{\ldots} */} 90 | zadd(a, b, c); 91 | \end{alltt} 92 | 93 | You only need to call {\tt setjmp} and {\tt zsetup} 94 | once, but can update the return point by calling 95 | them once more. 96 | 97 | If you don't need to check for errors, you can 98 | disable error detection at compile-time. By defining 99 | the {\tt ZAHL\_UNSAFE} C preprocessor definition 100 | when compiling libzahl, and when compiling your 101 | software that uses libzahl. 102 | 103 | 104 | \newpage 105 | \section{Integer structure} 106 | \label{sec:Integer structure} 107 | 108 | The data type used to represent a big integer with 109 | libzahl is {\tt z\_t},\footnote{This name actually 110 | violates the naming convention; it should be {\tt Z}, 111 | or {\tt Zahl} to avoid single-letter names. But this 112 | violation is common-place.} defined as 113 | 114 | \begin{alltt} 115 | typedef struct zahl z_t[1]; 116 | \end{alltt} 117 | 118 | \noindent 119 | where {\tt struct zahl} is defined as 120 | 121 | \begin{alltt} 122 | struct zahl \{ 123 | int sign; \textcolor{c}{/* \textrm{\emph{not} short for `signum'} */} 124 | size_t used; 125 | size_t alloced; \textcolor{c}{/* \textrm{short for `allocated'} */} 126 | zahl_char_t *chars; \textcolor{c}{/* \textrm{short for `characters'} */} 127 | \}; 128 | \end{alltt} 129 | 130 | \noindent 131 | where {\tt zahl\_char\_t} is defined as 132 | 133 | \begin{alltt} 134 | typedef uint64_t zahl_char_t; 135 | \end{alltt} 136 | 137 | \noindent 138 | As a user, try not to think about anything else than 139 | 140 | \begin{alltt} 141 | typedef \textcolor{c}{/* \textrm{ignore what is here} */} z_t[1]; 142 | \end{alltt} 143 | 144 | \noindent 145 | details can change in future versions of libzahl. 146 | 147 | {\tt z\_t} is defined as a single-element array. This 148 | is often called a reference, or a call-by-reference. 149 | There are some flexibility issues with this, why 150 | {\tt struct zahl} has beed added, but for most uses 151 | with big integers, it makes things simpler. Particularly, 152 | you need not work prepend {\tt \&} to variable when making 153 | function calls, but the existence of {\tt struct zahl} 154 | allows you do so if you so choose. 155 | 156 | The {\tt .sign} member, is either $-1$, 0, or 1, 157 | when the integer is negative, zero, or positive, 158 | respectively. Whenever {\tt .sign} is 0, the value 159 | of {\tt .used} and {\tt .chars} are undefined. 160 | 161 | {\tt .used} holds to the number of elements used in 162 | {\tt .chars}, and {\tt .alloced} holds the allocation 163 | side of {\tt .chars} measured in elements minus a few 164 | extra elements that are always added to the allocation. 165 | {\tt .chars} is a little-endian array of 64-bit digits, 166 | these 64-bit digits are called `characters' in libzahl. 167 | {\tt .chars} holds the absolute value of the 168 | represented value. 169 | 170 | Unless {\tt .sign} is 0, {\tt .chars} always contains 171 | four extra elements, refered to as fluff. These are 172 | merely allocated so functions can assume that they can 173 | always manipulate groups of four characters, and need 174 | not care about cases where the number of characters is 175 | not a multiple of four. There are of course a few cases 176 | when the precise number of characters is important. 177 | 178 | 179 | \newpage 180 | \section{Parameters} 181 | \label{sec:Parameters} 182 | 183 | The general order of parameters in libzahl functions 184 | are: output integers, input integers, input data, 185 | output data, parametric values. For example, in 186 | addition, the out parameter is the first parameter. 187 | But for marshalling and unmarshalling the buffer 188 | is last. For random number generation the order is: 189 | output, device, distribution, distribution parameters. 190 | Whilst the distribution parameters are big integers, 191 | they are not considered input integers. The order 192 | of the input parameters are that of the order you 193 | would write them using mathematical notation, this 194 | also holds true if you include the output parameter 195 | (as long as there is exactly one output), for example 196 | 197 | \vspace{1em} 198 | $a \gets b^c \mod d$ 199 | \vspace{1em} 200 | 201 | \noindent 202 | is written 203 | 204 | \begin{verbatim} 205 | zmodpow(a, b, c, d); 206 | \end{verbatim} 207 | 208 | \noindent 209 | or 210 | 211 | \begin{verbatim} 212 | zmodpowu(a, b, c, d); 213 | \end{verbatim} 214 | 215 | Like any self respecting bignum library, libzahl 216 | supports using the same big integer reference as 217 | for output as input, as long as all the output 218 | parameters are mutually unique. For example 219 | 220 | \begin{alltt} 221 | a += b; 222 | \end{alltt} 223 | 224 | \noindent 225 | or 226 | 227 | \begin{alltt} 228 | a = a + b; 229 | \end{alltt} 230 | 231 | \noindent 232 | is written, using libzahl, as 233 | 234 | \begin{alltt} 235 | zadd(a, a, b); 236 | \end{alltt} 237 | 238 | For commutative functions, like {\tt zadd}, the 239 | implementation is optimised to assume that this 240 | order is more likely to be used than the alternative. 241 | That is, we should, for example, write 242 | 243 | \begin{alltt} 244 | zadd(a, a, b); 245 | \end{alltt} 246 | 247 | \noindent 248 | rather than 249 | 250 | \begin{alltt} 251 | zadd(a, b, a); 252 | \end{alltt} 253 | 254 | \noindent 255 | This assumption is not made for non-commutative 256 | functions. 257 | 258 | When writting your own functions, be aware, 259 | input parameters are generally not declared {\tt const} 260 | in libzahl. Currently, some functions actually make 261 | modifications (that do not affect the value) to 262 | input parameters. 263 | -------------------------------------------------------------------------------- /doc/number-theory.tex: -------------------------------------------------------------------------------- 1 | \chapter{Number theory} 2 | \label{chap:Number theory} 3 | 4 | In this chapter, you will learn about the 5 | number theoretic functions in libzahl. 6 | 7 | \vspace{1cm} 8 | \minitoc 9 | 10 | 11 | \newpage 12 | \section{Odd or even} 13 | \label{sec:Odd or even} 14 | 15 | There are four functions available for testing 16 | the oddness and evenness of an integer: 17 | 18 | \begin{alltt} 19 | int zodd(z_t a); 20 | int zeven(z_t a); 21 | int zodd_nonzero(z_t a); 22 | int zeven_nonzero(z_t a); 23 | \end{alltt} 24 | 25 | \noindent 26 | {\tt zodd} returns 1 if {\tt a} contains an 27 | odd value, or 0 if {\tt a} contains an even 28 | number. Conversely, {\tt zeven} returns 1 if 29 | {\tt a} contains an even value, or 0 if {\tt a} 30 | contains an odd number. {\tt zodd\_nonzero} and 31 | {\tt zeven\_nonzero} behave exactly like {\tt zodd} 32 | and {\tt zeven}, respectively, but assumes that 33 | {\tt a} contains a non-zero value, if not 34 | undefined behaviour is invoked, possibly in the 35 | form of a segmentation fault; they are thus 36 | sligtly faster than {\tt zodd} and {\tt zeven}. 37 | 38 | It is discouraged to test the returned value 39 | against 1, we should always test against 0, 40 | treating all non-zero value as equivalent to 1. 41 | For clarity, we use also avoid testing that 42 | the returned value is zero, for example, rather 43 | than {\tt !zeven(a)} we write {\tt zodd(a)}. 44 | 45 | 46 | \newpage 47 | \section{Signum} 48 | \label{sec:Signum} 49 | 50 | There are two functions available for testing 51 | the sign of an integer, one of the can be used 52 | to retrieve the sign: 53 | 54 | \begin{alltt} 55 | int zsignum(z_t a); 56 | int zzero(z_t a); 57 | \end{alltt} 58 | 59 | \noindent 60 | {\tt zsignum} returns $-1$ if $a < 0$, 61 | $0$ if $a = 0$, and $+1$ if $a > 0$, that is, 62 | 63 | \vspace{1em} 64 | \( \displaystyle{ 65 | \mbox{sgn}~a = \left \lbrace \begin{array}{rl} 66 | -1 & \textrm{if}~ a < 0 \\ 67 | 0 & \textrm{if}~ a = 0 \\ 68 | +1 & \textrm{if}~ a > 0 69 | \end{array} \right . 70 | }\) 71 | \vspace{1em} 72 | 73 | \noindent 74 | It is discouraged to compare the returned value 75 | against $-1$ and $+1$; always compare against 0, 76 | for example: 77 | 78 | \begin{alltt} 79 | if (zsignum(a) > 0) "positive"; 80 | if (zsignum(a) >= 0) "non-negative"; 81 | if (zsignum(a) == 0) "zero"; 82 | if (!zsignum(a)) "zero"; 83 | if (zsignum(a) <= 0) "non-positive"; 84 | if (zsignum(a) < 0) "negative"; 85 | if (zsignum(a)) "non-zero"; 86 | \end{alltt} 87 | 88 | \noindent 89 | However, when we are doing arithmetic with the 90 | signum, we may relay on the result never being 91 | any other value than $-1$, $0$, and $+0$. 92 | For example: 93 | 94 | \begin{alltt} 95 | zset(sgn, zsignum(a)); 96 | zadd(b, sgn); 97 | \end{alltt} 98 | 99 | {\tt zzero} returns 0 if $a = 0$ or 1 if 100 | $a \neq 0$. Like with {\tt zsignum}, avoid 101 | testing the returned value against 1, rather 102 | test that the returned value is not 0. When 103 | however we are doing arithmetic with the 104 | result, we may relay on the result never 105 | being any other value than 0 or 1. 106 | 107 | 108 | \newpage 109 | \section{Greatest common divisor} 110 | \label{sec:Greatest common divisor} 111 | 112 | There is no single agreed upon definition 113 | for the greatest common divisor of two 114 | integer, that cover non-positive integers. 115 | In libzahl we define it as 116 | 117 | \vspace{1em} 118 | \( \displaystyle{ 119 | \gcd(a, b) = \left \lbrace \begin{array}{rl} 120 | -k & \textrm{if}~ a < 0, b < 0 \\ 121 | b & \textrm{if}~ a = 0 \\ 122 | a & \textrm{if}~ b = 0 \\ 123 | k & \textrm{otherwise} 124 | \end{array} \right . 125 | }\), 126 | \vspace{1em} 127 | 128 | \noindent 129 | where $k$ is the largest integer that divides 130 | both $\lvert a \rvert$ and $\lvert b \rvert$. This 131 | definion ensures 132 | 133 | \vspace{1em} 134 | \( \displaystyle{ 135 | \frac{a}{\gcd(a, b)} \left \lbrace \begin{array}{rl} 136 | > 0 & \textrm{if}~ a < 0, b < 0 \\ 137 | < 0 & \textrm{if}~ a < 0, b > 0 \\ 138 | = 1 & \textrm{if}~ b = 0, a \neq 0 \\ 139 | = 0 & \textrm{if}~ a = 0, b \neq 0 \\ 140 | \in \textbf{N} & \textrm{otherwise if}~ a \neq 0, b \neq 0 141 | \end{array} \right . 142 | }\), 143 | \vspace{1em} 144 | 145 | \noindent 146 | and analogously for $\frac{b}{\gcd(a,\,b)}$. Note however, 147 | the convension $\gcd(0, 0) = 0$ is adhered. Therefore, 148 | before dividing with $\gcd(a, b)$ you may want to check 149 | whether $\gcd(a, b) = 0$. $\gcd(a, b)$ is calculated 150 | with {\tt zgcd(a, b)}. 151 | 152 | {\tt zgcd} calculates the greatest common divisor using 153 | the Binary GCD algorithm. 154 | 155 | \vspace{1em} 156 | \hspace{-2.8ex} 157 | \begin{minipage}{\linewidth} 158 | \begin{algorithmic} 159 | \RETURN $a + b$ {\bf if} $ab = 0$ 160 | \RETURN $-\gcd(\lvert a \rvert, \lvert b \rvert)$ {\bf if} $a < 0$ \AND $b < 0$ 161 | \STATE $s \gets \max s : 2^s \vert a, b$ 162 | \STATE $u, v \gets \lvert a \rvert \div 2^s, \lvert b \rvert \div 2^s$ 163 | \WHILE{$u \neq v$} 164 | \STATE $v \leftrightarrow u$ {\bf if} $v < u$ 165 | \STATE $v \gets v - u$ 166 | \STATE $v \gets v \div 2^x$, where $x = \max x : 2^x \vert v$ 167 | \ENDWHILE 168 | \RETURN $u \cdot 2^s$ 169 | \end{algorithmic} 170 | \end{minipage} 171 | \vspace{1em} 172 | 173 | \noindent 174 | $\max x : 2^x \vert z$ is returned by {\tt zlsb(z)} 175 | \psecref{sec:Boundary}. 176 | 177 | 178 | \newpage 179 | \section{Primality test} 180 | \label{sec:Primality test} 181 | 182 | The primality of an integer can be tested with 183 | 184 | \begin{alltt} 185 | enum zprimality zptest(z_t w, z_t a, int t); 186 | \end{alltt} 187 | 188 | \noindent 189 | {\tt zptest} uses Miller–Rabin primality test, 190 | with {\tt t} runs of its witness loop, to 191 | determine whether {\tt a} is prime. {\tt zptest} 192 | returns either 193 | 194 | \begin{itemize} 195 | \item {\tt PRIME} = 2: 196 | {\tt a} is prime. This is only returned for 197 | known prime numbers: 2 and 3. 198 | 199 | \item {\tt PROBABLY\_PRIME} = 1: 200 | {\tt a} is probably a prime. The certainty 201 | will be $1 - 4^{-t}$. 202 | 203 | \item {\tt NONPRIME} = 0: 204 | {\tt a} is either composite, non-positive, or 1. 205 | It is certain that {\tt a} is not prime. 206 | \end{itemize} 207 | 208 | If and only if {\tt NONPRIME} is returned, a 209 | value will be assigned to {\tt w} — unless 210 | {\tt w} is {\tt NULL}. This will be the witness 211 | of {\tt a}'s completeness. If $a \le 1$, it 212 | is not really composite, and the value of 213 | {\tt a} is copied into {\tt w}. 214 | 215 | $\gcd(w, a)$ can be used to extract a factor 216 | of $a$. This factor is however not necessarily, 217 | and unlikely so, prime, but can be composite, 218 | or even 1. In the latter case this becomes 219 | utterly useless. Therefore using this method 220 | for prime factorisation is a bad idea. 221 | 222 | Below is pseudocode for the Miller–Rabin primality 223 | test with witness return. 224 | 225 | \vspace{1em} 226 | \hspace{-2.8ex} 227 | \begin{minipage}{\linewidth} 228 | \begin{algorithmic} 229 | \RETURN NONPRIME ($w \gets a$) {\bf if} {$a \le 1$} 230 | \RETURN PRIME {\bf if} {$a \le 3$} 231 | \RETURN NONPRIME ($w \gets 2$) {\bf if} {$2 \vert a$} 232 | \STATE $r \gets \max r : 2^r \vert (a - 1)$ 233 | \STATE $d \gets (a - 1) \div 2^r$ 234 | \STATE {\bf repeat} $t$ {\bf times} 235 | 236 | \hspace{2ex} 237 | \begin{minipage}{\linewidth} 238 | \STATE $k \xleftarrow{\$} \textbf{Z}_{a - 2} \setminus \textbf{Z}_{2}$ \textcolor{c}{\{Uniformly random assignment.\}} 239 | \STATE $x \gets k^d \mod a$ 240 | \STATE {\bf continue} {\bf if} $x = 1$ \OR $x = a - 1$ 241 | \STATE {\bf repeat} $r$ {\bf times or until} $x = 1$ \OR $x = a - 1$ 242 | 243 | \hspace{2ex} 244 | \begin{minipage}{\linewidth} 245 | \vspace{-1ex} 246 | \STATE $x \gets x^2 \mod a$ 247 | \end{minipage} 248 | \vspace{-1.5em} 249 | \STATE {\bf end repeat} 250 | \STATE {\bf if} $x = 1$ {\bf return} NONPRIME ($w \gets k$) 251 | \end{minipage} 252 | \vspace{-0.8ex} 253 | \STATE {\bf end repeat} 254 | \RETURN PROBABLY PRIME 255 | \end{algorithmic} 256 | \end{minipage} 257 | \vspace{1em} 258 | 259 | \noindent 260 | $\max x : 2^x \vert z$ is returned by {\tt zlsb(z)} 261 | \psecref{sec:Boundary}. 262 | -------------------------------------------------------------------------------- /doc/random-numbers.tex: -------------------------------------------------------------------------------- 1 | \chapter{Random numbers} 2 | \label{chap:Random numbers} 3 | 4 | TODO 5 | 6 | \vspace{1cm} 7 | \minitoc 8 | 9 | 10 | \newpage 11 | \section{Generation} 12 | \label{sec:Generation} 13 | 14 | TODO 15 | 16 | 17 | \newpage 18 | \section{Devices} 19 | \label{sec:Devices} 20 | 21 | TODO 22 | 23 | 24 | \newpage 25 | \section{Distributions} 26 | \label{sec:Distributions} 27 | 28 | TODO 29 | -------------------------------------------------------------------------------- /doc/refsheet.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{article} 2 | \usepackage[margin=1in]{geometry} 3 | \usepackage{amsmath, amssymb, mathtools} 4 | \usepackage{microtype} 5 | \DeclarePairedDelimiter\ab{\lvert}{\rvert} 6 | 7 | \newcommand{\size}{{\tt size\_t}} 8 | \newcommand{\ullong}{{\tt unsigned long long int}} 9 | 10 | \newcommand{\entry}[3]{ #2 & {\tt #1} & #3 \\ } 11 | \newcommand{\cont}[1]{ & & #1 \\ } 12 | 13 | \begin{document} 14 | 15 | 16 | 17 | {\Huge libzahl} 18 | \vspace{1ex} 19 | 20 | Unless specified otherwise, returns are {\tt void} and all parameters are of type {\tt z\_t}. 21 | \vspace{1.5em} 22 | 23 | 24 | 25 | \hspace{-2ex} 26 | \begin{tabular}{lll} 27 | 28 | 29 | 30 | \textbf{Initialisation} \\ 31 | \entry{zsetup(env)} {Initialise libzahl} {must be called before any other function is} 32 | \cont {used, {\tt env} is a {\tt jmp\_buf} all functions will} 33 | \cont {{\tt longjmp} to --- with value 1 --- on error} 34 | \entry{zunsetup()} {Deinitialise libzahl} {will free any pooled memory} 35 | \entry{zinit(a)} {Initialise $a$} {call once before use in any other function} 36 | \entry{zfree(a)} {Deinitialise $a$} {must not be used again before reinitialisation} 37 | \\ 38 | 39 | \textbf{Error handling} \\ 40 | \entry{zerror(a)} {Get error code} {returns {\tt enum zerror}, and stores} 41 | \cont {description in {\tt const char **a}} 42 | \entry{zperror(a)} {Print error description} {behaves like {\tt perror(a)}, {\tt a} is a,} 43 | \cont {possibly {\tt NULL} or $\varepsilon$, {\tt const char *}} 44 | %\\ 45 | 46 | \textbf{Arithmetic} \\ 47 | \entry{zadd(a, b, c)} {$a \gets b + c$} {} 48 | \entry{zsub(a, b, c)} {$a \gets b - c$} {} 49 | \entry{zmul(a, b, c)} {$a \gets b \cdot c$} {} 50 | \entry{zmodmul(a, b, c, d)} {$a \gets b \cdot c \mod d$} {$0 \le a~\mbox{sgn}~bc < \ab{d}$} 51 | \entry{zdiv(a, b, c)} {$a \gets b / c$} {rounded towards zero} 52 | \entry{zdivmod(a, b, c, d)} {$a \gets c / d$} {rounded towards zero} 53 | \entry{zdivmod(a, b, c, d)} {$b \gets c \mod d$} {$0 \le b~\mbox{sgn}~c < \ab{d}$} 54 | \entry{zmod(a, b, c)} {$a \gets b \mod c$} {$0 \le a~\mbox{sgn}~b < \ab{c}$} 55 | %\entry{zdiv\_exact(a, b, c)} {$a \gets b / c$} {assumes $c \vert d$} 56 | \entry{zsqr(a, b)} {$a \gets b^2$} {} 57 | \entry{zmodsqr(a, b, c)} {$a \gets b^2 \mod c$} {$0 \le a < \ab{c}$} 58 | \entry{zsqr(a, b)} {$a \gets b^2$} {} 59 | \entry{zpow(a, b, c)} {$a \gets b^c$} {} 60 | \entry{zpowu(a, b, c)} {$a \gets b^c$} {{\tt c} is an \ullong{}} 61 | \entry{zmodpow(a, b, c, d)} {$a \gets b^c \mod d$} {$0 \le a~\mbox{sgn}~b^c < \ab{d}$} 62 | \entry{zmodpowu(a, b, c, d)} {$a \gets b^c \mod d$} {ditto, {\tt c} is an \ullong{}} 63 | \entry{zabs(a, b)} {$a \gets \ab{b}$} {} 64 | \entry{zneg(a, b)} {$a \gets -b$} {} 65 | \\ 66 | 67 | \textbf{Assignment} \\ 68 | \entry{zset(a, b)} {$a \gets b$} {} 69 | \entry{zseti(a, b)} {$a \gets b$} {{\tt b} is an {\tt int64\_t}} 70 | \entry{zsetu(a, b)} {$a \gets b$} {{\tt b} is a {\tt uint64\_t}} 71 | \entry{zsets(a, b)} {$a \gets b$} {{\tt b} is a decimal {\tt const char *}} 72 | %\entry{zsets\_radix(a, b, c)} {$a \gets b$} {{\tt b} is a radix $c$ {\tt const char *},} 73 | %\cont {{\tt c} is an \ullong{}} 74 | \entry{zswap(a, b)} {$a \leftrightarrow b$} {} 75 | \\ 76 | 77 | \textbf{Comparison} \\ 78 | \entry{zcmp(a, b)} {Compare $a$ and $b$} {returns {\tt int} $\mbox{sgn}(a - b)$} 79 | \entry{zcmpi(a, b)} {Compare $a$ and $b$} {ditto, {\tt b} is an {\tt int64\_t}} 80 | \entry{zcmpu(a, b)} {Compare $a$ and $b$} {ditto, {\tt b} is a {\tt uint64\_t}} 81 | \entry{zcmpmag(a, b)} {Compare $\ab{a}$ and $\ab{b}$} {returns {\tt int} $\mbox{sgn}(\ab{a} - \ab{b})$} 82 | \\ 83 | 84 | 85 | 86 | \end{tabular} 87 | \newpage 88 | \hspace{-2ex} 89 | \begin{tabular}{lll} 90 | 91 | 92 | 93 | \textbf{Bit operation} \\ 94 | \entry{zand(a, b, c)} {$a \gets b \wedge c$} {bitwise} 95 | \entry{zor(a, b, c)} {$a \gets b \vee c$} {bitwise} 96 | \entry{zxor(a, b, c)} {$a \gets b \oplus c$} {bitwise} 97 | \entry{znot(a, b, c)} {$a \gets \lnot b$} {bitwise, cut at highest set bit} 98 | \entry{zlsh(a, b, c)} {$a \gets b \cdot 2^c$} {{\tt c} is a \size{}} 99 | \entry{zrsh(a, b, c)} {$a \gets b / 2^c$} {ditto, rounded towards zero} 100 | \entry{ztrunc(a, b, c)} {$a \gets b \mod 2^c$} {ditto, $a$ shares signum with $b$} 101 | \entry{zbits(a)} {Get number of used bits} {returns \size{}, 1 if $a = 0$} 102 | \entry{zlsb(a)} {Get index of lowest set bit} {returns \size{}, {\tt SIZE\_MAX} if $a = 0$} 103 | \entry{zbtest(a, b)} {Is bit $b$ in $a$ set?} {{\tt b} is a \size{}, returns {\tt int}} 104 | \entry{zbset(a, b, c, 1)} {$a \gets b$, set bit $c$} {{\tt c} is a \size{}} 105 | \entry{zbset(a, b, c, 0)} {$a \gets b$, clear bit $c$} {ditto} 106 | \entry{zbset(a, b, c, -1)} {$a \gets b$, flip bit $c$} {ditto} 107 | \entry{zsplit(a, b, c, d)} {$a \gets c / 2^d$} {{\tt d} is a \size{}, rounded towards zero} 108 | \entry{zsplit(a, b, c, d)} {$b \gets c \mod 2^d$} {ditto, $b$ shares signum with $c$} 109 | \\ 110 | 111 | \textbf{Conversion to string} \\ 112 | \entry{zstr(a, b, c)} {Convert $a$ to decimal} {returns the resulting {\tt const char *}} 113 | \cont {--- {\tt b} unless {\tt b} is 114 | {\tt NULL}, --- $c$ must be} 115 | \cont {either 0 or at least the length of the} 116 | \cont {resulting string but at most the} 117 | \cont {allocation size of {\tt b} minus 1} 118 | %\entry{zstr\_radix(a, b, c, d)} {Convert $a$ to radix $d$} {ditto, {\tt d} is an \ullong{}} 119 | \entry{zstr\_length(a, b)} {Get string length of $a$} {returns \size{} length of $a$ in radix $b$} 120 | \\ 121 | 122 | \textbf{Marshallisation} \\ 123 | \entry{zsave(a, b)} {Marshal $a$ into $b$} {returns \size{} number of saved bytes,} 124 | \cont {{\tt b} is a {\tt void *}} 125 | \entry{zsave(a, NULL)} {Get marshal-size of $a$} {returns \size{}} 126 | \entry{zload(a, b)} {Unmarshal $a$ from $b$} {returns \size{} number of read bytes,} 127 | \cont {{\tt b} is a {\tt const void *}} 128 | %\\ 129 | 130 | \textbf{Number theory} \\ 131 | \entry{zsignum(a, b)} {$a \gets \mbox{sgn}~b$} {} 132 | \entry{zeven(a)} {Is $a$ even?} {returns {\tt int} 1 (true) or 0 (false)} 133 | \entry{zeven\_nonzero(a)} {Is $a$ even?} {ditto, assumes $a \neq 0$} 134 | \entry{zodd(a)} {Is $a$ odd?} {returns {\tt int} 1 (true) or 0 (false)} 135 | \entry{zodd\_nonzero(a)} {Is $a$ odd?} {ditto, assumes $a \neq 0$} 136 | \entry{zzero(a)} {Is $a$ zero?} {returns {\tt int} 1 (true) or 0 (false)} 137 | \entry{zgcd(a, b, c)} {$a \gets \gcd(c, b)$} {$a < 0$ if $b < 0 \wedge c < 0$} 138 | \entry{zptest(a, b, c)} {Is $b$ a prime?} {$c$ runs of Miller--Rabin, returns} 139 | \cont {{\tt enum zprimality} {\tt NONPRIME} (0)} 140 | \cont {(and stores the witness in {\tt a} unless} 141 | \cont {{\tt a} is {\tt NULL}), {\tt PROBABLY\_PRIME} (1), or} 142 | \cont {{\tt PRIME} (2)} 143 | %\\ 144 | 145 | \textbf{Randomness} \\ 146 | \entry{zrand(a, b, UNIFORM, d)} {$a \xleftarrow{\$} \textbf{Z}_d$} 147 | {{\tt b} is a {\tt enum zranddev}, e.g.} 148 | \cont {{\tt DEFAULT\_RANDOM}, {\tt FASTEST\_RANDOM}} 149 | \\ 150 | 151 | 152 | 153 | \end{tabular} 154 | \end{document} 155 | -------------------------------------------------------------------------------- /examples/01-sum.c: -------------------------------------------------------------------------------- 1 | /* Calculates the sum of $@ */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int 9 | main(int argc, char *argv[]) 10 | { 11 | z_t sum, term; 12 | jmp_buf env; 13 | char *buf; 14 | int i; 15 | 16 | if (setjmp(env)) 17 | return zperror(argv[0]), 1; 18 | 19 | zsetup(env); 20 | zinit(sum); 21 | zinit(term); 22 | zsetu(sum, 0); 23 | 24 | for (i = 1; i < argc; i++) { 25 | zsets(term, argv[i]); 26 | zadd(sum, sum, term); 27 | } 28 | 29 | printf("%s\n", buf = zstr(sum, NULL, 0)); 30 | free(buf); 31 | 32 | zfree(term); 33 | zfree(sum); 34 | zunsetup(); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /examples/02-prod.c: -------------------------------------------------------------------------------- 1 | /* Calculates the product of $@ */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int 9 | main(int argc, char *argv[]) 10 | { 11 | z_t prod, factor; 12 | jmp_buf env; 13 | char *buf; 14 | int i; 15 | 16 | if (setjmp(env)) 17 | return zperror(argv[0]), 1; 18 | 19 | zsetup(env); 20 | zinit(prod); 21 | zinit(factor); 22 | zsetu(prod, 1); 23 | 24 | for (i = 1; i < argc; i++) { 25 | zsets(factor, argv[i]); 26 | zmul(prod, prod, factor); 27 | } 28 | 29 | printf("%s\n", buf = zstr(prod, NULL, 0)); 30 | free(buf); 31 | 32 | zfree(factor); 33 | zfree(prod); 34 | zunsetup(); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /examples/03-avg.c: -------------------------------------------------------------------------------- 1 | /* Calculates the truncated average of $@ */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int 9 | main(int argc, char *argv[]) 10 | { 11 | z_t sum, term; 12 | jmp_buf env; 13 | char *buf; 14 | int i; 15 | 16 | if (setjmp(env)) 17 | return zperror(argv[0]), 1; 18 | 19 | zsetup(env); 20 | zinit(sum); 21 | zinit(term); 22 | zsetu(sum, 0); 23 | 24 | for (i = 1; i < argc; i++) { 25 | zsets(term, argv[i]); 26 | zadd(sum, sum, term); 27 | } 28 | zseti(term, argc); 29 | zdiv(sum, sum, term); 30 | 31 | printf("%s\n", buf = zstr(sum, NULL, 0)); 32 | free(buf); 33 | 34 | zfree(term); 35 | zfree(sum); 36 | zunsetup(); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /examples/04-median.c: -------------------------------------------------------------------------------- 1 | /* Calculates the median of $@ */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int 9 | main(int argc, char *argv[]) 10 | { 11 | struct zahl *values; 12 | z_t med, medmod; 13 | jmp_buf env; 14 | char *buf, *argv0; 15 | int i, j; 16 | 17 | argv0 = *argv++, argc--; 18 | 19 | if (!argc) { 20 | fprintf(stderr, 21 | "%s: cannot calculate median of the empty bag\n", 22 | argv0); 23 | return 1; 24 | } 25 | 26 | values = calloc(argc, sizeof(*values)); 27 | if (!values) 28 | return perror(argv0), 1; 29 | 30 | if (setjmp(env)) 31 | return zperror(argv0), 1; 32 | 33 | zsetup(env); 34 | zinit(med); 35 | zinit(medmod); 36 | 37 | /* Since `values` where allocated with 38 | * `calloc` it is already cleared and 39 | * `zinit` is not necessary. */ 40 | 41 | for (i = 0; i < argc; i++) 42 | zsets(&values[i], argv[i]); 43 | 44 | qsort(values, argc, sizeof(*values), 45 | (int (*)(const void *, const void *))zcmp); 46 | i = argc / 2; 47 | j = i - !(argc & 1); 48 | zadd(med, &values[i], &values[j]); 49 | zsetu(medmod, 2); 50 | zdivmod(med, medmod, med, medmod); 51 | 52 | printf("%s%s\n", buf = zstr(med, NULL, 0), 53 | (const char *[]){"", ".5"}[zodd(medmod)]); 54 | free(buf); 55 | 56 | zfree(medmod); 57 | zfree(med); 58 | for (i = 0; i < argc; i++) 59 | zfree(&values[i]); 60 | free(values); 61 | zunsetup(); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /man/libzahl.7: -------------------------------------------------------------------------------- 1 | .TH LIBZAHL 7 libzahl 2 | .SH NAME 3 | libzahl - Big integer library 4 | .SH ETYMOLOGY 5 | The bold uppercase \(aqZ\(aq which represents the 6 | set of all integers is derived from the german word 7 | \(aqZahlen\(aq, whose singular is \(aqZahl\(aq. 8 | .SH DESCRIPTION 9 | .B libzahl 10 | is a C library for arbitrary size integers, that 11 | aims to be usable for robust programs, and be 12 | fast. 13 | .P 14 | .B libzahl 15 | will accomplish this by using long jumps when an 16 | error is detected, rather than letting the caller 17 | also perform a check. This shall make the code in 18 | the user program cleaner too. 19 | .B libzahl 20 | will use dedicated temporary bignum integers whether 21 | possible, and necessary, for its internal calculations. 22 | .B libzahl 23 | will not deallocate allocations, but rather cache 24 | them for reuse. 25 | .P 26 | With the exception of functions working with strings, 27 | all output parameters are before the input parameters. 28 | .P 29 | Like any self-respecting big number library, libzahl 30 | supports assign values to variables that are also 31 | input variables. However, keep in mind that commutative 32 | functions are optimised for the first operand to also 33 | be the output over the second operand to also be the 34 | input. For example, \fIzadd(a,a,b)\fP should be faster 35 | than \fIzadd(a,b,a)\fP, although both are supported. 36 | Whether or not the function believe that it is more 37 | likely to occur that the input variables are different 38 | that the output variable than the output variable 39 | being the first input variable depends on the function. 40 | Some functions are implemented to believe that the 41 | first is more likely, other fucntions are implemented 42 | to believe that the latter is more likely. 43 | .SH RATIONALE 44 | GMP MP cannot be used for robust programs. LibTomMath 45 | is too slow, probably because of all memory allocations, 46 | and has an nonintuitive API. Hebimath is promising, but 47 | I think it can be done better. 48 | .SH NOTES 49 | .B libzahl 50 | is currently not thread-safe. 51 | .P 52 | You are strongly discouraged from using 53 | .B libzahl 54 | for cryptographic applications. Instead, use a library 55 | specifically targeting cryptography, otherwise, your 56 | program may be subject to side-channel attacks such as 57 | timing attacks, power-monitoring attacks, electromagnetic 58 | attacks, acoustic cryptanalysis, and data remanence 59 | attacks. 60 | .B libzahl 61 | is known to be susceptible to timing attacks and data 62 | remanence attacks. 63 | .SH SEE ALSO 64 | .BR zsetup (3) 65 | -------------------------------------------------------------------------------- /man/zabs.3: -------------------------------------------------------------------------------- 1 | .TH ZABS 3 libzahl 2 | .SH NAME 3 | zabs - Calculate the absolute value of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zabs(z_t \fIa\fP, z_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zabs 12 | calculates the absolute value of 13 | .I b 14 | and stores the result in 15 | .IR a . 16 | That is, 17 | .I a 18 | gets 19 | .RI | b |. 20 | .P 21 | It is safe to call 22 | .B zabs 23 | with non-unique parameters. 24 | .SH SEE ALSO 25 | .BR zset (3), 26 | .BR zstr (3), 27 | .BR zadd (3), 28 | .BR zsub (3), 29 | .BR zmul (3), 30 | .BR zdiv (3), 31 | .BR zmod (3), 32 | .BR zneg (3), 33 | .BR zpow (3) 34 | -------------------------------------------------------------------------------- /man/zadd.3: -------------------------------------------------------------------------------- 1 | .TH ZADD 3 libzahl 2 | .SH NAME 3 | zadd - Calculate the sum of two big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zadd(z_t \fIsum\fP, z_t \fIaugend\fP, z_t \fIaddend\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zadd 12 | calculates the sum of a 13 | .I augend 14 | and a 15 | .IR addend , 16 | and stores the result in 17 | .IR sum . 18 | That is, 19 | .I sum 20 | gets 21 | .I augend 22 | + 23 | .IR addend . 24 | .P 25 | It is safe to call 26 | .B zadd 27 | with non-unique parameters. 28 | .SH SEE ALSO 29 | .BR zstr (3), 30 | .BR zsub (3), 31 | .BR zmul (3), 32 | .BR zdiv (3), 33 | .BR zmod (3), 34 | .BR zneg (3), 35 | .BR zabs (3), 36 | .BR zpow (3) 37 | -------------------------------------------------------------------------------- /man/zand.3: -------------------------------------------------------------------------------- 1 | .TH ZAND 3 libzahl 2 | .SH NAME 3 | zand - Calculate the bitwise AND of two big integers 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zand(z_t \fIa\fP, z_t \fIb\fP, z_t \fIc\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zand 12 | calculates the bitwise AND of 13 | .I b 14 | and 15 | .IR c , 16 | and stores the result in 17 | .IR a . 18 | .P 19 | It is safe to call 20 | .B zand 21 | with non-unique parameters. 22 | .SH SEE ALSO 23 | .BR zor (3), 24 | .BR zxor (3), 25 | .BR znot (3), 26 | .BR zlsh (3), 27 | .BR zrsh (3), 28 | .BR zsplit (3), 29 | .BR zbtest (3), 30 | .BR zbset (3), 31 | .BR zlsb (3), 32 | .BR zbits (3) 33 | -------------------------------------------------------------------------------- /man/zbits.3: -------------------------------------------------------------------------------- 1 | .TH ZBITS 3 libzahl 2 | .SH NAME 3 | zbits - Count used bits in a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | size_t zbits(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zbits 12 | calculates the bit-size of 13 | .IR a . 14 | If 15 | .I a 16 | is zero the bit-size is 1. 17 | .SH RETURN VALUE 18 | .B zbits 19 | returns the number of bits requires 20 | to represent 21 | .I a 22 | \(em 1 plus the floored binary logarithm of the 23 | absolute value of 24 | .I a 25 | \(em or 1 if 26 | .I a 27 | is zero. 28 | .SH RATIONALE 29 | .B zbits 30 | returns 1 rather than 0 if 31 | .B a 32 | is zero, this is to avoid off-by-one errors 33 | and it is the number of digits requires to 34 | write the number in binary. You will see this 35 | in corresponding functions in other libraries. 36 | .SH SEE ALSO 37 | .BR zlsb (3), 38 | .BR zzero (3), 39 | .BR zstr_length (3) 40 | -------------------------------------------------------------------------------- /man/zbset.3: -------------------------------------------------------------------------------- 1 | .TH ZBSET 3 libzahl 2 | .SH NAME 3 | zbset - Set, clear, or flip a bit in a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zbset(z_t \fIa\fP, z_t \fIb\fP, size_t \fIindex\fP, int \fIset\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zbset 12 | either sets, clears, or flips the bit with the selected 13 | .I index 14 | in 15 | .IR b , 16 | and stores the result in 17 | .IR a . 18 | .P 19 | The bit is set if 20 | .IR "(set>0)" , 21 | clear if 22 | .IR "(set==0)" , 23 | and flipped if 24 | .IR "(set<0)" . 25 | .P 26 | It is safe to call 27 | .B zbset 28 | with non-unique parameters. 29 | .SH SEE ALSO 30 | .BR zbtest (3), 31 | .BR zand (3), 32 | .BR zor (3), 33 | .BR zxor (3), 34 | .BR znot (3), 35 | .BR zlsh (3), 36 | .BR zrsh (3), 37 | .BR zsplit (3), 38 | .BR zlsb (3), 39 | .BR zbits (3) 40 | -------------------------------------------------------------------------------- /man/zbtest.3: -------------------------------------------------------------------------------- 1 | .TH ZBTEST 3 libzahl 2 | .SH NAME 3 | zbtest - Test a bit in a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zbtest(z_t \fIa\fP, size_t \fIindex\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zbtest 12 | returns whether the bit with the specified 13 | .I index 14 | is set in 15 | .IR a . 16 | .SH RETURN VALUE 17 | .B zbtest 18 | returns 1 if the bit is set, or 0 otherwise. 19 | .SH SEE ALSO 20 | .BR zbset (3), 21 | .BR zand (3), 22 | .BR zor (3), 23 | .BR zxor (3), 24 | .BR znot (3), 25 | .BR zlsh (3), 26 | .BR zrsh (3), 27 | .BR zsplit (3), 28 | .BR zlsb (3), 29 | .BR zbits (3) 30 | -------------------------------------------------------------------------------- /man/zcmp.3: -------------------------------------------------------------------------------- 1 | .TH ZCMP 3 libzahl 2 | .SH NAME 3 | zcmp - Compare two big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zcmp(z_t \fIa\fP, z_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zcmp 12 | compares 13 | .I a 14 | and 15 | .IR b . 16 | .SH RETURN VALUE 17 | .B zcmp 18 | returns -1 if 19 | .I a 20 | is less than 21 | .IR b , 22 | 0 if 23 | .I a 24 | is equal to 25 | .IR b , 26 | and +1 if 27 | .I a 28 | is greater than 29 | .IR b . 30 | .SH SEE ALSO 31 | .BR zcmpi (3), 32 | .BR zcmpu (3), 33 | .BR zcmpmag (3) 34 | -------------------------------------------------------------------------------- /man/zcmpi.3: -------------------------------------------------------------------------------- 1 | .TH ZCMPI 3 libzahl 2 | .SH NAME 3 | zcmpi - Compare a big integer and a signed integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zcmpi(z_t \fIa\fP, int64_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zcmpi 12 | compares 13 | .I a 14 | and 15 | .IR b . 16 | .SH RETURN VALUE 17 | .B zcmpi 18 | returns -1 if 19 | .I a 20 | is less than 21 | .IR b , 22 | 0 if 23 | .I a 24 | is equal to 25 | .IR b , 26 | and +1 if 27 | .I a 28 | is greater than 29 | .IR b . 30 | .SH SEE ALSO 31 | .BR zcmp (3), 32 | .BR zcmpu (3), 33 | .BR zcmpmag (3) 34 | -------------------------------------------------------------------------------- /man/zcmpmag.3: -------------------------------------------------------------------------------- 1 | .TH ZCMPMAG 3 libzahl 2 | .SH NAME 3 | zcmpmag - Compare the absolute values of two big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zcmpmag(z_t \fIa\fP, z_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zcmpmag 12 | compares the absolute value of 13 | .I a 14 | and the absolute value of 15 | .IR b . 16 | .SH RETURN VALUE 17 | .B zcmpmag 18 | returns -1 if 19 | .RI | a | 20 | is less than 21 | .RI | b |, 22 | 0 if 23 | .RI | a | 24 | is equal to 25 | .RI | b |, 26 | and +1 qif 27 | .RI | a | 28 | is greater than 29 | .RI | b |. 30 | .SH SEE ALSO 31 | .BR zcmp (3), 32 | .BR zcmpi (3), 33 | .BR zcmpu (3) 34 | -------------------------------------------------------------------------------- /man/zcmpu.3: -------------------------------------------------------------------------------- 1 | .TH ZCMPU 3 libzahl 2 | .SH NAME 3 | zcmpu - Compare a big integer and an unsigned integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zcmpu(z_t \fIa\fP, uint64_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zcmpu 12 | compares 13 | .I a 14 | and 15 | .IR b . 16 | .SH RETURN VALUE 17 | .B zcmpu 18 | returns -1 if 19 | .I a 20 | is less than 21 | .IR b , 22 | 0 if 23 | .I a 24 | is equal to 25 | .IR b , 26 | and +1 if 27 | .I a 28 | is greater than 29 | .IR b . 30 | .SH SEE ALSO 31 | .BR zcmp (3), 32 | .BR zcmpi (3), 33 | .BR zcmpmag (3) 34 | -------------------------------------------------------------------------------- /man/zdiv.3: -------------------------------------------------------------------------------- 1 | .TH ZDIV 3 libzahl 2 | .SH NAME 3 | zdiv - Calculate the quotient of two big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zdiv(z_t \fIquotient\fP, z_t \fIdividend\fP, z_t \fIdivisor\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zdiv 12 | calculates the truncated quotient of a 13 | .I dividend 14 | and a 15 | .IR divisor , 16 | and stores the result in 17 | .IR quotient . 18 | That is, 19 | .I quotient 20 | gets 21 | .I dividend 22 | / 23 | .IR divisor . 24 | .P 25 | It is safe to call 26 | .B zdiv 27 | with non-unique parameters. 28 | .SH RATIONALE 29 | .B zdiv 30 | rounds toward zero because this is what you expect 31 | from the C programming language and is most often 32 | what you want to do when rounding downwards. Note 33 | however, this is not the same things as floored 34 | division which is used in some programming languages 35 | and some libraries. 36 | .SH SEE ALSO 37 | .BR zdivmod (3), 38 | .BR zstr (3), 39 | .BR zadd (3), 40 | .BR zsub (3), 41 | .BR zmul (3), 42 | .BR zmod (3), 43 | .BR zneg (3), 44 | .BR zabs (3), 45 | .BR zpow (3) 46 | -------------------------------------------------------------------------------- /man/zdivmod.3: -------------------------------------------------------------------------------- 1 | .TH ZDIVMOD 3 libzahl 2 | .SH NAME 3 | zdivmod - Calculate the quotient and the remainder of two big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zdivmod(z_t \fIquotient\fP, z_t \fIremainder\fP, z_t \fIdividend\fP, z_t \fIdivisor\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zdivmod 12 | calculates the truncated quotient and the remainder of a 13 | .I dividend 14 | and a 15 | .IR divisor , 16 | and stores the truncated quotient in 17 | .I quotient 18 | and the remainder in 19 | .IR remainder . 20 | That is, 21 | .I quotient 22 | gets 23 | .I dividend 24 | / 25 | .I divisor 26 | and 27 | .I remainder 28 | gets 29 | .I dividend 30 | Mod 31 | .IR divisor . 32 | .P 33 | It is safe to call 34 | .B zdivmod 35 | with non-unique parameters, 36 | except it is 37 | .I not 38 | safe to call 39 | .B zdivmod with 40 | .IR "(quotient==remainder)" . 41 | .P 42 | See 43 | .BR zmod (3) 44 | for details on modulation. 45 | .SH RATIONALE 46 | Calculating the remainder requires calculating division to 47 | be performed, and performing a division gives the remainder 48 | for free. It is often useful to calculate both. 49 | .SH SEE ALSO 50 | .BR zstr (3), 51 | .BR zadd (3), 52 | .BR zsub (3), 53 | .BR zmul (3), 54 | .BR zdiv (3), 55 | .BR zmod (3), 56 | .BR zneg (3), 57 | .BR zabs (3), 58 | .BR zpow (3) 59 | -------------------------------------------------------------------------------- /man/zerror.3: -------------------------------------------------------------------------------- 1 | .TH ZERROR 3 libzahl 2 | .SH NAME 3 | zerror - Get the error that caused a jump to the jmp_buf passed to zsetup 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | enum zerror zerror(const char **\fIdesc\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zerror 12 | shall return the error that caused a libzahl 13 | function to perform a long jump to the point 14 | specified to 15 | .BR zsetup (3). 16 | If 17 | .I desc 18 | is not 19 | .BR 0 , 20 | a textual description is set stored in 21 | .IR *desc . 22 | This string may be changed by a subsequent 23 | call to 24 | .BR strerror (3), 25 | .BR perror (3), 26 | .BR zperror (3), 27 | and similar functions. 28 | .P 29 | Currently available 30 | .B "enum zerror" 31 | values are: 32 | .P 33 | .TP 34 | .B ZERROR_ERRNO_SET 35 | The error is stored in 36 | .IR errno . 37 | (The error may not be stored in 38 | .I errno 39 | until this function is called.) 40 | .TP 41 | .B ZERROR_0_POW_0 42 | An attempt to calculate the zeroth power of zero was made. 43 | This is on indeterminate form and cannot be calculated. 44 | The closest matching 45 | .I errno 46 | value is 47 | .BR EDOM . 48 | .TP 49 | .B ZERROR_0_DIV_0 50 | An attempt to divide zero by zero was made. 51 | This is on indeterminate form and cannot be calculated. 52 | The closest matching 53 | .I errno 54 | value is 55 | .BR EDOM . 56 | .TP 57 | .B ZERROR_DIV_0 58 | An attempt to divide a non-zero value by zero was made. 59 | This is undefined and cannot be calculated. 60 | This occurs if a divisor or a modulator is zero, or if 61 | zero is raised to a negative number. 62 | The closest matching 63 | .I errno 64 | value is 65 | .BR EDOM . 66 | .TP 67 | .B ZERROR_NEGATIVE 68 | A function argument that must not be negative was negative. 69 | The closest matching 70 | .I errno 71 | values is 72 | .B EDOM 73 | and 74 | .BR EINVAL . 75 | .TP 76 | .B ZERROR_INVALID_RADIX 77 | A radix less than 2 was selected, which is invalid because, 78 | radix 0 is impossible as there would be no digits, and radix 79 | 1 is impossible because only the value 0 can be represented 80 | in radix 1. The closest matching 81 | .I errno 82 | values is 83 | .BR EINVAL . 84 | .SH RETURN VALUE 85 | .B zerror 86 | returns the error that caused libzahl a function to fail. 87 | .SH NOTES 88 | .I errno 89 | is only set if 90 | .B ZERROR_ERRNO_SET 91 | is returned. 92 | .SH SEE ALSO 93 | .BR zperror (3) 94 | -------------------------------------------------------------------------------- /man/zeven.3: -------------------------------------------------------------------------------- 1 | .TH ZEVEN 3 libzahl 2 | .SH NAME 3 | zeven - Check whether a big integer is even 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zeven(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zeven 12 | checks whether 13 | .I a 14 | is even. 15 | .SH RETURN VALUE 16 | .B zeven 17 | returns 1 if 18 | .I a 19 | is even, and 0 otherwise. 20 | .SH SEE ALSO 21 | .BR zodd (3), 22 | .BR zeven_nonzero (3), 23 | .BR zzero (3), 24 | .BR zsignum (3), 25 | .BR zcmp (3) 26 | -------------------------------------------------------------------------------- /man/zeven_nonzero.3: -------------------------------------------------------------------------------- 1 | .TH ZEVEN_NONZERO 3 libzahl 2 | .SH NAME 3 | zeven_nonzero - Check whether a non-zero big integer is even 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zeven_nonzero(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zeven_nonzero 12 | checks whether 13 | .I a 14 | is even. 15 | .P 16 | Undefined behaviour is invoked if 17 | .I a 18 | is zero. 19 | .SH RETURN VALUE 20 | .B zeven_nonzero 21 | returns 1 if 22 | .I a 23 | is even, and 0 otherwise. 24 | .SH SEE ALSO 25 | .BR zeven (3), 26 | .BR zodd_nonzero (3), 27 | .BR zzero (3), 28 | .BR zsignum (3), 29 | .BR zcmp (3) 30 | -------------------------------------------------------------------------------- /man/zfree.3: -------------------------------------------------------------------------------- 1 | .TH ZFREE 3 libzahl 2 | .SH NAME 3 | zfree - Cache an allocation for reuse 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zfree(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zfree 12 | caches the memory stored in 13 | .I a 14 | for reuse. 15 | .I a 16 | must not be used again until 17 | .BR zinit (3), 18 | is called for it again. 19 | .SH SEE ALSO 20 | .BR zinit (3), 21 | .BR zswap (3) 22 | -------------------------------------------------------------------------------- /man/zgcd.3: -------------------------------------------------------------------------------- 1 | .TH ZGCD 3 libzahl 2 | .SH NAME 3 | zgcd - Calculates the greatest common divisor 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zgcd(z_t \fIgcd\fP, z_t \fIa\fP, z_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zgcd 12 | calculates the greatest common divisor 13 | between 14 | .I a 15 | and 16 | .I b 17 | and stores the result in 18 | .IR gcd . 19 | .SH SEE ALSO 20 | .BR zdiv (3) 21 | -------------------------------------------------------------------------------- /man/zinit.3: -------------------------------------------------------------------------------- 1 | .TH ZINIT 3 libzahl 2 | .SH NAME 3 | zinit - Prepare a bit integer for use. 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zinit(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zinit 12 | initializes the big integer 13 | .I a 14 | so that it can be used in other function calls. 15 | .P 16 | .B z_t 17 | is defined as 18 | .P 19 | .nf 20 | typedef struct zahl { 21 | /* You should not care about what is 22 | * inside this struct. It could change 23 | * in the future. */ 24 | } z_t[1]; 25 | .fi 26 | .SH SEE ALSO 27 | .BR zfree (3), 28 | .BR zswap (3), 29 | .BR zsave (3), 30 | .BR zsignum (3), 31 | .BR zeven (3), 32 | .BR zset (3), 33 | .BR zcmp (3), 34 | .BR zgcd (3), 35 | .BR zptest (3), 36 | .BR zrand (3), 37 | .BR zbits (3), 38 | .BR zlsb (3), 39 | .BR zbtest (3), 40 | .BR zbset (3), 41 | .BR zand (3), 42 | .BR zor (3), 43 | .BR zxor (3), 44 | .BR znot (3), 45 | .BR zlsh (3), 46 | .BR zrsh (3), 47 | .BR ztrunc (3), 48 | .BR zsplit (3), 49 | .BR zadd (3), 50 | .BR zsub (3), 51 | .BR zmul (3), 52 | .BR zdiv (3), 53 | .BR zmod (3), 54 | .BR zneg (3), 55 | .BR zabs (3), 56 | .BR zpow (3) 57 | -------------------------------------------------------------------------------- /man/zload.3: -------------------------------------------------------------------------------- 1 | .TH ZLOAD 3 libzahl 2 | .SH NAME 3 | zload - Unmarshal a big integer from a buffer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | size_t zload(z_t \fIa\fP, const void *\fIbuf\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zload 12 | unmarshals a big integer from 13 | .I buf 14 | into 15 | .IR a . 16 | The big integer should have be saved using 17 | .BR zsave (3), 18 | with the same version of libzahl 19 | and on the processor architecture. 20 | .P 21 | .I a 22 | must have been initialized with 23 | .BR zinit (3). 24 | .SH RETURN VALUE 25 | The number of bytes read from 26 | .IR buf . 27 | .SH SEE ALSO 28 | .BR zinit (3), 29 | .BR zsave (3), 30 | .BR zsets (3) 31 | -------------------------------------------------------------------------------- /man/zlsb.3: -------------------------------------------------------------------------------- 1 | .TH ZLSB 3 libzahl 2 | .SH NAME 3 | zlsb - Get the least set bit. 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | size_t zlsb(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zlsb 12 | gets the index of the bit of 13 | lowest value that is set in 14 | .IR a . 15 | If 16 | .I a 17 | is zero, 18 | .B SIZE_MAX 19 | is returned. 20 | .SH RETURN VALUE 21 | The index of the least set bit in 22 | .IR a , 23 | or 24 | .B SIZE_MAX 25 | if 26 | .I a 27 | is zero. 28 | .SH SEE ALSO 29 | .BR zbits (3), 30 | .BR zbtest (3), 31 | .BR zbset (3), 32 | .BR znot (3), 33 | .BR zrsh (3) 34 | -------------------------------------------------------------------------------- /man/zlsh.3: -------------------------------------------------------------------------------- 1 | .TH ZLSH 3 libzahl 2 | .SH NAME 3 | zlsh - Perform a left shift on a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zlsh(z_t \fIa\fP, z_t \fIb\fP, size_t \fIn\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zlsh 12 | shifts 13 | .I b 14 | .I n 15 | bits to the left and stores the result in 16 | .IR a . 17 | .P 18 | It is safe to call 19 | .B zlsh 20 | with 21 | .IR "(a==b)" . 22 | .SH SEE ALSO 23 | .BR zand (3), 24 | .BR zor (3), 25 | .BR zxor (3), 26 | .BR znot (3), 27 | .BR zrsh (3), 28 | .BR ztrunc (3), 29 | .BR zsplit (3), 30 | .BR zbtest (3), 31 | .BR zbset (3), 32 | .BR zlsb (3), 33 | .BR zbits (3) 34 | -------------------------------------------------------------------------------- /man/zmod.3: -------------------------------------------------------------------------------- 1 | .TH ZMOD 3 libzahl 2 | .SH NAME 3 | zmod - Calculate the modulus of two big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zmod(z_t \fIremainder\fP, z_t \fIdividend\fP, z_t \fIdivisor\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zmod 12 | calculates the remainder of a 13 | .I dividend 14 | and a 15 | .IR divisor , 16 | and stores the result in 17 | .IR remainder . 18 | That is, 19 | .I remainder 20 | gets 21 | .I dividend 22 | Mod 23 | .IR divisor . 24 | .P 25 | The result 26 | .RI ( remainder ) 27 | is negative if and only if the 28 | .I dividend 29 | is negative. To be more precise, 30 | a Mod b = (|a| Mod |b|) sgn a for all integers a 31 | and b. 32 | .P 33 | It is safe to call 34 | .B zmod 35 | with non-unique parameters. 36 | .SH SEE ALSO 37 | .BR zdivmod (3), 38 | .BR zstr (3), 39 | .BR zadd (3), 40 | .BR zsub (3), 41 | .BR zmul (3), 42 | .BR zdiv (3), 43 | .BR zneg (3), 44 | .BR zabs (3), 45 | .BR zpow (3) 46 | -------------------------------------------------------------------------------- /man/zmodmul.3: -------------------------------------------------------------------------------- 1 | .TH ZMODMUL 3 libzahl 2 | .SH NAME 3 | zmodmul - Calculate a modular product of two big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zmodmul(z_t \fIproduct\fP, z_t \fImultiplier\fP, z_t \fImultiplicand\fP, z_t \fImodulator\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zmodmul 12 | calculates the product of a 13 | .I multiplier 14 | and a 15 | .IR multiplicand , 16 | modulus a 17 | .IR modulator , 18 | and stores the result in 19 | .IR product . 20 | That is, 21 | .I product 22 | gets 23 | .RI ( multiplier 24 | ⋅ 25 | .IR multiplicand ) 26 | Mod 27 | .IR modulator . 28 | .P 29 | It is safe to call 30 | .B zmodmul 31 | with non-unique parameters. 32 | .P 33 | See 34 | .BR zmod (3) 35 | for details on modulation. 36 | .SH RATIONALE 37 | It is possible to calculate the modular product 38 | with a faster algorithm than calculating the 39 | product and than the modulus of that product. 40 | .SH SEE ALSO 41 | .BR zmodsqr (3), 42 | .BR zmodpow (3), 43 | .BR zstr (3), 44 | .BR zadd (3), 45 | .BR zsub (3), 46 | .BR zmul (3), 47 | .BR zdiv (3), 48 | .BR zmod (3), 49 | .BR zneg (3), 50 | .BR zabs (3), 51 | .BR zpow (3) 52 | -------------------------------------------------------------------------------- /man/zmodpow.3: -------------------------------------------------------------------------------- 1 | .TH ZMODPOW 3 libzahl 2 | .SH NAME 3 | zmodpow - Calculate a modular power of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zmodpow(z_t \fIpower\fP, z_t \fIbase\fP, z_t \fIexponent\fP, z_t \fImodulator\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zmodpow 12 | calculates the 13 | .IR exponent :th 14 | power of a 15 | .IR base , 16 | modulus a 17 | .IR modulator , 18 | and stores the result in 19 | .IR power . 20 | That is, 21 | .I power 22 | gets 23 | .RI ( base 24 | ↑ 25 | .IR exponent ) 26 | Mod 27 | .IR modulator . 28 | .P 29 | It is safe to call 30 | .B zmodpow 31 | with non-unique parameters. 32 | .P 33 | See 34 | .BR zmod (3) 35 | for details on modulation. 36 | .SH RATIONALE 37 | It is possible to calculate the modular power 38 | with a faster algorithm than calculating the 39 | power and than the modulus of that power. 40 | .SH SEE ALSO 41 | .BR zmodpowu (3), 42 | .BR zmodsqr (3), 43 | .BR zmodmul (3), 44 | .BR zsqr (3), 45 | .BR zstr (3), 46 | .BR zadd (3), 47 | .BR zsub (3), 48 | .BR zmul (3), 49 | .BR zdiv (3), 50 | .BR zmod (3), 51 | .BR zneg (3), 52 | .BR zabs (3) 53 | -------------------------------------------------------------------------------- /man/zmodpowu.3: -------------------------------------------------------------------------------- 1 | .TH ZMODPOWU 3 libzahl 2 | .SH NAME 3 | zmodpowu - Calculate a modular power of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zmodpowu(z_t \fIpower\fP, z_t \fIbase\fP, unsigned long long int \fIexponent\fP, z_t \fImodulator\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zmodpowu 12 | calculates the 13 | .IR exponent :th 14 | power of a 15 | .IR base , 16 | modulus a 17 | .IR modulator , 18 | and stores the result in 19 | .IR power . 20 | That is, 21 | .I power 22 | gets 23 | .RI ( base 24 | ↑ 25 | .IR exponent ) 26 | Mod 27 | .IR modulator . 28 | .P 29 | It is safe to call 30 | .B zmodpowu 31 | with non-unique parameters. 32 | .P 33 | See 34 | .BR zmod (3) 35 | for details on modulation. 36 | .SH RATIONALE 37 | It is possible to calculate the modular power 38 | with a faster algorithm than calculating the 39 | power and than the modulus of that power. 40 | .SH SEE ALSO 41 | .BR zmodpow (3), 42 | .BR zmodsqr (3), 43 | .BR zmodmul (3), 44 | .BR zsqr (3), 45 | .BR zstr (3), 46 | .BR zadd (3), 47 | .BR zsub (3), 48 | .BR zmul (3), 49 | .BR zdiv (3), 50 | .BR zmod (3), 51 | .BR zneg (3), 52 | .BR zabs (3) 53 | -------------------------------------------------------------------------------- /man/zmodsqr.3: -------------------------------------------------------------------------------- 1 | .TH ZMODSQR 3 libzahl 2 | .SH NAME 3 | zsqr - Calculate a modular square of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zmodsqr(z_t \fIsquare\fP, z_t \fIinteger\fP, z_t \fImodulator\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zmodsqr 12 | calculates the square of an 13 | .IR integer , 14 | modulus a 15 | .IR modulator , 16 | and stores the result in 17 | .IR square . 18 | That is, 19 | .I square 20 | gets 21 | .IR integer ². 22 | Mod 23 | .IR modulator . 24 | .P 25 | It is safe to call 26 | .B zmodsqr 27 | with non-unique parameters. 28 | .P 29 | See 30 | .BR zmod (3) 31 | for details on modulation. 32 | .SH RATIONALE 33 | See rationle for 34 | .BR zmodmul (3), 35 | and 36 | .BR zsqr (3). 37 | .SH SEE ALSO 38 | .BR zmodmul (3), 39 | .BR zmodpow (3), 40 | .BR zsqr (3), 41 | .BR zstr (3), 42 | .BR zadd (3), 43 | .BR zsub (3), 44 | .BR zmul (3), 45 | .BR zdiv (3), 46 | .BR zmod (3), 47 | .BR zneg (3), 48 | .BR zabs (3), 49 | .BR zpow (3) 50 | -------------------------------------------------------------------------------- /man/zmul.3: -------------------------------------------------------------------------------- 1 | .TH ZMUL 3 libzahl 2 | .SH NAME 3 | zmul - Calculate the product of two big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zmul(z_t \fIproduct\fP, z_t \fImultiplier\fP, z_t \fImultiplicand\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zmul 12 | calculates the product of a 13 | .I multiplier 14 | and a 15 | .IR multiplicand , 16 | and stores the result in 17 | .IR product . 18 | That is, 19 | .I product 20 | gets 21 | .I multiplier 22 | ⋅ 23 | .IR multiplicand . 24 | .P 25 | It is safe to call 26 | .B zmul 27 | with non-unique parameters. 28 | .SH SEE ALSO 29 | .BR zmodmul (3), 30 | .BR zsqr (3), 31 | .BR zstr (3), 32 | .BR zadd (3), 33 | .BR zsub (3), 34 | .BR zdiv (3), 35 | .BR zmod (3), 36 | .BR zneg (3), 37 | .BR zabs (3), 38 | .BR zpow (3) 39 | -------------------------------------------------------------------------------- /man/zneg.3: -------------------------------------------------------------------------------- 1 | .TH ZNEG 3 libzahl 2 | .SH NAME 3 | zneg - Calculate the negation of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zneg(z_t \fIa\fP, z_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zneg 12 | calculates the negation of 13 | .I b 14 | and stores the result in 15 | .IR a . 16 | That is, 17 | .I a 18 | gets 19 | .RI - b . 20 | .P 21 | It is safe to call 22 | .B zneg 23 | with non-unique parameters. 24 | .SH SEE ALSO 25 | .BR zset (3), 26 | .BR zstr (3), 27 | .BR zadd (3), 28 | .BR zsub (3), 29 | .BR zmul (3), 30 | .BR zdiv (3), 31 | .BR zmod (3), 32 | .BR zabs (3), 33 | .BR zpow (3) 34 | -------------------------------------------------------------------------------- /man/znot.3: -------------------------------------------------------------------------------- 1 | .TH ZNOT 3 libzahl 2 | .SH NAME 3 | znot - Calculate the bitwise complement of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void znot(z_t \fIa\fP, z_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B znot 12 | calculates the bitwise complement of 13 | .I b 14 | and stores the result in 15 | .IR a . 16 | .P 17 | It is safe to call 18 | .B znot 19 | with 20 | .IR "(a==b)" . 21 | .SH NOTES 22 | Be aware, the following code will halt for any input 23 | .P 24 | .nf 25 | #include 26 | 27 | void 28 | silly(z_t a) 29 | { 30 | while (!zzero(a)) 31 | znot(a, a); 32 | } 33 | .fi 34 | .P 35 | Also note that 36 | .B z_t 37 | uses neither two's complement, ones' complement, nor 38 | sign-and-magnitude. 39 | .SH SEE ALSO 40 | .BR zand (3), 41 | .BR zor (3), 42 | .BR zxor (3), 43 | .BR zlsh (3), 44 | .BR zrsh (3), 45 | .BR zsplit (3), 46 | .BR zbtest (3), 47 | .BR zbset (3), 48 | .BR zlsb (3), 49 | .BR zbits (3) 50 | -------------------------------------------------------------------------------- /man/zodd.3: -------------------------------------------------------------------------------- 1 | .TH ZODD 3 libzahl 2 | .SH NAME 3 | zodd - Check whether a big integer is odd 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zodd(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zodd 12 | checks whether 13 | .I a 14 | is odd. 15 | .SH RETURN VALUE 16 | .B zeven 17 | returns 1 if 18 | .I a 19 | is odd, and 0 otherwise. 20 | .SH SEE ALSO 21 | .BR zeven (3), 22 | .BR zodd_nonzero (3), 23 | .BR zzero (3), 24 | .BR zsignum (3), 25 | .BR zcmp (3) 26 | -------------------------------------------------------------------------------- /man/zodd_nonzero.3: -------------------------------------------------------------------------------- 1 | .TH ZODD_NONZERO 3 libzahl 2 | .SH NAME 3 | zodd_nonzero - Check whether a non-zero big integer is odd 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zodd_nonzero(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zodd_nonzero 12 | checks whether 13 | .I a 14 | is odd. 15 | .P 16 | Undefined behaviour is invoked if 17 | .I a 18 | is zero. 19 | .SH RETURN VALUE 20 | .B zodd_nonzero 21 | returns 1 if 22 | .I a 23 | is odd, and 0 otherwise. 24 | .SH SEE ALSO 25 | .BR zodd (3), 26 | .BR zeven_nonzero (3), 27 | .BR zzero (3), 28 | .BR zsignum (3), 29 | .BR zcmp (3) 30 | -------------------------------------------------------------------------------- /man/zor.3: -------------------------------------------------------------------------------- 1 | .TH ZOR 3 libzahl 2 | .SH NAME 3 | zor - Calculate the bitwise inclusive OR of two big integers 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zor(z_t \fIa\fP, z_t \fIb\fP, z_t \fIc\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zor 12 | calculates the bitwise OR of 13 | .I b 14 | and 15 | .IR c , 16 | and stores the result in 17 | .IR a . 18 | .P 19 | It is safe to call 20 | .B zor 21 | with non-unique parameters. 22 | .SH SEE ALSO 23 | .BR zand (3), 24 | .BR zxor (3), 25 | .BR znot (3), 26 | .BR zlsh (3), 27 | .BR zrsh (3), 28 | .BR zsplit (3), 29 | .BR zbtest (3), 30 | .BR zbset (3), 31 | .BR zlsb (3), 32 | .BR zbits (3) 33 | -------------------------------------------------------------------------------- /man/zperror.3: -------------------------------------------------------------------------------- 1 | .TH ZPERROR 3 libzahl 2 | .SH NAME 3 | zperror - Print a libzahl error message 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zperror(const char *\fIprefix\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zperror 12 | prints a libzahl error message to standard error. 13 | Unless 14 | .I prefix 15 | is 16 | .B 0 17 | or an empty string, the message is prefixed by 18 | .IR prefix , 19 | a colon and a blank space. 20 | .SH SEE ALSO 21 | .BR zerror (3) 22 | -------------------------------------------------------------------------------- /man/zpow.3: -------------------------------------------------------------------------------- 1 | .TH ZPOW 3 libzahl 2 | .SH NAME 3 | zpow - Calculate a power of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zpow(z_t \fIpower\fP, z_t \fIbase\fP, z_t \fIexponent\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zpow 12 | calculates the 13 | .IR exponent :th 14 | power of a 15 | .IR base , 16 | and stores the result in 17 | .IR power . 18 | That is, 19 | .I power 20 | gets 21 | .I base 22 | ↑ 23 | .IR exponent . 24 | .P 25 | It is safe to call 26 | .B zpow 27 | with non-unique parameters. 28 | .SH SEE ALSO 29 | .BR zpowu (3), 30 | .BR zmodpow (3), 31 | .BR zsqr (3), 32 | .BR zstr (3), 33 | .BR zadd (3), 34 | .BR zsub (3), 35 | .BR zmul (3), 36 | .BR zdiv (3), 37 | .BR zmod (3), 38 | .BR zneg (3), 39 | .BR zabs (3) 40 | -------------------------------------------------------------------------------- /man/zpowu.3: -------------------------------------------------------------------------------- 1 | .TH ZPOWU 3 libzahl 2 | .SH NAME 3 | zpowu - Calculate a power of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zpowu(z_t \fIpower\fP, z_t \fIbase\fP, unsigned long long int \fIexponent\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zpowu 12 | calculates the 13 | .IR exponent :th 14 | power of a 15 | .IR base , 16 | and stores the result in 17 | .IR power . 18 | That is, 19 | .I power 20 | gets 21 | .I base 22 | ↑ 23 | .IR exponent . 24 | .P 25 | It is safe to call 26 | .B zpowu 27 | with non-unique parameters. 28 | .SH SEE ALSO 29 | .BR zpowu (3), 30 | .BR zmodpowu (3), 31 | .BR zsqr (3), 32 | .BR zstr (3), 33 | .BR zadd (3), 34 | .BR zsub (3), 35 | .BR zmul (3), 36 | .BR zdiv (3), 37 | .BR zmod (3), 38 | .BR zneg (3), 39 | .BR zabs (3) 40 | -------------------------------------------------------------------------------- /man/zptest.3: -------------------------------------------------------------------------------- 1 | .TH ZPTEST 3 libzahl 2 | .SH NAME 3 | zptest - Test the primality of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | enum zprimality zptest(z_t \fIwitness\fP, z_t \fIquestioned\fP, int \fItries\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zptest 12 | tests whether 13 | .I questioned 14 | is a prime number. This is implemented using the 15 | Miller–Rabin primality test. 16 | .P 17 | If 18 | .I questioned 19 | is determined to be a composite, the witness if its 20 | compositeness is stored into 21 | .I witness 22 | unless 23 | .I witness 24 | is 25 | .BR 0 . 26 | .BR zgcd (3) 27 | can be used on 28 | .I questioned 29 | and 30 | .I witness 31 | to extract a factor of 32 | .IR questioned . 33 | This factor can be either composite, prime, or 1. 34 | .P 35 | The risk that a composite number is determined to be 36 | a probably prime is 37 | .IR (1-4↑-tries) . 38 | .P 39 | It is safe to call 40 | .B zptest 41 | with non-unique parameters, and with 42 | .IR "(witness==0)" . 43 | .SH RETURN VALUE 44 | This function will either return: 45 | .TP 46 | .B NONPRIME 47 | .I questioned 48 | is certainly a nonprime number (composite). 49 | .TP 50 | .B PROBABLY_PRIME 51 | .I questioned 52 | is probably a prime number. 53 | .TP 54 | .B PRIME 55 | .I questioned 56 | is certainly a prime number. 57 | .SH NOTES 58 | If 59 | .I questioned 60 | is less than two 61 | .I questioned 62 | is copied into 63 | .P 64 | Increasing 65 | .I tries 66 | only reduces the chance that 67 | .B PROBABLY_PRIME 68 | is returned. It cannot increase 69 | the chance that 70 | .B PRIME 71 | is returned. 72 | .IR witness . 73 | .SH RATIONALE 74 | .B NONPRIME 75 | is called just that, rather than COMPOSITE, 76 | because negative integers, zero, and one are 77 | neither prime nor composite. (One was historically 78 | a prime, we do not recognise it as such.) 79 | .SH SEE ALSO 80 | .BR zgcd (3) 81 | -------------------------------------------------------------------------------- /man/zrand.3: -------------------------------------------------------------------------------- 1 | .TH ZRAND 3 libzahl 2 | .SH NAME 3 | zrand - Generate random a number 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zrand(z_t \fIr\fP, enum zranddev \fIdev\fP, enum zranddist \fIdist\fP, z_t \fImax\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zrand 12 | generates a random number and stores it in 13 | .IR r . 14 | .P 15 | .I dev 16 | selects the device 17 | .B zrand 18 | uses to generate random bits. 19 | This value may be either of: 20 | .TP 21 | .B DEFAULT_RANDOM 22 | This is a version-dependent alias for the 23 | default random number generator. That is, 24 | using this option will cause 25 | .B zrand 26 | to select the default random number generator. 27 | Which random number generator is actually 28 | selected may change between versions of 29 | .B zrand. 30 | 31 | The selection will be a balance between randomness 32 | and performance. 33 | .TP 34 | .B FASTEST_RANDOM 35 | This is a version-dependent alias for the 36 | fastest random number generator. That is, 37 | using this option will cause 38 | .B zrand 39 | to select the fastest random number generator. 40 | Which random number generator is actually 41 | selected may change between versions of 42 | .B zrand. 43 | .TP 44 | .B FAST_RANDOM 45 | The fast, non-blocking random number generator. 46 | This is /dev/urandom on Linux. 47 | .TP 48 | .B SECURE_RANDOM 49 | The secure, blocking random number generator. 50 | This is /dev/random on Linux. 51 | .P 52 | .I dist 53 | selects the probably distribution of the 54 | output 55 | .IR r : 56 | .TP 57 | .B QUASIUNIFORM 58 | Use the method of generation that is often 59 | recommended for generating uniformally random 60 | integers. This method has unnecessary 61 | computational overhead and is not properly 62 | uniform, but is is guaranteed to run in 63 | constant time assuming the underlying device 64 | for random bit generation does. 65 | 66 | The generated number if be in the inclusive 67 | range [0, 68 | .IR max ]. 69 | .TP 70 | .B UNIFORM 71 | Generate a integer in the range [0, 72 | .IR max ] 73 | uniformally random. 74 | .TP 75 | .B MODUNIFORM 76 | Slightly faster alternative to 77 | .BR UNIFORM . 78 | 79 | It is not truly uniform. It is biased 80 | to the lower numbers, but the probably 81 | if any number is either 82 | .I p 83 | or 84 | .I 2p 85 | for some parameter-dependent number 86 | .IR p . 87 | 88 | It uses the naïve approach of generating 89 | a random number and modulation with the maximum 90 | number. However, this implementation this 91 | modulation by subtracting with the maximum number 92 | if the generated number is greater. 93 | .P 94 | It is safe to call 95 | .B zrand 96 | with non-unique parameters. 97 | -------------------------------------------------------------------------------- /man/zrsh.3: -------------------------------------------------------------------------------- 1 | .TH ZRSH 3 libzahl 2 | .SH NAME 3 | zrsh - Perform a right shift on a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zrsh(z_t \fIa\fP, z_t \fIb\fP, size_t \fIn\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zrsh 12 | shifts 13 | .I b 14 | .I n 15 | bits to the right and stores the result in 16 | .IR a . 17 | .P 18 | It is safe to call 19 | .B zrsh 20 | with 21 | .IR "(a==b)" . 22 | .SH SEE ALSO 23 | .BR zand (3), 24 | .BR zor (3), 25 | .BR zxor (3), 26 | .BR znot (3), 27 | .BR zlsh (3), 28 | .BR ztrunc (3), 29 | .BR zsplit (3), 30 | .BR zbtest (3), 31 | .BR zbset (3), 32 | .BR zlsb (3), 33 | .BR zbits (3) 34 | -------------------------------------------------------------------------------- /man/zsave.3: -------------------------------------------------------------------------------- 1 | .TH ZSAVE 3 libzahl 2 | .SH NAME 3 | zsave - Marshal a big integer into a buffer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | size_t zsave(z_t \fIa\fP, void *\fIbuf\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zsave 12 | marshals 13 | .I a 14 | into the buffer 15 | .IR buf 16 | unless 17 | .IR buf 18 | is 19 | .IR 0 . 20 | The data stored is not necessarily transferable 21 | between machines or between different versions 22 | of libzahl. For such use, 23 | use 24 | .BR zstr (3) 25 | instead. 26 | .P 27 | Upon successful completion, 28 | .I (*(int*)buf) 29 | will always be either -1, 0, or 1. 30 | .SH RETURN VALUE 31 | The number of bytes written to 32 | .IR buf , 33 | or the number bytes that would have been written if 34 | .IR buf 35 | was not 36 | .IR 0 . 37 | .SH ERRORS 38 | This function cannot detect failure. 39 | .SH EXAMPLE 40 | .nf 41 | #include 42 | #include 43 | 44 | int buffer_z(z_t num, char **buf, size_t *off) { 45 | size_t n = zsave(num, 0); 46 | char *new = realloc(*buf, *off + n); 47 | if (!new) { 48 | return -1; 49 | } 50 | *buf = new; 51 | assert(zsave(num, *buf + *off) == n); 52 | *off += n; 53 | return 0; 54 | } 55 | .fi 56 | .SH RATIONALE 57 | This makes it possible to fork a process and send 58 | result between the parent and the child, as long as 59 | none of the process re-execute themself. 60 | .B zsave 61 | is much faster than 62 | .BR zstr (3). 63 | .SH SEE ALSO 64 | .BR zload (3), 65 | .BR zstr (3) 66 | -------------------------------------------------------------------------------- /man/zset.3: -------------------------------------------------------------------------------- 1 | .TH ZSET 3 libzahl 2 | .SH NAME 3 | zset - Copy the value of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zset(z_t \fIa\fP, z_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zset 12 | stores the value of 13 | .I b 14 | into 15 | .IR a . 16 | .I a 17 | must already be initialized with 18 | .BR zinit (3). 19 | The value of 20 | .I b 21 | remains unchanged. 22 | .SH SEE ALSO 23 | .BR zseti (3), 24 | .BR zsetu (3), 25 | .BR zsets (3), 26 | .BR zswap (3), 27 | .BR zabs (3), 28 | .BR zneg (3), 29 | .BR ztrunc (3) 30 | -------------------------------------------------------------------------------- /man/zseti.3: -------------------------------------------------------------------------------- 1 | .TH ZSETI 3 libzahl 2 | .SH NAME 3 | zseti - Set the value of a big integer to a signed integer. 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zseti(z_t \fIa\fP, int64_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zseti 12 | sets the value of 13 | .I a 14 | to 15 | .IR b . 16 | .I a 17 | must already be initialized with 18 | .BR zinit (3). 19 | .SH SEE ALSO 20 | .BR zset (3), 21 | .BR zsetu (3), 22 | .BR zsets (3), 23 | .BR zswap (3) 24 | -------------------------------------------------------------------------------- /man/zsets.3: -------------------------------------------------------------------------------- 1 | .TH ZSETS 3 libzahl 2 | .SH NAME 3 | zsets - Parses a string to a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zsets(z_t \fIa\fP, const char *\fIstr\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zsets 12 | parses the string 13 | .I str 14 | and stores the value in 15 | .IR a . 16 | .I a 17 | must already be initialized with 18 | .BR zinit (3). 19 | .I b 20 | must be a decimal integer. It may be 21 | prefixed with at most one ASCII minus 22 | sign or plus sign. 23 | .SH RETURN VALUE 24 | Upon successful completion, 0 is returned. 25 | On error -1 is returned an errno is appropriately. 26 | .SH ERRORS 27 | This function fails if: 28 | .TP 29 | .B EINVAL 30 | .B str 31 | is not a valid decimal ASCII integer. 32 | .P 33 | On other errors, the function performs a long jump 34 | using the jump buffer provided via 35 | .BR zsetup (3). 36 | .SH SEE ALSO 37 | .BR zset (3), 38 | .BR zsetu (3), 39 | .BR zseti (3), 40 | .BR zsave (3), 41 | .BR zstr (3) 42 | -------------------------------------------------------------------------------- /man/zsetu.3: -------------------------------------------------------------------------------- 1 | .TH ZSETU 3 libzahl 2 | .SH NAME 3 | zsetu - Set the value of a big integer to an unsigned integer. 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zsetu(z_t \fIa\fP, uint64_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zseti 12 | sets the value of 13 | .I a 14 | to 15 | .IR b . 16 | .I a 17 | must already be initialized with 18 | .BR zinit (3). 19 | .SH SEE ALSO 20 | .BR zset (3), 21 | .BR zseti (3), 22 | .BR zsets (3), 23 | .BR zswap (3) 24 | -------------------------------------------------------------------------------- /man/zsetup.3: -------------------------------------------------------------------------------- 1 | .TH ZSETUP 3 libzahl 2 | .SH NAME 3 | zsetup - Prepare libzahl for use 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zsetup(jmp_buf \fIenv\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zsetup 12 | initializes all memory that is used internally by 13 | libzahl. 14 | .B zsetup 15 | is also used to specify where to return in case 16 | an error occurs. 17 | You must call this function before using libzahl. 18 | .P 19 | .B zsetup 20 | can be used multiple times, the 21 | .I env 22 | from the last call is in effect. 23 | .SH EXAMPLE 24 | .nf 25 | #include 26 | #include 27 | 28 | int 29 | main(void) 30 | { 31 | jmp_buf env; 32 | 33 | if (setjmp(env)) { 34 | perror(0); 35 | zunsetup(); 36 | return 1; 37 | } 38 | zsetup(env); 39 | 40 | /* Use libzahl ... */ 41 | 42 | zunsetup(); 43 | return 0; 44 | } 45 | .fi 46 | .SH RATIONALE 47 | To increase the performance of libzahl, it uses 48 | dedicated memory for temporary storage. 49 | .PP 50 | libzahl performs checks internally, this is 51 | necessary. It would decrease the performance 52 | of the program that uses libzahl, if it had 53 | to check that libzahl's functions returned 54 | successfully, it would also produce cluttered 55 | code. Instead libzahl goes directly to the 56 | part of the program that handles the error. 57 | .SH SEE ALSO 58 | .BR zunsetup (3), 59 | .BR zinit (3), 60 | .BR zerror (3), 61 | .BR zperror (3) 62 | -------------------------------------------------------------------------------- /man/zsignum.3: -------------------------------------------------------------------------------- 1 | .TH ZSIGNUM 3 libzahl 2 | .SH NAME 3 | zsignum - Get the sign of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zsignum(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zsignum 12 | returns signum of 13 | .I 14 | a ; 15 | the sign. 16 | .SH RETURN VALUE 17 | .B zsignum 18 | returns -1 if 19 | .I a 20 | is negative, 0 if 21 | .I a 22 | is zero, and +1 if 23 | .I a 24 | is positive. 25 | .SH SEE ALSO 26 | .BR zzero (3), 27 | .BR zeven (3), 28 | .BR zodd (3), 29 | .BR zcmp (3) 30 | -------------------------------------------------------------------------------- /man/zsplit.3: -------------------------------------------------------------------------------- 1 | .TH ZSPLIT 3 libzahl 2 | .SH NAME 3 | zsplit - Split a big integer in two parts 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zsplit(z_t \fIhigh\fP, z_t \fIlow\fP, z_t \fIa\fP, size_t \fIn\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zsplits 12 | splits 13 | .I a 14 | into two parts. The lowest 15 | .I n 16 | bits are stored in 17 | .IR low , 18 | and the rest of the bits are 19 | stored in 20 | .IR high . 21 | The result stored in 22 | .I high 23 | is shifted 24 | .I n 25 | bits to the right. Both 26 | .I high 27 | and 28 | .I low 29 | will have the same sign as 30 | .IR a . 31 | .P 32 | It is safe to call 33 | .B zsplit 34 | with 35 | .I "(high==a)" 36 | and 37 | .IR "(low==a)" . 38 | .SH RATIONALE 39 | Splitting big integers in the described way is useful 40 | for divide-and-conquer algorithms. 41 | .SH SEE ALSO 42 | .BR zand (3), 43 | .BR zor (3), 44 | .BR zxor (3), 45 | .BR znot (3), 46 | .BR zlsh (3), 47 | .BR zrsh (3), 48 | .BR zbits (3) 49 | -------------------------------------------------------------------------------- /man/zsqr.3: -------------------------------------------------------------------------------- 1 | .TH ZSQR 3 libzahl 2 | .SH NAME 3 | zsqr - Calculate the square of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zsqr(z_t \fIsquare\fP, z_t \fIinteger\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zsqr 12 | calculates the square of an 13 | .IR integer , 14 | and stores the result in 15 | .IR square . 16 | That is, 17 | .I square 18 | gets 19 | .IR integer ². 20 | .P 21 | It is safe to call 22 | .B zsqr 23 | with non-unique parameters. 24 | .SH RATIONALE 25 | Multiplication algorithm can be optimised if 26 | we know that the multiplier and the multiplicand 27 | are equal. 28 | .SH SEE ALSO 29 | .BR zmodmul (3), 30 | .BR zmodpow (3), 31 | .BR zstr (3), 32 | .BR zadd (3), 33 | .BR zsub (3), 34 | .BR zdiv (3), 35 | .BR zmod (3), 36 | .BR zneg (3), 37 | .BR zabs (3), 38 | .BR zpow (3) 39 | -------------------------------------------------------------------------------- /man/zstr.3: -------------------------------------------------------------------------------- 1 | .TH ZSTR 3 libzahl 2 | .SH NAME 3 | zstr - Create a string representation of a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | char *zstr(z_t \fIa\fP, char *\fIstr\fP, size_t \fIn\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zstr 12 | writes the integer 13 | .I a 14 | in decimal form into 15 | .IR str . 16 | If 17 | .I str 18 | is is 19 | .BR 0 , 20 | .B zstr 21 | create a new allocation. 22 | .P 23 | .I n 24 | must be either be zero or a value at least 25 | as great as the length of the resulting string. 26 | If both 27 | .I n 28 | and 29 | .I str 30 | are nonzero, 31 | .I n 32 | must be at least the allocation size of 33 | .I str 34 | minus 1. Proper value for 35 | .I n 36 | can be calculated using 37 | .BR zstr_length (3). 38 | .SH RETURN VALUE 39 | .I str 40 | is returned unless 41 | .I str 42 | is 43 | .BR 0 . 44 | If 45 | .I str 46 | is 47 | .BR 0 , 48 | the string allocated by the function is returned. 49 | .SH SEE ALSO 50 | .BR zstr_length (3), 51 | .BR zsets (3), 52 | .BR zload (3) 53 | -------------------------------------------------------------------------------- /man/zstr_length.3: -------------------------------------------------------------------------------- 1 | .TH ZSTR_LENGTH 3 libzahl 2 | .SH NAME 3 | zstr_length - Predict the length of a string 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | size_t zstr_length(z_t \fIa\fP, unsigned long long int \fIradix\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zstr_length 12 | calculates the number of digits required to 13 | to represent 14 | .I a 15 | in the selected 16 | .IR radix . 17 | .SH RETURN VALUE 18 | The number of digits requires to represent 19 | .I a 20 | in the selected 21 | .I radix 22 | is returned. 23 | .SH SEE ALSO 24 | .BR zstr (3), 25 | .BR zbits (3) 26 | -------------------------------------------------------------------------------- /man/zsub.3: -------------------------------------------------------------------------------- 1 | .TH ZSUB 3 libzahl 2 | .SH NAME 3 | zsub - Calculate the difference of two big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zsub(z_t \fIdifference\fP, z_t \fIminuend\fP, z_t \fIsubtrahend\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zsub 12 | calculates the difference of a 13 | .I minuend 14 | and a 15 | .IR subtrahend , 16 | and stores the result in 17 | .IR difference . 18 | That is, 19 | .I difference 20 | gets 21 | .I minuend 22 | - 23 | .IR subtrahend . 24 | .P 25 | It is safe to call 26 | .B zsub 27 | with non-unique parameters. 28 | .SH SEE ALSO 29 | .BR zstr (3), 30 | .BR zadd (3), 31 | .BR zmul (3), 32 | .BR zdiv (3), 33 | .BR zmod (3), 34 | .BR zneg (3), 35 | .BR zabs (3), 36 | .BR zpow (3) 37 | -------------------------------------------------------------------------------- /man/zswap.3: -------------------------------------------------------------------------------- 1 | .TH ZSWAP 3 libzahl 2 | .SH NAME 3 | zswap - Exchanges the value of two big integers 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zswap(z_t \fIa\fP, z_t \fIb\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zswap 12 | exchanges all information stored in 13 | .I a 14 | with the information stored in 15 | .IR b . 16 | .P 17 | It is safe to call 18 | .B zswap 19 | with 20 | .IR "(a==b)" . 21 | .SH SEE ALSO 22 | .BR zset (3) 23 | -------------------------------------------------------------------------------- /man/ztrunc.3: -------------------------------------------------------------------------------- 1 | .TH ZTRUNC 3 libzahl 2 | .SH NAME 3 | ztrunc - Truncate a big integer 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void ztrunc(z_t \fIa\fP, z_t \fIb\fP, size_t \fIbits\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B ztrunc 12 | makes a truncated copy of 13 | .I b 14 | and stores it in 15 | .IR a . 16 | Only the first 17 | .I bits 18 | from 19 | .I b 20 | and 21 | .IR b 's 22 | sign is copied to 23 | .IR a . 24 | .P 25 | It is safe to call 26 | .B zsplit 27 | with non-unique parameters. 28 | .SH RATIONALE 29 | This was useful for improving the performance of 30 | .BR zsplit (3). 31 | .SH SEE ALSO 32 | .BR zand (3), 33 | .BR zor (3), 34 | .BR zxor (3), 35 | .BR znot (3), 36 | .BR zlsh (3), 37 | .BR zrsh (3), 38 | .BR zsplit (3), 39 | .BR zbits (3) 40 | -------------------------------------------------------------------------------- /man/zunsetup.3: -------------------------------------------------------------------------------- 1 | .TH ZUNSETUP 3 libzahl 2 | .SH NAME 3 | zsetup - Release all memory used internally by libzahl. 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zunsetup(void); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zunsetup 12 | release all memory used internally or cached by libzahl. 13 | You should run this function when you are done using libzahl. 14 | .P 15 | It is possible to call 16 | .B zunsetup 17 | directly followed by 18 | .BR zsetup (3). 19 | .SH SEE ALSO 20 | .BR zsetup (3) 21 | -------------------------------------------------------------------------------- /man/zxor.3: -------------------------------------------------------------------------------- 1 | .TH ZXOR 3 libzahl 2 | .SH NAME 3 | zxor - Calculate the bitwise exclusive OR (XOR) of two big integers 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | void zxor(z_t \fIa\fP, z_t \fIb\fP, z_t \fIc\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zxor 12 | calculates the bitwise XOR of 13 | .I b 14 | and 15 | .IR c , 16 | and stores the result in 17 | .IR a . 18 | .P 19 | It is safe to call 20 | .B zxor 21 | with non-unique parameters. 22 | .SH SEE ALSO 23 | .BR zand (3), 24 | .BR zor (3), 25 | .BR znot (3), 26 | .BR zlsh (3), 27 | .BR zrsh (3), 28 | .BR zsplit (3), 29 | .BR zbtest (3), 30 | .BR zbset (3), 31 | .BR zlsb (3), 32 | .BR zbits (3) 33 | -------------------------------------------------------------------------------- /man/zzero.3: -------------------------------------------------------------------------------- 1 | .TH ZZERO 3 libzahl 2 | .SH NAME 3 | zzero - Check whether a big integer is zero 4 | .SH SYNOPSIS 5 | .nf 6 | #include 7 | 8 | int zzero(z_t \fIa\fP); 9 | .fi 10 | .SH DESCRIPTION 11 | .B zzero 12 | checks whether 13 | .I a 14 | is zero. 15 | .SH RETURN VALUE 16 | .B zzero 17 | returns 1 if 18 | .I a 19 | is zero, and 0 otherwise. 20 | .SH SEE ALSO 21 | .BR zsignum (3), 22 | .BR zeven (3), 23 | .BR zodd (3), 24 | .BR zcmp (3) 25 | -------------------------------------------------------------------------------- /src/allocator.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | libzahl_realloc(z_t a, size_t need) 7 | { 8 | size_t i, new_size = 1; 9 | zahl_char_t *new; 10 | 11 | new_size <<= i = libzahl_msb_nz_zu(need); 12 | if (likely(new_size != need)) { 13 | i += 1; 14 | new_size <<= 1; 15 | } 16 | 17 | if (likely(libzahl_pool_n[i])) { 18 | libzahl_pool_n[i]--; 19 | new = libzahl_pool[i][libzahl_pool_n[i]]; 20 | zmemcpy(new, a->chars, a->alloced); 21 | zfree(a); 22 | a->chars = new; 23 | } else { 24 | a->chars = realloc(a->chars, (new_size + ZAHL_FLUFF) * sizeof(zahl_char_t)); 25 | if (check(!a->chars)) 26 | libzahl_memfailure(); 27 | } 28 | a->alloced = new_size; 29 | } 30 | -------------------------------------------------------------------------------- /src/zadd.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | #if defined(__x86_64__) && !defined(ZAHL_NO_ASM) 6 | # define ASM3(code) \ 7 | __asm__ __volatile__ (code : [x]"+r"(carry), [a]"+r"(ac), [b]"+r"(bc), [c]"+r"(cc)) 8 | 9 | # define ASM2(code) \ 10 | __asm__ __volatile__ (code : [x]"+r"(carry), [a]"+r"(ac), [b]"+r"(bc)) 11 | 12 | # define ADD2(off) \ 13 | "\n movq "#off"(%[b]), %[x]" \ 14 | "\n adcq %[x], "#off"(%[a])" 15 | 16 | # define ADD3(off) \ 17 | "\n movq "#off"(%[b]), %[x]" \ 18 | "\n adcq "#off"(%[c]), %[x]" \ 19 | "\n movq %[x], "#off"(%[a])" 20 | 21 | # define WRAP_CARRY(interior) \ 22 | "\n addq $-1, %[x]" \ 23 | interior \ 24 | "\n movq $1, %[x]" \ 25 | "\n jc 1f" \ 26 | "\n movq $0, %[x]" \ 27 | "\n 1:" 28 | /* 29 | * I have already tried setc, cmovnc, cmovc, and adc, 30 | * instead of the last four lines. There does not seem 31 | * to be any better why to store the carry flag. 32 | */ 33 | 34 | # define ASM_ADD(N) \ 35 | do { \ 36 | register zahl_char_t carry = 0; \ 37 | size_t i; \ 38 | for (i = 0; (INC(4)), (i += 4) <= n;) \ 39 | ASM##N(WRAP_CARRY(ADD##N(-32) ADD##N(-24) ADD##N(-16) ADD##N(-8))); \ 40 | switch (n & 3) { \ 41 | case 3: \ 42 | ASM##N(WRAP_CARRY(ADD##N(-32) ADD##N(-24) ADD##N(-16))); \ 43 | break; \ 44 | case 2: \ 45 | ASM##N(WRAP_CARRY(ADD##N(-32) ADD##N(-24))); \ 46 | break; \ 47 | case 1: \ 48 | ASM##N(WRAP_CARRY(ADD##N(-32))); \ 49 | break; \ 50 | default: \ 51 | break; \ 52 | } \ 53 | i = n; \ 54 | while (carry) { \ 55 | carry = libzahl_add_overflow(a->chars + i, a->chars[i], 1); \ 56 | i++; \ 57 | } \ 58 | if (a->used < i) \ 59 | a->used = i; \ 60 | } while (0) 61 | #endif 62 | 63 | 64 | static inline void 65 | zadd_impl_4(z_t a, z_t b, z_t c, size_t n) 66 | { 67 | #ifdef ASM_ADD 68 | register zahl_char_t *ac = a->chars, *bc = b->chars, *cc = c->chars; 69 | # define INC(P) (ac += (P), bc += (P), cc += (P)) 70 | ASM_ADD(3); 71 | # undef INC 72 | #else 73 | zahl_char_t carry = 0, tcarry; 74 | zahl_char_t *ac = a->chars, *bc = b->chars, *cc = c->chars; 75 | size_t i; 76 | 77 | for (i = 0; i < n; i++) { 78 | tcarry = libzahl_add_overflow(ac + i, bc[i], cc[i]); 79 | carry = tcarry | (zahl_char_t)libzahl_add_overflow(ac + i, ac[i], carry); 80 | } 81 | 82 | while (carry) { 83 | carry = libzahl_add_overflow(ac + i, ac[i], 1); 84 | i++; 85 | } 86 | 87 | if (a->used < i) 88 | a->used = i; 89 | #endif 90 | } 91 | 92 | static inline void 93 | zadd_impl_3(z_t a, z_t b, size_t n) 94 | { 95 | #ifdef ASM_ADD 96 | register zahl_char_t *ac = a->chars, *bc = b->chars; 97 | # define INC(P) (ac += (P), bc += (P)) 98 | ASM_ADD(2); 99 | # undef INC 100 | #else 101 | zadd_impl_4(a, a, b, n); 102 | #endif 103 | } 104 | 105 | static inline void 106 | libzahl_zadd_unsigned(z_t a, z_t b, z_t c) 107 | { 108 | size_t size, n; 109 | 110 | if (unlikely(zzero(b))) { 111 | zabs(a, c); 112 | return; 113 | } else if (unlikely(zzero(c))) { 114 | zabs(a, b); 115 | return; 116 | } 117 | 118 | size = MAX(b->used, c->used); 119 | n = b->used + c->used - size; 120 | 121 | ENSURE_SIZE(a, size + 1); 122 | a->chars[size] = 0; 123 | 124 | if (a == b) { 125 | if (a->used < c->used) { 126 | n = c->used; 127 | zmemset(a->chars + a->used, 0, n - a->used); 128 | } 129 | zadd_impl_3(a, c, n); 130 | } else if (unlikely(a == c)) { 131 | if (a->used < b->used) { 132 | n = b->used; 133 | zmemset(a->chars + a->used, 0, n - a->used); 134 | } 135 | zadd_impl_3(a, b, n); 136 | } else if (likely(b->used > c->used)) { 137 | zmemcpy(a->chars + n, b->chars + n, size - n); 138 | a->used = size; 139 | zadd_impl_4(a, b, c, n); 140 | } else { 141 | zmemcpy(a->chars + n, c->chars + n, size - n); 142 | a->used = size; 143 | zadd_impl_4(a, b, c, n); 144 | } 145 | 146 | SET_SIGNUM(a, 1); 147 | } 148 | 149 | void 150 | zadd_unsigned(z_t a, z_t b, z_t c) 151 | { 152 | libzahl_zadd_unsigned(a, b, c); 153 | } 154 | 155 | void 156 | zadd_unsigned_assign(z_t a, z_t b) 157 | { 158 | size_t size, n; 159 | 160 | if (unlikely(zzero(a))) { 161 | zabs(a, b); 162 | return; 163 | } else if (unlikely(zzero(b))) { 164 | return; 165 | } 166 | 167 | size = MAX(a->used, b->used); 168 | n = a->used + b->used - size; 169 | 170 | ENSURE_SIZE(a, size + 1); 171 | a->chars[size] = 0; 172 | 173 | if (a->used < b->used) { 174 | n = b->used; 175 | zmemset(a->chars + a->used, 0, n - a->used); 176 | } 177 | zadd_impl_3(a, b, n); 178 | 179 | SET_SIGNUM(a, 1); 180 | } 181 | 182 | void 183 | zadd(z_t a, z_t b, z_t c) 184 | { 185 | if (unlikely(zzero(b))) { 186 | SET(a, c); 187 | } else if (unlikely(zzero(c))) { 188 | SET(a, b); 189 | } else if (unlikely(znegative(b))) { 190 | if (znegative(c)) { 191 | libzahl_zadd_unsigned(a, b, c); 192 | SET_SIGNUM(a, -zsignum(a)); 193 | } else { 194 | zsub_unsigned(a, c, b); 195 | } 196 | } else if (unlikely(znegative(c))) { 197 | zsub_unsigned(a, b, c); 198 | } else { 199 | libzahl_zadd_unsigned(a, b, c); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/zand.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | zand(z_t a, z_t b, z_t c) 7 | { 8 | /* Yes, you are reading this right. It's an optimisation. */ 9 | if (unlikely(zzero(b))) { 10 | SET_SIGNUM(a, 0); 11 | return; 12 | } else if (unlikely(zzero(c))) { 13 | SET_SIGNUM(a, 0); 14 | return; 15 | } 16 | 17 | a->used = MIN(b->used, c->used); 18 | 19 | if (a == b) { 20 | ZMEM_2OP(a->chars, a->chars, c->chars, a->used, &); 21 | } else if (unlikely(a == c)) { 22 | ZMEM_2OP(a->chars, a->chars, b->chars, a->used, &); 23 | } else { 24 | ENSURE_SIZE(a, a->used); 25 | ZMEM_2OP(a->chars, b->chars, c->chars, a->used, &); 26 | } 27 | 28 | TRIM_AND_SIGN(a, zpositive1(b, c) * 2 - 1); 29 | } 30 | -------------------------------------------------------------------------------- /src/zbset.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | #define PROLOGUE(MAY_INCREASE)\ 6 | zahl_char_t mask = 1;\ 7 | size_t chars = FLOOR_BITS_TO_CHARS(bit);\ 8 | if (MAY_INCREASE) {\ 9 | if (zzero(a)) {\ 10 | a->used = 0;\ 11 | SET_SIGNUM(a, 1);\ 12 | }\ 13 | if (unlikely(chars >= a->used)) {\ 14 | ENSURE_SIZE(a, chars + 1);\ 15 | zmemset(a->chars + a->used, 0, chars + 1 - a->used);\ 16 | a->used = chars + 1;\ 17 | }\ 18 | } else if (unlikely(chars >= a->used)) {\ 19 | return;\ 20 | }\ 21 | bit = BITS_IN_LAST_CHAR(bit);\ 22 | mask <<= bit 23 | 24 | 25 | void 26 | zbset_ll_set(z_t a, size_t bit) 27 | { 28 | PROLOGUE(1); 29 | a->chars[chars] |= mask; 30 | } 31 | 32 | void 33 | zbset_ll_clear(z_t a, size_t bit) 34 | { 35 | PROLOGUE(0); 36 | a->chars[chars] &= ~mask; 37 | TRIM_AND_ZERO(a); 38 | } 39 | 40 | void 41 | zbset_ll_flip(z_t a, size_t bit) 42 | { 43 | PROLOGUE(1); 44 | a->chars[chars] ^= mask; 45 | TRIM_AND_ZERO(a); 46 | } 47 | -------------------------------------------------------------------------------- /src/zdivmod.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #define ta libzahl_tmp_divmod_a 5 | #define tb libzahl_tmp_divmod_b 6 | #define td libzahl_tmp_divmod_d 7 | #define tds_proper libzahl_tmp_divmod_ds 8 | 9 | 10 | static inline void 11 | zdivmod_impl(z_t a, z_t b, z_t c, z_t d) 12 | { 13 | size_t c_bits, d_bits, bit, i; 14 | static z_t tds[BITS_PER_CHAR]; 15 | 16 | c_bits = zbits(c); 17 | d_bits = zbits(d); 18 | 19 | bit = c_bits - d_bits; 20 | zlsh(td, d, bit); 21 | SET_SIGNUM(td, 1); 22 | if (zcmpmag(td, c) > 0) { 23 | zrsh(td, td, 1); 24 | bit -= 1; 25 | } 26 | 27 | SET_SIGNUM(ta, 0); 28 | zabs(tb, c); 29 | 30 | if (unlikely(bit <= BITS_PER_CHAR)) { 31 | for (;;) { 32 | if (zcmpmag(td, tb) <= 0) { 33 | zsub_unsigned(tb, tb, td); 34 | zbset(ta, ta, bit, 1); 35 | } 36 | if (!bit-- || zzero(tb)) 37 | goto done; 38 | zrsh(td, td, 1); 39 | } 40 | } else { 41 | for (i = 0; i < BITS_PER_CHAR; i++) { 42 | zrsh(tds_proper[i], td, i); 43 | tds[i]->used = tds_proper[i]->used; 44 | tds[i]->sign = tds_proper[i]->sign; 45 | tds[i]->chars = tds_proper[i]->chars; 46 | } 47 | for (;;) { 48 | for (i = 0; i < BITS_PER_CHAR; i++) { 49 | if (zcmpmag(tds[i], tb) <= 0) { 50 | zsub_unsigned(tb, tb, tds[i]); 51 | zbset(ta, ta, bit, 1); 52 | } 53 | if (!bit-- || zzero(tb)) 54 | goto done; 55 | } 56 | for (i = MIN(bit, BITS_PER_CHAR - 1) + 1; i--;) 57 | zrsh_taint(tds[i], BITS_PER_CHAR); 58 | } 59 | } 60 | done: 61 | 62 | zswap(a, ta); 63 | zswap(b, tb); 64 | } 65 | 66 | 67 | void 68 | zdivmod(z_t a, z_t b, z_t c, z_t d) 69 | { 70 | int c_sign, sign, cmpmag; 71 | 72 | c_sign = zsignum(c); 73 | sign = c_sign * zsignum(d); 74 | 75 | if (unlikely(!sign)) { 76 | if (check(!zzero(c))) { 77 | libzahl_failure(-ZERROR_DIV_0); 78 | } else if (check(zzero(d))) { 79 | libzahl_failure(-ZERROR_0_DIV_0); 80 | } else { 81 | SET_SIGNUM(a, 0); 82 | SET_SIGNUM(b, 0); 83 | } 84 | return; 85 | } else if (cmpmag = zcmpmag(c, d), unlikely(cmpmag <= 0)) { 86 | if (unlikely(cmpmag == 0)) { 87 | zseti(a, sign); 88 | SET_SIGNUM(b, 0); 89 | } else { 90 | SET(b, c); 91 | SET_SIGNUM(a, 0); 92 | } 93 | return; 94 | } 95 | 96 | zdivmod_impl(a, b, c, d); 97 | SET_SIGNUM(a, sign); 98 | if (zsignum(b) > 0) 99 | SET_SIGNUM(b, c_sign); 100 | } 101 | -------------------------------------------------------------------------------- /src/zerror.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | #define LIST_ERRORS\ 6 | X(ZERROR_0_POW_0, "indeterminate form: 0:th power of 0")\ 7 | X(ZERROR_0_DIV_0, "indeterminate form: 0 divided by 0")\ 8 | X(ZERROR_DIV_0, "undefined result: division by 0")\ 9 | X(ZERROR_NEGATIVE, "argument must be non-negative") 10 | 11 | 12 | enum zerror 13 | zerror(const char **desc) 14 | { 15 | if (libzahl_error >= 0) { 16 | if (desc) 17 | *desc = strerror(libzahl_error); 18 | errno = libzahl_error; 19 | return ZERROR_ERRNO_SET; 20 | } 21 | 22 | if (desc) { 23 | switch (-libzahl_error) { 24 | #define X(V, D) case V: *desc = D; break; 25 | LIST_ERRORS 26 | #undef X 27 | default: 28 | abort(); 29 | } 30 | } 31 | return -libzahl_error; 32 | } 33 | -------------------------------------------------------------------------------- /src/zfree.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | zfree(z_t a) 7 | { 8 | size_t i, x, j; 9 | zahl_char_t **new; 10 | 11 | if (unlikely(!a->chars)) 12 | return; 13 | 14 | i = libzahl_msb_nz_zu(a->alloced); 15 | j = libzahl_pool_n[i]++; 16 | 17 | if (j == libzahl_pool_alloc[i]) { 18 | x = j ? ((j * 3) >> 1) : 128; 19 | new = realloc(libzahl_pool[i], x * sizeof(zahl_char_t *)); 20 | if (check(!new)) { 21 | free(a->chars); 22 | free(libzahl_pool[i]); 23 | libzahl_pool_n[i] = 0; 24 | libzahl_pool[i] = 0; 25 | libzahl_pool_alloc[i] = 0; 26 | return; 27 | } 28 | libzahl_pool[i] = new; 29 | libzahl_pool_alloc[i] = x; 30 | } 31 | 32 | libzahl_pool[i][j] = a->chars; 33 | } 34 | -------------------------------------------------------------------------------- /src/zgcd.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #define u libzahl_tmp_gcd_u 5 | #define v libzahl_tmp_gcd_v 6 | 7 | 8 | void 9 | zgcd(z_t a, z_t b, z_t c) 10 | { 11 | /* 12 | * Binary GCD algorithm. 13 | */ 14 | 15 | size_t shifts; 16 | zahl_char_t *u_orig, *v_orig; 17 | size_t u_lsb, v_lsb; 18 | int neg, cmpmag; 19 | 20 | if (unlikely(zzero(b))) { 21 | SET(a, c); 22 | return; 23 | } 24 | if (unlikely(zzero(c))) { 25 | SET(a, b); 26 | return; 27 | } 28 | 29 | neg = znegative2(b, c); 30 | 31 | u_lsb = zlsb(b); 32 | v_lsb = zlsb(c); 33 | shifts = MIN(u_lsb, v_lsb); 34 | zrsh(u, b, u_lsb); 35 | zrsh(v, c, v_lsb); 36 | 37 | u_orig = u->chars; 38 | v_orig = v->chars; 39 | 40 | for (;;) { 41 | if (likely((cmpmag = zcmpmag(u, v)) >= 0)) { 42 | if (unlikely(cmpmag == 0)) 43 | break; 44 | zswap_tainted_unsigned(u, v); 45 | } 46 | zsub_positive_assign(v, u); 47 | zrsh_taint(v, zlsb(v)); 48 | } 49 | 50 | zlsh(a, u, shifts); 51 | SET_SIGNUM(a, neg ? -1 : 1); 52 | 53 | u->chars = u_orig; 54 | v->chars = v_orig; 55 | } 56 | -------------------------------------------------------------------------------- /src/zload.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | size_t 6 | zload(z_t a, const void *buffer) 7 | { 8 | const char *buf = buffer; 9 | a->sign = (int)*((const long *)buf), buf += sizeof(long); 10 | a->used = *((const size_t *)buf), buf += sizeof(size_t); 11 | if (likely(a->sign)) { 12 | ENSURE_SIZE(a, a->used); 13 | zmemcpy(a->chars, (const zahl_char_t *)buf, a->used); 14 | } 15 | return sizeof(long) + sizeof(size_t) + 16 | (zzero(a) ? 0 : ((a->used + 3) & (size_t)~3) * sizeof(zahl_char_t)); 17 | } 18 | -------------------------------------------------------------------------------- /src/zlsh.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | zlsh(z_t a, z_t b, size_t bits) 7 | { 8 | size_t i, chars, cbits; 9 | zahl_char_t carry = 0, tcarry; 10 | 11 | if (unlikely(zzero(b))) { 12 | SET_SIGNUM(a, 0); 13 | return; 14 | } 15 | 16 | chars = FLOOR_BITS_TO_CHARS(bits); 17 | bits = BITS_IN_LAST_CHAR(bits); 18 | cbits = BITS_PER_CHAR - bits; 19 | 20 | ENSURE_SIZE(a, b->used + chars + 1); 21 | if (likely(a == b)) { 22 | zmemmoveb(a->chars + chars, b->chars, b->used); 23 | } else { 24 | zmemcpy(a->chars + chars, b->chars, b->used); 25 | } 26 | zmemset_precise(a->chars, 0, chars); 27 | a->used = b->used + chars; 28 | 29 | if (likely(bits)) { /* This if statement is very important in C. */ 30 | for (i = chars; i < a->used; i++) { 31 | tcarry = a->chars[i] >> cbits; 32 | a->chars[i] <<= bits; 33 | a->chars[i] |= carry; 34 | carry = tcarry; 35 | } 36 | if (carry) 37 | a->chars[a->used++] = carry; 38 | } 39 | 40 | SET_SIGNUM(a, zsignum(b)); 41 | } 42 | -------------------------------------------------------------------------------- /src/zmodmul.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | zmodmul(z_t a, z_t b, z_t c, z_t d) 7 | { 8 | /* TODO Montgomery modular multiplication */ 9 | /* TODO Kochanski multiplication */ 10 | if (unlikely(a == d)) { 11 | zset(libzahl_tmp_modmul, d); 12 | zmul(a, b, c); 13 | zmod(a, a, libzahl_tmp_modmul); 14 | } else { 15 | zmul(a, b, c); 16 | zmod(a, a, d); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/zmodpow.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #define tb libzahl_tmp_pow_b 5 | #define tc libzahl_tmp_pow_c 6 | #define td libzahl_tmp_pow_d 7 | 8 | 9 | void 10 | zmodpow(z_t a, z_t b, z_t c, z_t d) 11 | { 12 | size_t i, j, n, bits; 13 | zahl_char_t x; 14 | 15 | /* TODO use zmodpowu when possible */ 16 | 17 | if (unlikely(zsignum(c) <= 0)) { 18 | if (zzero(c)) { 19 | if (check(zzero(b))) 20 | libzahl_failure(-ZERROR_0_POW_0); 21 | else if (check(zzero(d))) 22 | libzahl_failure(-ZERROR_DIV_0); 23 | zsetu(a, 1); 24 | } else if (check(zzero1(b, d))) { 25 | libzahl_failure(-ZERROR_DIV_0); 26 | } else { 27 | SET_SIGNUM(a, 0); 28 | } 29 | return; 30 | } else if (check(zzero(d))) { 31 | libzahl_failure(-ZERROR_DIV_0); 32 | } else if (unlikely(zzero(b))) { 33 | SET_SIGNUM(a, 0); 34 | return; 35 | } 36 | 37 | bits = zbits(c); 38 | n = FLOOR_BITS_TO_CHARS(bits); 39 | 40 | zmod(tb, b, d); 41 | zset(tc, c); 42 | zset(td, d); 43 | zsetu(a, 1); 44 | 45 | for (i = 0; i < n; i++) { /* Remember, n is floored. */ 46 | x = tc->chars[i]; 47 | for (j = BITS_PER_CHAR; j--; x >>= 1) { 48 | if (x & 1) 49 | zmodmul(a, a, tb, td); 50 | zmodsqr(tb, tb, td); 51 | } 52 | } 53 | x = tc->chars[i]; 54 | for (; x; x >>= 1) { 55 | if (x & 1) 56 | zmodmul(a, a, tb, td); 57 | zmodsqr(tb, tb, td); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/zmodpowu.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #define tb libzahl_tmp_pow_b 5 | #define td libzahl_tmp_pow_d 6 | 7 | 8 | void 9 | zmodpowu(z_t a, z_t b, unsigned long long int c, z_t d) 10 | { 11 | if (unlikely(!c)) { 12 | if (check(zzero(b))) 13 | libzahl_failure(-ZERROR_0_POW_0); 14 | else if (check(zzero(d))) 15 | libzahl_failure(-ZERROR_DIV_0); 16 | else 17 | zsetu(a, 1); 18 | return; 19 | } else if (check(zzero(d))) { 20 | libzahl_failure(-ZERROR_DIV_0); 21 | } else if (unlikely(zzero(b))) { 22 | SET_SIGNUM(a, 0); 23 | return; 24 | } 25 | 26 | zmod(tb, b, d); 27 | zset(td, d); 28 | 29 | if (c & 1) 30 | zset(a, tb); 31 | else 32 | zsetu(a, 1); 33 | while (c >>= 1) { 34 | zmodsqr(tb, tb, td); 35 | if (c & 1) 36 | zmodmul(a, a, tb, td); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/zmodsqr.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | zmodsqr(z_t a, z_t b, z_t c) 7 | { 8 | /* TODO What is the fastest way to do zmodsqr? */ 9 | if (unlikely(a == c)) { 10 | zset(libzahl_tmp_modsqr, c); 11 | zsqr(a, b); 12 | zmod(a, a, libzahl_tmp_modsqr); 13 | } else { 14 | zsqr(a, b); 15 | zmod(a, a, c); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/zmul.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | static inline void 6 | zmul_ll_single_char(z_t a, z_t b, z_t c) 7 | { 8 | ENSURE_SIZE(a, 1); 9 | a->used = 1; 10 | a->chars[0] = b->chars[0] * c->chars[0]; 11 | SET_SIGNUM(a, 1); 12 | } 13 | 14 | void 15 | zmul_ll(z_t a, z_t b, z_t c) 16 | { 17 | /* 18 | * Karatsuba algorithm 19 | * 20 | * Basically, this is how you were taught to multiply large numbers 21 | * by hand in school: 4010⋅3020 = (4000 + 10)(3000 + 20) = 22 | * = 40⋅30⋅10⁴ + (40⋅20 + 30⋅10)⋅10² + 10⋅20, but the middle is 23 | * optimised to only one multiplication: 24 | * 40⋅20 + 30⋅10 = (40 + 10)(30 + 20) − 40⋅30 − 10⋅20. 25 | * This optimisation is crucial. Without it, the algorithm with 26 | * run in O(n²). 27 | */ 28 | 29 | #define z2 c_low 30 | #define z1 b_low 31 | #define z0 a 32 | size_t m, m2; 33 | z_t b_high, b_low, c_high, c_low; 34 | 35 | if (unlikely(zzero1(b, c))) { 36 | SET_SIGNUM(a, 0); 37 | return; 38 | } 39 | 40 | m = zbits(b); 41 | m2 = b == c ? m : zbits(c); 42 | 43 | if (m + m2 <= BITS_PER_CHAR) { 44 | zmul_ll_single_char(a, b, c); 45 | return; 46 | } 47 | 48 | m = MAX(m, m2); 49 | m2 = m >> 1; 50 | 51 | zinit_temp(b_high); 52 | zinit_temp(b_low); 53 | zinit_temp(c_high); 54 | zinit_temp(c_low); 55 | 56 | zsplit_pz(b_high, b_low, b, m2); 57 | zsplit_pz(c_high, c_low, c, m2); 58 | 59 | 60 | zmul_ll(z0, b_low, c_low); 61 | zadd_unsigned_assign(b_low, b_high); 62 | zadd_unsigned_assign(c_low, c_high); 63 | zmul_ll(z1, b_low, c_low); 64 | zmul_ll(z2, b_high, c_high); 65 | 66 | zsub_nonnegative_assign(z1, z0); 67 | zsub_nonnegative_assign(z1, z2); 68 | 69 | zlsh(z1, z1, m2); 70 | m2 <<= 1; 71 | zlsh(z2, z2, m2); 72 | zadd_unsigned_assign(a, z1); 73 | zadd_unsigned_assign(a, z2); 74 | 75 | 76 | zfree_temp(c_low); 77 | zfree_temp(c_high); 78 | zfree_temp(b_low); 79 | zfree_temp(b_high); 80 | } 81 | -------------------------------------------------------------------------------- /src/znot.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | znot(z_t a, z_t b) 7 | { 8 | size_t bits; 9 | 10 | if (unlikely(zzero(b))) { 11 | SET_SIGNUM(a, 0); 12 | return; 13 | } 14 | 15 | bits = zbits(b); 16 | a->used = b->used; 17 | SET_SIGNUM(a, -zsignum(b)); 18 | 19 | ZMEM_1OP(a->chars, b->chars, a->used, ~); 20 | bits = BITS_IN_LAST_CHAR(bits); 21 | if (bits) 22 | a->chars[a->used - 1] &= ((zahl_char_t)1 << bits) - 1; 23 | 24 | TRIM_AND_ZERO(a); 25 | } 26 | -------------------------------------------------------------------------------- /src/zor.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | zor(z_t a, z_t b, z_t c) 7 | { 8 | size_t n, m; 9 | 10 | if (unlikely(zzero(b))) { 11 | SET(a, c); 12 | return; 13 | } else if (unlikely(zzero(c))) { 14 | SET(a, b); 15 | return; 16 | } 17 | 18 | MIN_MAX_1(n, m, b->used, c->used); 19 | ENSURE_SIZE(a, m); 20 | 21 | if (a == b) { 22 | ZMEM_2OP_PRECISE(a->chars, a->chars, c->chars, n, |); 23 | if (a->used < c->used) 24 | zmemcpy_range(a->chars, c->chars, n, m); 25 | } else if (unlikely(a == c)) { 26 | ZMEM_2OP_PRECISE(a->chars, a->chars, b->chars, n, |); 27 | if (a->used < b->used) 28 | zmemcpy_range(a->chars, b->chars, n, m); 29 | } else if (m == b->used) { 30 | ZMEM_2OP(a->chars, c->chars, b->chars, n, |); 31 | zmemcpy_range(a->chars, b->chars, n, m); 32 | } else { 33 | ZMEM_2OP(a->chars, b->chars, c->chars, n, |); 34 | zmemcpy_range(a->chars, c->chars, n, m); 35 | } 36 | 37 | a->used = m; 38 | SET_SIGNUM(a, zpositive2(b, c) * 2 - 1); 39 | } 40 | -------------------------------------------------------------------------------- /src/zperror.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #include 5 | 6 | 7 | void 8 | zperror(const char *prefix) 9 | { 10 | if (libzahl_error >= 0) { 11 | errno = libzahl_error; 12 | perror(prefix); 13 | } else { 14 | const char *desc; 15 | zerror(&desc); 16 | if (prefix && *prefix) 17 | fprintf(stderr, "%s: %s\n", prefix, desc); 18 | else 19 | fprintf(stderr, "%s\n", desc); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/zpow.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #define tb libzahl_tmp_pow_b 5 | #define tc libzahl_tmp_pow_c 6 | 7 | 8 | void 9 | zpow(z_t a, z_t b, z_t c) 10 | { 11 | /* 12 | * Exponentiation by squaring. 13 | * 14 | * 7↑19 = 7↑10011₂ = 7↑2⁰ ⋅ 7↑2¹ ⋅ 7↑2⁴ where a↑2↑(n + 1) = (a↑2↑n)². 15 | */ 16 | 17 | /* TODO use zpowu when possible */ 18 | 19 | size_t i, j, n, bits; 20 | zahl_char_t x; 21 | int neg; 22 | 23 | if (unlikely(zsignum(c) <= 0)) { 24 | if (zzero(c)) { 25 | if (check(zzero(b))) 26 | libzahl_failure(-ZERROR_0_POW_0); 27 | zsetu(a, 1); 28 | } else if (check(zzero(b))) { 29 | libzahl_failure(-ZERROR_DIV_0); 30 | } else { 31 | SET_SIGNUM(a, 0); 32 | } 33 | return; 34 | } else if (unlikely(zzero(b))) { 35 | SET_SIGNUM(a, 0); 36 | return; 37 | } 38 | 39 | bits = zbits(c); 40 | n = FLOOR_BITS_TO_CHARS(bits); 41 | 42 | neg = znegative(b) && zodd(c); 43 | zabs(tb, b); 44 | zset(tc, c); 45 | zsetu(a, 1); 46 | 47 | for (i = 0; i < n; i++) { /* Remember, n is floored. */ 48 | x = tc->chars[i]; 49 | for (j = BITS_PER_CHAR; j--; x >>= 1) { 50 | if (x & 1) 51 | zmul_ll(a, a, tb); 52 | zsqr_ll(tb, tb); 53 | } 54 | } 55 | x = tc->chars[i]; 56 | for (; x; x >>= 1) { 57 | if (x & 1) 58 | zmul_ll(a, a, tb); 59 | zsqr_ll(tb, tb); 60 | } 61 | 62 | if (neg) 63 | zneg(a, a); 64 | } 65 | -------------------------------------------------------------------------------- /src/zpowu.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #define tb libzahl_tmp_pow_b 5 | 6 | 7 | void 8 | zpowu(z_t a, z_t b, unsigned long long int c) 9 | { 10 | int neg; 11 | 12 | if (unlikely(!c)) { 13 | if (check(zzero(b))) 14 | libzahl_failure(-ZERROR_0_POW_0); 15 | zsetu(a, 1); 16 | return; 17 | } else if (unlikely(zzero(b))) { 18 | SET_SIGNUM(a, 0); 19 | return; 20 | } 21 | 22 | neg = znegative(b) && (c & 1); 23 | zabs(tb, b); 24 | 25 | if (c & 1) 26 | zset(a, tb); 27 | else 28 | zsetu(a, 1); 29 | while (c >>= 1) { 30 | zsqr_ll(tb, tb); 31 | if (c & 1) 32 | zmul_ll(a, a, tb); 33 | } 34 | 35 | if (neg) 36 | zneg(a, a); 37 | } 38 | -------------------------------------------------------------------------------- /src/zptest.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #define x libzahl_tmp_ptest_x 5 | #define a libzahl_tmp_ptest_a 6 | #define d libzahl_tmp_ptest_d 7 | #define n1 libzahl_tmp_ptest_n1 8 | #define n4 libzahl_tmp_ptest_n4 9 | 10 | 11 | enum zprimality 12 | zptest(z_t witness, z_t n, int t) 13 | { 14 | /* 15 | * Miller–Rabin primarlity test. 16 | */ 17 | 18 | size_t i, r; 19 | 20 | if (unlikely(zcmpu(n, 3) <= 0)) { 21 | if (zcmpu(n, 1) <= 0) { 22 | if (witness) 23 | SET(witness, n); 24 | return NONPRIME; 25 | } else { 26 | return PRIME; 27 | } 28 | } 29 | if (unlikely(zeven(n))) { 30 | if (witness) 31 | zsetu(witness, 2); 32 | return NONPRIME; 33 | } 34 | 35 | zsub_unsigned(n1, n, libzahl_const_1); 36 | zsub_unsigned(n4, n, libzahl_const_4); 37 | 38 | r = zlsb(n1); 39 | zrsh(d, n1, r); 40 | 41 | while (t--) { 42 | zrand(a, DEFAULT_RANDOM, UNIFORM, n4); 43 | zadd_unsigned(a, a, libzahl_const_2); 44 | zmodpow(x, a, d, n); 45 | 46 | if (!zcmp(x, libzahl_const_1) || !zcmp(x, n1)) 47 | continue; 48 | 49 | for (i = 1; i < r; i++) { 50 | zmodsqr(x, x, n); 51 | if (!zcmp(x, libzahl_const_1)) { 52 | if (witness) 53 | zswap(witness, a); 54 | return NONPRIME; 55 | } 56 | if (!zcmp(x, n1)) 57 | break; 58 | } 59 | if (i == r) { 60 | if (witness) 61 | zswap(witness, a); 62 | return NONPRIME; 63 | } 64 | } 65 | 66 | return PROBABLY_PRIME; 67 | } 68 | -------------------------------------------------------------------------------- /src/zrand.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef FAST_RANDOM_PATHNAME 10 | # define FAST_RANDOM_PATHNAME "/dev/urandom" 11 | #endif 12 | 13 | #ifndef SECURE_RANDOM_PATHNAME 14 | # define SECURE_RANDOM_PATHNAME "/dev/random" 15 | #endif 16 | 17 | 18 | static void 19 | zrand_libc_rand(void *out, size_t n, void *statep) 20 | { 21 | static char inited = 0; 22 | 23 | unsigned int ri; 24 | double rd; 25 | unsigned char *buf = out; 26 | 27 | if (!inited) { 28 | inited = 1; 29 | srand((unsigned)((intptr_t)out | time(NULL))); 30 | } 31 | 32 | while (n--) { 33 | ri = (unsigned)rand(); 34 | rd = (double)ri / ((double)RAND_MAX + 1); 35 | #ifdef GOOD_RAND 36 | rd *= 256 * 256; 37 | ri = (unsigned int)rd; 38 | buf[n] = (unsigned char)((ri >> 0) & 255); 39 | if (!n--) break; 40 | buf[n] = (unsigned char)((ri >> 8) & 255); 41 | #else 42 | rd *= 256; 43 | buf[n] = (unsigned char)rd; 44 | #endif 45 | } 46 | 47 | (void) statep; 48 | } 49 | 50 | static void 51 | zrand_libc_rand48(void *out, size_t n, void *statep) 52 | { 53 | static char inited = 0; 54 | 55 | long int r0, r1; 56 | unsigned char *buf = out; 57 | 58 | if (!inited) { 59 | inited = 1; 60 | srand48((intptr_t)out | time(NULL)); 61 | } 62 | 63 | while (n--) { 64 | r0 = lrand48() & 15; 65 | r1 = lrand48() & 15; 66 | buf[n] = (unsigned char)((r0 << 4) | r1); 67 | } 68 | 69 | (void) statep; 70 | } 71 | 72 | static void 73 | zrand_libc_random(void *out, size_t n, void *statep) 74 | { 75 | static char inited = 0; 76 | 77 | long int ri; 78 | unsigned char *buf = out; 79 | 80 | if (!inited) { 81 | inited = 1; 82 | srandom((unsigned)((intptr_t)out | time(NULL))); 83 | } 84 | 85 | while (n--) { 86 | ri = random(); 87 | buf[n] = (unsigned char)((ri >> 0) & 255); 88 | if (!n--) break; 89 | buf[n] = (unsigned char)((ri >> 8) & 255); 90 | if (!n--) break; 91 | buf[n] = (unsigned char)((ri >> 16) & 255); 92 | } 93 | 94 | (void) statep; 95 | } 96 | 97 | static void 98 | zrand_fd(void *out, size_t n, void *statep) 99 | { 100 | int fd = *(int *)statep; 101 | ssize_t read_just; 102 | size_t read_total = 0; 103 | char *buf = out; 104 | 105 | while (n) { 106 | read_just = read(fd, buf + read_total, n); 107 | if (check(read_just < 0)) 108 | libzahl_failure(errno); 109 | read_total += (size_t)read_just; 110 | n -= (size_t)read_just; 111 | } 112 | } 113 | 114 | static void 115 | zrand_get_random_bits(z_t r, size_t bits, void (*fun)(void *, size_t, void *), void *statep) 116 | { 117 | size_t n, chars = CEILING_BITS_TO_CHARS(bits); 118 | zahl_char_t mask = 1; 119 | 120 | ENSURE_SIZE(r, chars); 121 | 122 | fun(r->chars, chars * sizeof(zahl_char_t), statep); 123 | 124 | bits = BITS_IN_LAST_CHAR(bits); 125 | mask <<= bits; 126 | mask -= 1; 127 | 128 | r->chars[chars - 1] &= mask; 129 | for (n = chars; n--;) { 130 | if (likely(r->chars[n])) { 131 | r->used = n + 1; 132 | SET_SIGNUM(r, 1); 133 | return; 134 | } 135 | } 136 | SET_SIGNUM(r, 0); 137 | } 138 | 139 | void 140 | zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n) 141 | { 142 | #define RANDOM_UNIFORM(RETRY)\ 143 | do {\ 144 | if (check(znegative(n)))\ 145 | libzahl_failure(-ZERROR_NEGATIVE);\ 146 | bits = zbits(n);\ 147 | do\ 148 | zrand_get_random_bits(r, bits, random_fun, statep);\ 149 | while (RETRY && unlikely(zcmpmag(r, n) > 0));\ 150 | } while (0) 151 | 152 | 153 | const char *pathname = 0; 154 | size_t bits; 155 | int fd = -1; 156 | void *statep = 0; 157 | void (*random_fun)(void *, size_t, void *) = &zrand_fd; 158 | 159 | switch (dev) { 160 | case FAST_RANDOM: 161 | pathname = FAST_RANDOM_PATHNAME; 162 | break; 163 | case SECURE_RANDOM: 164 | pathname = SECURE_RANDOM_PATHNAME; 165 | break; 166 | case LIBC_RAND_RANDOM: 167 | random_fun = &zrand_libc_rand; 168 | break; 169 | case DEFAULT_RANDOM: 170 | case FASTEST_RANDOM: 171 | case LIBC_RANDOM_RANDOM: 172 | random_fun = &zrand_libc_random; 173 | break; 174 | case LIBC_RAND48_RANDOM: 175 | random_fun = &zrand_libc_rand48; 176 | break; 177 | default: 178 | libzahl_failure(EINVAL); 179 | } 180 | 181 | if (unlikely(zzero(n))) { 182 | SET_SIGNUM(r, 0); 183 | return; 184 | } 185 | 186 | if (pathname) { 187 | fd = open(pathname, O_RDONLY); 188 | if (check(fd < 0)) 189 | libzahl_failure(errno); 190 | statep = &fd; 191 | } 192 | 193 | switch (dist) { 194 | case QUASIUNIFORM: 195 | RANDOM_UNIFORM(0); 196 | zadd(r, r, libzahl_const_1); 197 | zmul(r, r, n); 198 | zrsh(r, r, bits); 199 | break; 200 | 201 | case UNIFORM: 202 | RANDOM_UNIFORM(1); 203 | break; 204 | 205 | case MODUNIFORM: 206 | RANDOM_UNIFORM(0); 207 | if (unlikely(zcmpmag(r, n) > 0)) 208 | zsub(r, r, n); 209 | break; 210 | 211 | default: 212 | #if !defined(ZAHL_UNSAFE) 213 | libzahl_failure(EINVAL); 214 | #endif 215 | break; 216 | } 217 | 218 | if (fd >= 0) 219 | close(fd); 220 | } 221 | -------------------------------------------------------------------------------- /src/zrsh.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | zrsh(z_t a, z_t b, size_t bits) 7 | { 8 | size_t i, chars, cbits; 9 | 10 | if (unlikely(!bits)) { 11 | SET(a, b); 12 | return; 13 | } 14 | 15 | chars = FLOOR_BITS_TO_CHARS(bits); 16 | 17 | if (unlikely(zzero(b) || chars >= b->used || zbits(b) <= bits)) { 18 | SET_SIGNUM(a, 0); 19 | return; 20 | } 21 | 22 | bits = BITS_IN_LAST_CHAR(bits); 23 | cbits = BITS_PER_CHAR - bits; 24 | 25 | if (likely(chars) && likely(a == b)) { 26 | a->used -= chars; 27 | zmemmove(a->chars, a->chars + chars, a->used); 28 | } else if (unlikely(a != b)) { 29 | a->used = b->used - chars; 30 | ENSURE_SIZE(a, a->used); 31 | zmemcpy(a->chars, b->chars + chars, a->used); 32 | } 33 | 34 | if (unlikely(bits)) { /* This if statement is very important in C. */ 35 | a->chars[0] >>= bits; 36 | for (i = 1; i < a->used; i++) { 37 | a->chars[i - 1] |= a->chars[i] << cbits; 38 | a->chars[i] >>= bits; 39 | } 40 | TRIM_NONZERO(a); 41 | } 42 | 43 | SET_SIGNUM(a, zsignum(b)); 44 | } 45 | -------------------------------------------------------------------------------- /src/zsets.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #include 5 | 6 | #ifdef __GNUC__ 7 | # pragma GCC diagnostic ignored "-Wswitch-default" 8 | #endif 9 | 10 | 11 | int 12 | zsets(z_t a, const char *str) 13 | { 14 | unsigned long long int temp = 0; 15 | int neg = (*str == '-'); 16 | const char *str_end; 17 | 18 | str += neg || (*str == '+'); 19 | 20 | if (check(!*str)) { 21 | errno = EINVAL; 22 | return -1; 23 | } 24 | for (str_end = str; *str_end; str_end++) { 25 | if (check(!isdigit(*str_end))) { 26 | errno = EINVAL; 27 | return -1; 28 | } 29 | } 30 | 31 | SET_SIGNUM(a, 0); 32 | 33 | zset(libzahl_tmp_str_num, libzahl_const_1e19); 34 | switch ((str_end - str) % 19) { 35 | while (*str) { 36 | zmul(a, a, libzahl_const_1e19); 37 | temp = 0; 38 | #define X(n)\ 39 | case n:\ 40 | temp *= 10, temp += *str++ & 15; 41 | X(0) X(18) X(17) X(16) X(15) X(14) X(13) X(12) X(11) 42 | X(10) X(9) X(8) X(7) X(6) X(5) X(4) X(3) X(2) X(1) 43 | #undef X 44 | if (!temp) 45 | continue; 46 | libzahl_tmp_str_num->chars[0] = (zahl_char_t)temp; 47 | zadd(a, a, libzahl_tmp_str_num); 48 | } 49 | } 50 | 51 | if (unlikely(neg)) 52 | SET_SIGNUM(a, -zsignum(a)); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/zsetup.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #define X(x, s) z_t x; 5 | LIST_TEMPS 6 | #undef X 7 | #define X(i, x, f, v) z_t x; 8 | LIST_CONSTS 9 | #undef X 10 | 11 | z_t libzahl_tmp_divmod_ds[BITS_PER_CHAR]; 12 | jmp_buf libzahl_jmp_buf; 13 | int libzahl_set_up = 0; 14 | int libzahl_error; 15 | zahl_char_t **libzahl_pool[sizeof(size_t) * 8]; 16 | size_t libzahl_pool_n[sizeof(size_t) * 8]; 17 | size_t libzahl_pool_alloc[sizeof(size_t) * 8]; 18 | struct zahl **libzahl_temp_stack; 19 | struct zahl **libzahl_temp_stack_head; 20 | struct zahl **libzahl_temp_stack_end; 21 | void *libzahl_temp_allocation = 0; 22 | 23 | #define X(i, x, f, v) 1 + 24 | static zahl_char_t constant_chars[LIST_CONSTS ZAHL_FLUFF]; 25 | #undef X 26 | 27 | 28 | void 29 | zsetup(jmp_buf env) 30 | { 31 | size_t i; 32 | *libzahl_jmp_buf = *env; 33 | 34 | if (likely(!libzahl_set_up)) { 35 | libzahl_set_up = 1; 36 | 37 | memset(libzahl_pool, 0, sizeof(libzahl_pool)); 38 | memset(libzahl_pool_n, 0, sizeof(libzahl_pool_n)); 39 | memset(libzahl_pool_alloc, 0, sizeof(libzahl_pool_alloc)); 40 | 41 | #define X(x, s)\ 42 | zinit(x); if (s) zsetu(x, 1); 43 | LIST_TEMPS; 44 | #undef X 45 | #define X(i, x, f, v)\ 46 | (x)->alloced = 1, (x)->chars = constant_chars + (i), f(x, v); 47 | LIST_CONSTS; 48 | #undef X 49 | for (i = BITS_PER_CHAR; i--;) 50 | zinit(libzahl_tmp_divmod_ds[i]); 51 | 52 | libzahl_temp_stack = malloc(256 * sizeof(*libzahl_temp_stack)); 53 | if (check(!libzahl_temp_stack)) 54 | libzahl_memfailure(); 55 | libzahl_temp_stack_head = libzahl_temp_stack; 56 | libzahl_temp_stack_end = libzahl_temp_stack + 256; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/zsqr.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | static inline void 6 | zsqr_ll_single_char(z_t a, z_t b) 7 | { 8 | ENSURE_SIZE(a, 1); 9 | a->used = 1; 10 | a->chars[0] = b->chars[0] * b->chars[0]; 11 | SET_SIGNUM(a, 1); 12 | } 13 | 14 | void 15 | zsqr_ll(z_t a, z_t b) 16 | { 17 | /* 18 | * Karatsuba algorithm, optimised for equal factors. 19 | */ 20 | 21 | #define z2 a 22 | z_t z0, z1, high, low; 23 | zahl_char_t auxchars[3 * ZAHL_FLUFF]; 24 | size_t bits; 25 | 26 | bits = zbits(b); 27 | 28 | if (bits <= BITS_PER_CHAR / 2) { 29 | zsqr_ll_single_char(a, b); 30 | return; 31 | } 32 | 33 | bits >>= 1; 34 | 35 | /* Try to split only at a character level rather than a bit level. 36 | * Such splits are faster, even if bit-level is required, and do 37 | * not require auxiliary memory except for the bit-level split 38 | * which require constant auxiliary memory. */ 39 | if (bits < BITS_PER_CHAR) { 40 | low->chars = auxchars; 41 | high->chars = auxchars + ZAHL_FLUFF; 42 | zsplit_unsigned_fast_small_auto(high, low, b, bits); 43 | } else { 44 | bits = TRUNCATE_TO_CHAR(bits); 45 | zsplit_unsigned_fast_large_taint(high, low, b, bits); 46 | } 47 | 48 | 49 | if (unlikely(zzero(low))) { 50 | zsqr_ll(z2, high); 51 | zlsh(a, z2, bits << 1); 52 | } else { 53 | zinit_temp(z0); 54 | zinit_temp(z1); 55 | 56 | zsqr_ll(z0, low); 57 | 58 | zmul_ll(z1, low, high); 59 | zlsh(z1, z1, bits + 1); 60 | 61 | zsqr_ll(z2, high); 62 | zlsh(a, z2, bits << 1); 63 | 64 | zadd_unsigned_assign(a, z1); 65 | zadd_unsigned_assign(a, z0); 66 | 67 | zfree_temp(z1); 68 | zfree_temp(z0); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/zstr.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #include 5 | 6 | #define num libzahl_tmp_str_num 7 | #define rem libzahl_tmp_str_rem 8 | 9 | /* All 19 you see here is derived from that 10¹⁹ is the largest 10 | * power of than < 2⁶⁴, and 64 is the number of bits in 11 | * zahl_char_t. If zahl_char_t is chanced, the value 19, and 12 | * the cast to unsigned long long must be changed accordingly. */ 13 | 14 | 15 | #define S1(P) P"0" P"1" P"2" P"3" P"4" P"5" P"6" P"7" P"8" P"9" 16 | #define S2(P) S1(P"0")S1(P"1")S1(P"2")S1(P"3")S1(P"4")S1(P"5")S1(P"6")S1(P"7")S1(P"8")S1(P"9") 17 | 18 | 19 | static inline O2 void 20 | sprintint_fix(char *buf, zahl_char_t v) 21 | { 22 | const char *partials = S2(""); 23 | uint16_t *buffer = (uint16_t *)(buf + 1); 24 | 25 | buffer[8] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100; 26 | buffer[7] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100; 27 | buffer[6] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100; 28 | buffer[5] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100; 29 | buffer[4] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100; 30 | buffer[3] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100; 31 | buffer[2] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100; 32 | buffer[1] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100; 33 | buffer[0] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100; 34 | *buf = (char)('0' + v); 35 | buf[19] = 0; 36 | } 37 | 38 | static inline void 39 | cmemmove(char *d, const char *s, long n) 40 | { 41 | while (n--) 42 | *d++ = *s++; 43 | } 44 | 45 | static inline size_t 46 | sprintint_min(char *buf, zahl_char_t v) 47 | { 48 | long i = 0, j; 49 | sprintint_fix(buf, v); 50 | for (; buf[i] == '0'; i++); 51 | cmemmove(buf, buf + i, j = 19 - i); 52 | buf[j] = 0; 53 | return (size_t)j; 54 | } 55 | 56 | 57 | char * 58 | zstr(z_t a, char *b, size_t n) 59 | { 60 | char buf[19 + 1]; 61 | size_t len, neg, last, tot = 0; 62 | char overridden = 0; 63 | 64 | if (unlikely(zzero(a))) { 65 | if (unlikely(!b) && unlikely(!(b = malloc(2)))) 66 | libzahl_memfailure(); 67 | b[0] = '0'; 68 | b[1] = 0; 69 | return b; 70 | } 71 | 72 | if (!n) { 73 | /* Calculate a value that is at least the number of 74 | * digits required to store the string. The overshoot 75 | * is not too signicant. */ 76 | n = (20 * BITS_PER_CHAR / 64 + (BITS_PER_CHAR == 8)) * a->used; 77 | /* Note, depends on a ≠ as ensure above. */ 78 | } 79 | 80 | if (unlikely(!b) && unlikely(!(b = libzahl_temp_allocation = malloc(n + 1)))) 81 | libzahl_memfailure(); 82 | 83 | neg = znegative(a); 84 | zabs(num, a); 85 | b[0] = '-'; 86 | b += neg; 87 | n -= neg; 88 | n = (last = n) > 19 ? (n - 19) : 0; 89 | 90 | for (;;) { 91 | zdivmod(num, rem, num, libzahl_const_1e19); 92 | if (likely(!zzero(num))) { 93 | sprintint_fix(b + n, zzero(rem) ? 0 : rem->chars[0]); 94 | b[n + 19] = overridden; 95 | overridden = b[n]; 96 | n = (last = n) > 19 ? (n - 19) : 0; 97 | tot += 19; 98 | } else { 99 | len = sprintint_min(buf, rem->chars[0]); 100 | if (tot) { 101 | memcpy(b, buf, len); 102 | memmove(b + len, b + last, tot + 1); 103 | } else { 104 | memcpy(b, buf, len + 1); 105 | } 106 | break; 107 | } 108 | } 109 | 110 | libzahl_temp_allocation = 0; 111 | return b - neg; 112 | } 113 | -------------------------------------------------------------------------------- /src/zstr_length.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | #define num libzahl_tmp_str_num 5 | #define mag libzahl_tmp_str_mag 6 | #define div libzahl_tmp_str_div 7 | 8 | 9 | size_t 10 | zstr_length(z_t a, unsigned long long int radix) 11 | { 12 | size_t size_total = 1, size_temp; 13 | if (check(radix < 2)) 14 | libzahl_failure(-ZERROR_INVALID_RADIX); 15 | zset(num, a); 16 | while (!zzero(num)) { 17 | zsetu(mag, radix); 18 | zset(div, mag); 19 | size_temp = 1; 20 | while (zcmpmag(mag, num) <= 0) { 21 | zset(div, mag); 22 | zsqr(mag, mag); 23 | size_temp <<= 1; 24 | } 25 | size_temp >>= 1; 26 | size_total += size_temp; 27 | zdiv(num, num, div); 28 | } 29 | return size_total + (zsignum(a) < 0); 30 | } 31 | -------------------------------------------------------------------------------- /src/zsub.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | static inline void 6 | zsub_impl(z_t a, z_t b, size_t n) 7 | { 8 | zahl_char_t carry = 0, tcarry; 9 | size_t i; 10 | 11 | for (i = 0; i < n; i++) { 12 | tcarry = carry ? (a->chars[i] <= b->chars[i]) : (a->chars[i] < b->chars[i]); 13 | a->chars[i] -= b->chars[i]; 14 | a->chars[i] -= carry; 15 | carry = tcarry; 16 | } 17 | 18 | if (carry) { 19 | while (!a->chars[i]) 20 | a->chars[i++] = ZAHL_CHAR_MAX; 21 | if (a->chars[i] == 1) 22 | a->used--; 23 | else 24 | a->chars[i] -= 1; 25 | } 26 | } 27 | 28 | static inline void 29 | libzahl_zsub_unsigned(z_t a, z_t b, z_t c) 30 | { 31 | int magcmp; 32 | size_t n; 33 | 34 | if (unlikely(zzero(b))) { 35 | zabs(a, c); 36 | zneg(a, a); 37 | return; 38 | } else if (unlikely(zzero(c))) { 39 | zabs(a, b); 40 | return; 41 | } 42 | 43 | magcmp = zcmpmag(b, c); 44 | if (unlikely(magcmp <= 0)) { 45 | if (unlikely(magcmp == 0)) { 46 | SET_SIGNUM(a, 0); 47 | return; 48 | } 49 | n = b->used; 50 | if (a == b) { 51 | zset(libzahl_tmp_sub, b); 52 | SET(a, c); 53 | zsub_impl(a, libzahl_tmp_sub, n); 54 | } else { 55 | SET(a, c); 56 | zsub_impl(a, b, n); 57 | } 58 | } else { 59 | n = c->used; 60 | if (unlikely(a == c)) { 61 | zset(libzahl_tmp_sub, c); 62 | SET(a, b); 63 | zsub_impl(a, libzahl_tmp_sub, n); 64 | } else { 65 | SET(a, b); 66 | zsub_impl(a, c, n); 67 | } 68 | } 69 | 70 | SET_SIGNUM(a, magcmp); 71 | } 72 | 73 | void 74 | zsub_unsigned(z_t a, z_t b, z_t c) 75 | { 76 | libzahl_zsub_unsigned(a, b, c); 77 | } 78 | 79 | void 80 | zsub_nonnegative_assign(z_t a, z_t b) 81 | { 82 | if (unlikely(zzero(b))) 83 | zabs(a, a); 84 | else if (unlikely(!zcmpmag(a, b))) 85 | SET_SIGNUM(a, 0); 86 | else 87 | zsub_impl(a, b, b->used); 88 | } 89 | 90 | void 91 | zsub_positive_assign(z_t a, z_t b) 92 | { 93 | zsub_impl(a, b, b->used); 94 | } 95 | 96 | void 97 | zsub(z_t a, z_t b, z_t c) 98 | { 99 | if (unlikely(zzero(b))) { 100 | zneg(a, c); 101 | } else if (unlikely(zzero(c))) { 102 | SET(a, b); 103 | } else if (unlikely(znegative(b))) { 104 | if (znegative(c)) { 105 | libzahl_zsub_unsigned(a, c, b); 106 | } else { 107 | zadd_unsigned(a, b, c); 108 | SET_SIGNUM(a, -zsignum(a)); 109 | } 110 | } else if (znegative(c)) { 111 | zadd_unsigned(a, b, c); 112 | } else { 113 | libzahl_zsub_unsigned(a, b, c); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/ztrunc.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | ztrunc(z_t a, z_t b, size_t bits) 7 | { 8 | size_t chars; 9 | 10 | if (unlikely(zzero(b))) { 11 | SET_SIGNUM(a, 0); 12 | return; 13 | } 14 | 15 | chars = CEILING_BITS_TO_CHARS(bits); 16 | a->used = MIN(chars, b->used); 17 | if (unlikely(a->used < chars)) 18 | bits = 0; 19 | if (likely(a != b)) { 20 | a->sign = b->sign; 21 | ENSURE_SIZE(a, a->used); 22 | zmemcpy(a->chars, b->chars, a->used); 23 | } 24 | bits = BITS_IN_LAST_CHAR(bits); 25 | if (likely(bits)) 26 | a->chars[a->used - 1] &= ((zahl_char_t)1 << bits) - 1; 27 | 28 | TRIM_AND_ZERO(a); 29 | } 30 | -------------------------------------------------------------------------------- /src/zunsetup.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | zunsetup(void) 7 | { 8 | size_t i; 9 | if (libzahl_set_up) { 10 | libzahl_set_up = 0; 11 | #define X(x, s)\ 12 | free(x->chars); 13 | LIST_TEMPS; 14 | #undef X 15 | for (i = BITS_PER_CHAR; i--;) 16 | free(libzahl_tmp_divmod_ds[i]->chars); 17 | 18 | for (i = sizeof(libzahl_pool) / sizeof(*libzahl_pool); i--;) { 19 | while (libzahl_pool_n[i]--) 20 | free(libzahl_pool[i][libzahl_pool_n[i]]); 21 | free(libzahl_pool[i]); 22 | } 23 | 24 | free(libzahl_temp_stack); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/zxor.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "internals.h" 3 | 4 | 5 | void 6 | zxor(z_t a, z_t b, z_t c) 7 | { 8 | size_t n, m, bn, cn; 9 | const zahl_char_t *restrict bc; 10 | const zahl_char_t *restrict cc; 11 | 12 | if (unlikely(zzero(b))) { 13 | SET(a, c); 14 | return; 15 | } else if (unlikely(zzero(c))) { 16 | SET(a, b); 17 | return; 18 | } 19 | 20 | bn = b->used; 21 | bc = b->chars; 22 | cn = c->used; 23 | cc = c->chars; 24 | 25 | MIN_MAX_1(n, m, bn, cn); 26 | ENSURE_SIZE(a, m); 27 | 28 | if (a == b) { 29 | ZMEM_2OP_PRECISE(a->chars, a->chars, cc, n, ^); 30 | if (a->used < cn) 31 | zmemcpy_range(a->chars, cc, n, m); 32 | } else if (unlikely(a == c)) { 33 | ZMEM_2OP_PRECISE(a->chars, a->chars, bc, n, ^); 34 | if (a->used < bn) 35 | zmemcpy_range(a->chars, bc, n, m); 36 | } else if (m == bn) { 37 | ZMEM_2OP(a->chars, c->chars, b->chars, n, ^); 38 | zmemcpy_range(a->chars, b->chars, n, m); 39 | } else { 40 | ZMEM_2OP(a->chars, b->chars, c->chars, n, ^); 41 | zmemcpy_range(a->chars, c->chars, n, m); 42 | } 43 | 44 | a->used = m; 45 | TRIM_AND_SIGN(a, 1 - 2 * ((zsignum(b) ^ zsignum(c)) < 0)); 46 | } 47 | -------------------------------------------------------------------------------- /zahl.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | /* Warning: libzahl is not thread-safe. */ 4 | /* Caution: Do not use libzahl for cryptographic applications, use a specialised library. */ 5 | 6 | #ifndef ZAHL_H 7 | #define ZAHL_H 1 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | 18 | /* TODO these should be documented*/ 19 | #define ZAHL_VERSION_MAJOR 1L 20 | #define ZAHL_VERSION_MINOR 1L 21 | #define ZAHL_VERSION_PATCHLEVEL 0L 22 | #define ZAHL_VERSION (ZAHL_VERSION_MAJOR * 1000000L + \ 23 | ZAHL_VERSION_MINOR * 1000L + \ 24 | ZAHL_VERSION_PATCHLEVEL) 25 | #define ZAHL_VERSION_STRING "1.1" 26 | #define ZAHL_INTERNALS_VERSION 1 27 | #define ZAHL_ZRANDDEV_COUNT 7 28 | #define ZAHL_ZRANDDIST_COUNT 3 29 | #define ZAHL_ZERROR_COUNT 6 30 | 31 | 32 | 33 | #include "zahl/internals.h" 34 | 35 | 36 | 37 | typedef struct zahl z_t[1]; 38 | 39 | 40 | 41 | enum zprimality { 42 | NONPRIME = 0, /* The number is definitely composite. */ 43 | PROBABLY_PRIME, /* The number is probably prime. */ 44 | PRIME /* The number is definitely prime. */ 45 | }; 46 | 47 | enum zranddev { 48 | FAST_RANDOM = 0, /* Random numbers are generated directly from /dev/urandom. */ 49 | SECURE_RANDOM, /* Random numbers are generated directly from /dev/random. */ 50 | DEFAULT_RANDOM, /* Select the default random number generator. */ 51 | FASTEST_RANDOM, /* Select the fastest random number generator. */ 52 | LIBC_RAND_RANDOM, /* Use rand(3). */ 53 | LIBC_RANDOM_RANDOM, /* Use random(3). */ 54 | LIBC_RAND48_RANDOM /* Use lrand48(3). */ 55 | }; 56 | 57 | enum zranddist { 58 | QUASIUNIFORM = 0, /* Almost uniformly random, per the usual recommendation. */ 59 | UNIFORM, /* Actually uniformly random. */ 60 | MODUNIFORM /* Almost uniformly random, using the naïve approach of modulation. */ 61 | }; 62 | 63 | enum zerror { 64 | ZERROR_ERRNO_SET = 0, /* Please refer to errno. */ 65 | ZERROR_0_POW_0, /* Indeterminate form: 0:th power of 0. (Translatable to EDOM.) */ 66 | ZERROR_0_DIV_0, /* Indeterminate form: 0 divided by 0. (Translatable to EDOM.) */ 67 | ZERROR_DIV_0, /* Undefined result: Division by 0. (Translatable to EDOM.) */ 68 | ZERROR_NEGATIVE, /* Argument must be non-negative. (Translatable to EDOM or EINVAL.) */ 69 | ZERROR_INVALID_RADIX /* Radix must be at least 2. (Translatable to EINVAL.) */ 70 | }; 71 | 72 | 73 | 74 | /* The parameters in the functions below are numbers a, b, c, ... */ 75 | 76 | 77 | /* Library initialisation and destruction. */ 78 | 79 | void zsetup(jmp_buf); /* Prepare libzahl for use. */ 80 | void zunsetup(void); /* Free resources used by libzahl */ 81 | 82 | 83 | /* Memory functions. */ 84 | 85 | ZAHL_INLINE void zinit(z_t); /* Prepare a for use. */ 86 | ZAHL_INLINE void zswap(z_t, z_t); /* (a, b) := (b, a) */ 87 | void zfree(z_t); /* Free resources in a. */ 88 | ZAHL_INLINE size_t zsave(z_t, void *); /* Store a into b (if !!b), and return number of written bytes. */ 89 | size_t zload(z_t, const void *); /* Restore a from b, and return number of read bytes. */ 90 | 91 | 92 | /* Assignment functions. */ 93 | 94 | ZAHL_INLINE void zset(z_t, z_t); /* a := b */ 95 | ZAHL_INLINE void zsetu(z_t, uint64_t); /* a := b */ 96 | ZAHL_INLINE void zseti(z_t, int64_t); /* a := b */ 97 | 98 | 99 | /* Comparison functions. */ 100 | 101 | ZAHL_INLINE int zcmp(z_t, z_t); /* signum (a - b) */ 102 | ZAHL_INLINE int zcmpu(z_t, uint64_t); /* signum (a - b) */ 103 | ZAHL_INLINE int zcmpi(z_t, int64_t); /* signum (a - b) */ 104 | ZAHL_INLINE int zcmpmag(z_t, z_t); /* signum (|a| - |b|) */ 105 | 106 | 107 | /* Arithmetic functions. */ 108 | 109 | ZAHL_INLINE void zabs(z_t, z_t); /* a := |b| */ 110 | ZAHL_INLINE void zneg(z_t, z_t); /* a := -b */ 111 | void zadd(z_t, z_t, z_t); /* a := b + c */ 112 | void zsub(z_t, z_t, z_t); /* a := b - c */ 113 | ZAHL_INLINE void zmul(z_t, z_t, z_t); /* a := b * c */ 114 | void zmodmul(z_t, z_t, z_t, z_t); /* a := (b * c) % d */ 115 | ZAHL_INLINE void zdiv(z_t, z_t, z_t); /* a := b / c */ 116 | void zdivmod(z_t, z_t, z_t, z_t); /* a := c / d, b = c % d */ 117 | ZAHL_INLINE void zmod(z_t, z_t, z_t); /* a := b % c */ 118 | ZAHL_INLINE void zsqr(z_t, z_t); /* a := b² */ 119 | void zmodsqr(z_t, z_t, z_t); /* a := b² % c */ 120 | void zpow(z_t, z_t, z_t); /* a := b ↑ c */ 121 | void zmodpow(z_t, z_t, z_t, z_t); /* a := (b ↑ c) % d */ 122 | void zpowu(z_t, z_t, unsigned long long int); 123 | void zmodpowu(z_t, z_t, unsigned long long int, z_t); 124 | 125 | /* These are used internally and may be removed in a future version. */ 126 | void zadd_unsigned(z_t, z_t, z_t); /* a := |b| + |c| */ 127 | void zsub_unsigned(z_t, z_t, z_t); /* a := |b| - |c| */ 128 | void zadd_unsigned_assign(z_t, z_t); /* a := |a| + |b| */ 129 | void zsub_nonnegative_assign(z_t, z_t); /* a := a - b, assuming a ≥ b ≥ 0 */ 130 | void zsub_positive_assign(z_t, z_t); /* a := a - b, assuming a > b > 0 */ 131 | 132 | 133 | /* Bitwise operations. */ 134 | 135 | void zand(z_t, z_t, z_t); /* a := b & c */ 136 | void zor(z_t, z_t, z_t); /* a := b | c */ 137 | void zxor(z_t, z_t, z_t); /* a := b ^ c */ 138 | void znot(z_t, z_t); /* a := ~b */ 139 | void zlsh(z_t, z_t, size_t); /* a := b << c */ 140 | void zrsh(z_t, z_t, size_t); /* a := b >> c */ 141 | void ztrunc(z_t, z_t, size_t); /* a := b & ((1 << c) - 1) */ 142 | ZAHL_INLINE void zsplit(z_t, z_t, z_t, size_t); 143 | /* a := c >> d, b := c - (a << d) */ 144 | ZAHL_INLINE int zbtest(z_t, size_t); /* (a >> b) & 1 */ 145 | ZAHL_INLINE size_t zlsb(z_t); /* Index of first set bit, SIZE_MAX if none are set. */ 146 | ZAHL_INLINE size_t zbits(z_t); /* ⌊log₂ |a|⌋ + 1, 1 if a = 0 */ 147 | 148 | /* If d > 0: a := b | (1 << c), if d = 0: a := b & ~(1 << c), if d < 0: a := b ^ (1 << c) */ 149 | ZAHL_INLINE void zbset(z_t, z_t, size_t, int); 150 | 151 | 152 | /* Number theory. */ 153 | 154 | ZAHL_INLINE int zeven(z_t); /* Is a even? */ 155 | ZAHL_INLINE int zodd(z_t); /* Is a odd? */ 156 | ZAHL_INLINE int zeven_nonzero(z_t); /* Is a even? Assumes a ≠ 0. */ 157 | ZAHL_INLINE int zodd_nonzero(z_t); /* Is a odd? Assumes a ≠ 0. */ 158 | ZAHL_INLINE int zzero(z_t); /* Is a zero? */ 159 | ZAHL_INLINE int zsignum(z_t); /* a/|a|, 0 if a is zero. */ 160 | void zgcd(z_t, z_t, z_t); /* a := gcd(b, c) */ 161 | 162 | /* NONPRIME if b ∉ ℙ, PROBABLY_PRIME, if b ∈ ℙ with (1 − 4↑−c) certainty, 2 if PRIME ∈ ℙ. 163 | * If NONPRIME is returned the witness of b's compositeness is stored in a. */ 164 | enum zprimality zptest(z_t, z_t, int); 165 | 166 | 167 | /* Random number generation. */ 168 | 169 | /* Pick a randomly from [0, d] ∩ ℤ. */ 170 | void zrand(z_t, enum zranddev, enum zranddist, z_t); 171 | 172 | 173 | /* String conversion. */ 174 | 175 | char *zstr(z_t, char *, size_t); /* Write a in decimal onto b. c is the output size or 0. */ 176 | int zsets(z_t, const char *); /* a := b */ 177 | 178 | /* Length of a in radix b. */ 179 | size_t zstr_length(z_t, unsigned long long int); 180 | 181 | 182 | /* Error handling functions. */ 183 | 184 | enum zerror zerror(const char **); /* Return the current error code, and unless !a, a description in *a. */ 185 | void zperror(const char *); /* Identical to perror(3p) except it supports libzahl errors. */ 186 | 187 | 188 | 189 | /* Low-level functions. [Do not count on these to be retained between different versions of libzahl.] */ 190 | 191 | void zbset_ll_set(z_t, size_t); /* zbset(a, a, b, 1) */ 192 | void zbset_ll_clear(z_t, size_t); /* zbset(a, a, b, 0) */ 193 | void zbset_ll_flip(z_t, size_t); /* zbset(a, a, b, -1) */ 194 | void zmul_ll(z_t, z_t, z_t); /* zmul for non-negative operands */ 195 | void zsqr_ll(z_t, z_t); /* zsqr for non-negative operand */ 196 | 197 | 198 | 199 | #include "zahl/inlines.h" 200 | 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /zahl/inlines.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | ZAHL_INLINE void zinit(z_t a) { a->alloced = 0; a->chars = 0; } 4 | ZAHL_INLINE int zeven(z_t a) { return !a->sign || (~a->chars[0] & 1); } 5 | ZAHL_INLINE int zodd(z_t a) { return a->sign && (a->chars[0] & 1); } 6 | ZAHL_INLINE int zeven_nonzero(z_t a) { return ~a->chars[0] & 1; } 7 | ZAHL_INLINE int zodd_nonzero(z_t a) { return a->chars[0] & 1; } 8 | ZAHL_INLINE int zzero(z_t a) { return !a->sign; } 9 | ZAHL_INLINE int zsignum(z_t a) { return a->sign; } 10 | ZAHL_INLINE void zneg(z_t a, z_t b) { ZAHL_SET(a, b); a->sign = -a->sign; } 11 | 12 | #if 1 && (-1 & 1) /* In the future, tuning will select the fastest implementation. */ 13 | ZAHL_INLINE void zabs(z_t a, z_t b) { ZAHL_SET(a, b); a->sign &= 1; } 14 | #elif 1 15 | ZAHL_INLINE void zabs(z_t a, z_t b) { ZAHL_SET(a, b); if (ZAHL_LIKELY(a->sign < 0)) a->sign = 1; } 16 | #else 17 | ZAHL_INLINE void zabs(z_t a, z_t b) { ZAHL_SET(a, b); a->sign = !!a->sign; } 18 | #endif 19 | 20 | 21 | #if ULONG_MAX != SIZE_MAX /* This variant should be equivalent to the second one if .sign was long. */ 22 | ZAHL_INLINE void 23 | zswap(z_t a, z_t b) 24 | { 25 | z_t t; 26 | ZAHL_SWAP(a, b, t, sign); 27 | ZAHL_SWAP(b, a, t, used); 28 | ZAHL_SWAP(a, b, t, alloced); 29 | ZAHL_SWAP(b, a, t, chars); 30 | } 31 | #else 32 | ZAHL_INLINE void 33 | zswap(z_t a_, z_t b_) 34 | { 35 | register long t; 36 | long *a = (long *)a_; 37 | long *b = (long *)b_; 38 | t = a[0], a[0] = b[0], b[0] = t; 39 | t = b[1], b[1] = a[1], a[1] = t; 40 | t = a[2], a[2] = b[2], b[2] = t; 41 | t = b[3], b[3] = a[3], a[3] = t; 42 | } 43 | #endif 44 | 45 | 46 | ZAHL_INLINE void 47 | zset(z_t a, z_t b) 48 | { 49 | if (ZAHL_UNLIKELY(b->sign == 0)) { 50 | a->sign = 0; 51 | } else { 52 | a->sign = b->sign; 53 | a->used = b->used; 54 | ZAHL_ENSURE_SIZE(a, b->used); 55 | libzahl_memcpy(a->chars, b->chars, b->used); 56 | } 57 | } 58 | 59 | 60 | ZAHL_INLINE void 61 | zseti(z_t a, int64_t b) 62 | { 63 | if (ZAHL_UNLIKELY(b >= 0)) { 64 | zsetu(a, (uint64_t)b); 65 | return; 66 | } 67 | ZAHL_ENSURE_SIZE(a, 1); 68 | ZAHL_SET_SIGNUM(a, -1); 69 | a->chars[0] = (zahl_char_t)-b; 70 | a->used = 1; 71 | } 72 | 73 | 74 | ZAHL_INLINE void 75 | zsetu(z_t a, uint64_t b) 76 | { 77 | if (ZAHL_UNLIKELY(!b)) { 78 | ZAHL_SET_SIGNUM(a, 0); 79 | return; 80 | } 81 | ZAHL_ENSURE_SIZE(a, 1); 82 | ZAHL_SET_SIGNUM(a, 1); 83 | a->chars[0] = (zahl_char_t)b; 84 | a->used = 1; 85 | } 86 | 87 | 88 | ZAHL_INLINE size_t 89 | zlsb(z_t a) 90 | { 91 | size_t i = 0; 92 | if (ZAHL_UNLIKELY(zzero(a))) 93 | return SIZE_MAX; 94 | for (; !a->chars[i]; i++); 95 | i *= 8 * sizeof(zahl_char_t); 96 | ZAHL_ADD_CTZ(i, a->chars[i]); 97 | return i; 98 | } 99 | 100 | 101 | ZAHL_INLINE size_t 102 | zbits(z_t a) 103 | { 104 | size_t rc; 105 | if (ZAHL_UNLIKELY(zzero(a))) 106 | return 1; 107 | while (!a->chars[a->used - 1]) a->used--; /* TODO should not be necessary */ 108 | rc = a->used * 8 * sizeof(zahl_char_t); 109 | ZAHL_SUB_CLZ(rc, a->chars[a->used - 1]); 110 | return rc; 111 | } 112 | 113 | 114 | ZAHL_INLINE int 115 | zcmpmag(z_t a, z_t b) 116 | { 117 | size_t i, j; 118 | if (ZAHL_UNLIKELY(zzero(a))) return -!zzero(b); 119 | if (ZAHL_UNLIKELY(zzero(b))) return 1; 120 | i = a->used - 1; 121 | j = b->used - 1; 122 | #if 0 /* TODO this should be sufficient. */ 123 | if (i != j) 124 | return (i > j) * 2 - 1; 125 | #else 126 | for (; i > j; i--) { 127 | if (a->chars[i]) 128 | return +1; 129 | a->used--; 130 | } 131 | for (; j > i; j--) { 132 | if (b->chars[j]) 133 | return -1; 134 | b->used--; 135 | } 136 | #endif 137 | for (; i && a->chars[i] == b->chars[i]; i--); 138 | return a->chars[i] < b->chars[i] ? -1 : a->chars[i] > b->chars[i]; 139 | } 140 | 141 | 142 | ZAHL_INLINE int 143 | zcmp(z_t a, z_t b) 144 | { 145 | if (zsignum(a) != zsignum(b)) 146 | return zsignum(a) < zsignum(b) ? -1 : zsignum(a) > zsignum(b); 147 | return zsignum(a) * zcmpmag(a, b); 148 | } 149 | 150 | 151 | ZAHL_INLINE int 152 | zcmpu(z_t a, uint64_t b) 153 | { 154 | if (ZAHL_UNLIKELY(!b)) 155 | return zsignum(a); 156 | if (ZAHL_UNLIKELY(zsignum(a) <= 0)) 157 | return -1; 158 | while (!a->chars[a->used - 1]) a->used--; /* TODO should not be necessary */ 159 | if (a->used > 1) 160 | return +1; 161 | return a->chars[0] < b ? -1 : a->chars[0] > b; 162 | } 163 | 164 | 165 | ZAHL_INLINE int 166 | zcmpi(z_t a, int64_t b) 167 | { 168 | if (ZAHL_UNLIKELY(!b)) 169 | return zsignum(a); 170 | if (ZAHL_UNLIKELY(zzero(a))) 171 | return ZAHL_LIKELY(b < 0) ? 1 : -1; 172 | if (ZAHL_LIKELY(b < 0)) { 173 | if (zsignum(a) > 0) 174 | return +1; 175 | while (!a->chars[a->used - 1]) a->used--; /* TODO should not be necessary */ 176 | if (a->used > 1) 177 | return -1; 178 | return a->chars[0] > (zahl_char_t)-b ? -1 : a->chars[0] < (zahl_char_t)-b; 179 | } else { 180 | if (zsignum(a) < 0) 181 | return -1; 182 | while (!a->chars[a->used - 1]) a->used--; /* TODO should not be necessary */ 183 | if (a->used > 1) 184 | return +1; 185 | return a->chars[0] < (zahl_char_t)b ? -1 : a->chars[0] > (zahl_char_t)b; 186 | } 187 | } 188 | 189 | 190 | ZAHL_INLINE void 191 | zbset(z_t a, z_t b, size_t bit, int action) 192 | { 193 | if (ZAHL_UNLIKELY(a != b)) 194 | zset(a, b); 195 | 196 | #ifdef ZAHL_CONST_P 197 | if (ZAHL_CONST_P(action) && ZAHL_CONST_P(bit)) { 198 | zahl_char_t mask = 1; 199 | if (zzero(a) || ZAHL_FLOOR_BITS_TO_CHARS(bit) >= a->used) { 200 | if (!action) 201 | return; 202 | goto fallback; 203 | } 204 | mask <<= ZAHL_BITS_IN_LAST_CHAR(bit); 205 | if (action > 0) { 206 | a->chars[ZAHL_FLOOR_BITS_TO_CHARS(bit)] |= mask; 207 | return; 208 | } else if (action < 0) { 209 | a->chars[ZAHL_FLOOR_BITS_TO_CHARS(bit)] ^= mask; 210 | } else { 211 | a->chars[ZAHL_FLOOR_BITS_TO_CHARS(bit)] &= ~mask; 212 | } 213 | ZAHL_TRIM_AND_ZERO(a); 214 | return; 215 | } 216 | fallback: 217 | #endif 218 | 219 | if (action > 0) 220 | zbset_ll_set(a, bit); 221 | else if (action < 0) 222 | zbset_ll_flip(a, bit); 223 | else 224 | zbset_ll_clear(a, bit); 225 | } 226 | 227 | 228 | ZAHL_O3 ZAHL_INLINE int 229 | zbtest(z_t a, size_t bit) 230 | { 231 | size_t chars; 232 | if (ZAHL_UNLIKELY(zzero(a))) 233 | return 0; 234 | 235 | chars = ZAHL_FLOOR_BITS_TO_CHARS(bit); 236 | if (ZAHL_UNLIKELY(chars >= a->used)) 237 | return 0; 238 | 239 | bit &= ZAHL_BITS_IN_LAST_CHAR(bit); 240 | return (a->chars[chars] >> bit) & 1; 241 | } 242 | 243 | 244 | ZAHL_O3 ZAHL_INLINE void 245 | zsplit(z_t high, z_t low, z_t a, size_t delim) 246 | { 247 | if (ZAHL_UNLIKELY(high == a)) { 248 | ztrunc(low, a, delim); 249 | zrsh(high, a, delim); 250 | } else { 251 | zrsh(high, a, delim); 252 | ztrunc(low, a, delim); 253 | } 254 | } 255 | 256 | 257 | ZAHL_INLINE size_t 258 | zsave(z_t a, void *buffer) 259 | { 260 | if (ZAHL_LIKELY(buffer)) { 261 | char *buf = buffer; 262 | *((long *)buf) = a->sign, buf += sizeof(long); /* Use `long` for alignment. */ 263 | *((size_t *)buf) = a->used, buf += sizeof(size_t); 264 | if (ZAHL_LIKELY(!zzero(a))) { 265 | a->chars[a->used + 2] = 0; 266 | a->chars[a->used + 1] = 0; 267 | a->chars[a->used + 0] = 0; 268 | libzahl_memcpy((zahl_char_t *)buf, a->chars, a->used); 269 | } 270 | } 271 | return sizeof(long) + sizeof(size_t) + 272 | (zzero(a) ? 0 :((a->used + 3) & (size_t)~3) * sizeof(zahl_char_t)); 273 | } 274 | 275 | 276 | ZAHL_INLINE void 277 | zmul(z_t a, z_t b, z_t c) 278 | { 279 | int b_sign, c_sign; 280 | b_sign = b->sign, b->sign *= b_sign; 281 | c_sign = c->sign, c->sign *= c_sign; 282 | zmul_ll(a, b, c); 283 | c->sign = c_sign; 284 | b->sign = b_sign; 285 | ZAHL_SET_SIGNUM(a, zsignum(b) * zsignum(c)); 286 | } 287 | 288 | 289 | ZAHL_INLINE void 290 | zsqr(z_t a, z_t b) 291 | { 292 | if (ZAHL_UNLIKELY(zzero(b))) { 293 | ZAHL_SET_SIGNUM(a, 0); 294 | } else { 295 | zsqr_ll(a, b); 296 | ZAHL_SET_SIGNUM(a, 1); 297 | } 298 | } 299 | 300 | 301 | ZAHL_INLINE void 302 | zdiv(z_t a, z_t b, z_t c) 303 | { 304 | zdivmod(a, libzahl_tmp_div, b, c); 305 | } 306 | 307 | 308 | ZAHL_INLINE void 309 | zmod(z_t a, z_t b, z_t c) 310 | { 311 | zdivmod(libzahl_tmp_mod, a, b, c); 312 | } 313 | -------------------------------------------------------------------------------- /zahl/internals.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | #ifndef ZAHL_INLINE 4 | # if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 5 | # define ZAHL_INLINE static inline 6 | # else 7 | # define ZAHL_INLINE static 8 | # endif 9 | #endif 10 | 11 | 12 | #if defined(__GNUC__) || defined(__clang__) 13 | # define ZAHL_LIKELY(expr) __builtin_expect(!!(expr), 1) 14 | # define ZAHL_UNLIKELY(expr) __builtin_expect(!!(expr), 0) 15 | # define ZAHL_CONST_P(value) __builtin_constant_p(value) 16 | #else 17 | # define ZAHL_LIKELY(expr) (expr) 18 | # define ZAHL_UNLIKELY(expr) (expr) 19 | #endif 20 | 21 | 22 | #if defined(__GNUC__) && !defined(__clang__) 23 | # define ZAHL_O0 __attribute__((__optimize__("O0"))) 24 | # define ZAHL_O1 __attribute__((__optimize__("O1"))) 25 | # define ZAHL_O2 __attribute__((__optimize__("O2"))) 26 | # define ZAHL_O3 __attribute__((__optimize__("O3"))) 27 | # define ZAHL_Ofast __attribute__((__optimize__("Ofast"))) 28 | # define ZAHL_Os __attribute__((__optimize__("Os"))) 29 | # define ZAHL_Oz __attribute__((__optimize__("Os"))) 30 | #elif defined(__clang__) 31 | # define ZAHL_O0 __attribute__((__optnone__)) 32 | # define ZAHL_O1 /* Don't know how. */ 33 | # define ZAHL_O2 /* Don't know how. */ 34 | # define ZAHL_O3 /* Don't know how. */ 35 | # define ZAHL_Ofast /* Don't know how. */ 36 | # define ZAHL_Os /* Don't know how. */ 37 | # define ZAHL_Oz /* Don't know how. */ 38 | #else 39 | # define ZAHL_O0 /* Don't know how. */ 40 | # define ZAHL_O1 /* Don't know how. */ 41 | # define ZAHL_O2 /* Don't know how. */ 42 | # define ZAHL_O3 /* Don't know how. */ 43 | # define ZAHL_Ofast /* Don't know how. */ 44 | # define ZAHL_Os /* Don't know how. */ 45 | # define ZAHL_Oz /* Don't know how. */ 46 | #endif 47 | /* Mostly ZAHL_O2, but sometimes ZAHL_O3, are useful. 48 | * But note, often it optimal to not use any of them. */ 49 | 50 | 51 | #define ZAHL_BITS_PER_CHAR 64 52 | #define ZAHL_LB_BITS_PER_CHAR 6 53 | #define ZAHL_CHAR_MAX UINT64_MAX 54 | #define ZAHL_FLUFF 4 55 | /* Note: These cannot be changed willy-nilly, some code depends 56 | * on them, be cause being flexible would just be too painful. */ 57 | 58 | 59 | #define ZAHL_FLOOR_BITS_TO_CHARS(bits) ((bits) >> ZAHL_LB_BITS_PER_CHAR) 60 | #define ZAHL_CEILING_BITS_TO_CHARS(bits) (((bits) + (ZAHL_BITS_PER_CHAR - 1)) >> ZAHL_LB_BITS_PER_CHAR) 61 | #define ZAHL_BITS_IN_LAST_CHAR(bits) ((bits) & (ZAHL_BITS_PER_CHAR - 1)) 62 | #define ZAHL_TRUNCATE_TO_CHAR(bits) ((bits) & ~(size_t)(ZAHL_BITS_PER_CHAR - 1)) 63 | 64 | 65 | #define ZAHL_SET_SIGNUM(a, signum) ((a)->sign = (signum)) 66 | #define ZAHL_SET(a, b) do { if ((a) != (b)) zset(a, b); } while (0) 67 | #define ZAHL_ENSURE_SIZE(a, n) do { if ((a)->alloced < (n)) libzahl_realloc(a, (n)); } while (0) 68 | #define ZAHL_TRIM(a) for (; (a)->used && !(a)->chars[(a)->used - 1]; (a)->used--) 69 | #define ZAHL_TRIM_NONZERO(a) for (; !(a)->chars[(a)->used - 1]; (a)->used--) 70 | #define ZAHL_TRIM_AND_ZERO(a) do { ZAHL_TRIM(a); if (!(a)->used) ZAHL_SET_SIGNUM(a, 0); } while (0) 71 | #define ZAHL_TRIM_AND_SIGN(a, s) do { ZAHL_TRIM(a); ZAHL_SET_SIGNUM(a, (a)->used ? (s) : 0); } while (0) 72 | #define ZAHL_SWAP(a, b, t, m) ((t)->m = (a)->m, (a)->m = (b)->m, (b)->m = (t)->m) 73 | 74 | 75 | #if defined(__GNUC__) || defined(__clang__) 76 | # if ZAHL_CHAR_MAX == LONG_MAX 77 | # define ZAHL_ADD_CTZ(r, x) ((r) += (size_t)__builtin_ctzl(x)) 78 | # define ZAHL_SUB_CLZ(r, x) ((r) -= (size_t)__builtin_clzl(x)) 79 | # else 80 | # define ZAHL_ADD_CTZ(r, x) ((r) += (size_t)__builtin_ctzll(x)) 81 | # define ZAHL_SUB_CLZ(r, x) ((r) -= (size_t)__builtin_clzll(x)) 82 | # endif 83 | #else 84 | # define ZAHL_ADD_CTZ(r, x) \ 85 | do { \ 86 | zahl_char_t zahl_x__ = (x); \ 87 | for (; zahl_x__ & 1; zahl_x__ >>= 1, (r)++); \ 88 | } while (0) 89 | # define ZAHL_SUB_CLZ(r, x) \ 90 | do { \ 91 | zahl_char_t zahl_x__ = (x); \ 92 | (r) -= 8 * sizeof(zahl_char_t); \ 93 | for (; zahl_x__; zahl_x__ >>= 1, (r)++); \ 94 | } while (0) 95 | #endif 96 | 97 | 98 | typedef uint64_t zahl_char_t; 99 | 100 | struct zahl { 101 | int sign; 102 | #if INT_MAX != LONG_MAX 103 | int padding__; 104 | #endif 105 | size_t used; 106 | size_t alloced; 107 | zahl_char_t *chars; 108 | }; 109 | 110 | 111 | extern struct zahl libzahl_tmp_div[1]; 112 | extern struct zahl libzahl_tmp_mod[1]; 113 | 114 | 115 | void libzahl_realloc(struct zahl *, size_t); 116 | 117 | #include "memory.h" 118 | -------------------------------------------------------------------------------- /zahl/memory.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | #define LIBZAHL_MEM_CASES \ 4 | LIBZAHL_X(20); \ 5 | LIBZAHL_X(19); \ 6 | LIBZAHL_X(18); \ 7 | LIBZAHL_X(17); \ 8 | LIBZAHL_X(16); \ 9 | LIBZAHL_X(15); \ 10 | LIBZAHL_X(14); \ 11 | LIBZAHL_X(13); \ 12 | LIBZAHL_X(12); \ 13 | LIBZAHL_X(11); \ 14 | LIBZAHL_X(10); \ 15 | LIBZAHL_X( 9); \ 16 | LIBZAHL_X( 8); \ 17 | LIBZAHL_X( 7); \ 18 | LIBZAHL_X( 6); \ 19 | LIBZAHL_X( 5); \ 20 | LIBZAHL_X( 4); \ 21 | LIBZAHL_X( 3); \ 22 | LIBZAHL_X( 2); \ 23 | LIBZAHL_X( 1); \ 24 | case 0: break; 25 | 26 | 27 | #if defined(ZAHL_ISA_MISSING_INDIRECT_JUMP) 28 | # define LIBZAHL_SMALL_INPUT_BEGIN(n) 29 | # define LIBZAHL_SMALL_INPUT_END 30 | #else 31 | # define LIBZAHL_SMALL_INPUT_BEGIN(n) switch (n) { LIBZAHL_MEM_CASES default: 32 | # define LIBZAHL_SMALL_INPUT_END break; } 33 | #endif 34 | 35 | 36 | ZAHL_INLINE void 37 | libzahl_memcpy(register zahl_char_t *restrict d, register const zahl_char_t *restrict s, register size_t n) 38 | { 39 | #define LIBZAHL_X(I) case I: d[I - 1] = s[I - 1]; 40 | LIBZAHL_SMALL_INPUT_BEGIN(n); 41 | { 42 | #if defined(__x86_64__) && !defined(ZAHL_NO_ASM) 43 | /* This crap is needed for clang. */ 44 | register zahl_char_t t; 45 | __asm__ __volatile__ ( 46 | # if defined(ZAHL_ISA_MISSING_INDIRECT_JUMP) 47 | "\n testq %[e], %[e]" 48 | "\n jz 2f" 49 | # endif 50 | "\n shlq $3, %[e]" 51 | "\n addq %[d], %[e]" 52 | "\n 1:" 53 | "\n movq 0(%[s]), %[t]" 54 | "\n movq %[t], 0(%[d])" 55 | "\n movq 8(%[s]), %[t]" 56 | "\n movq %[t], 8(%[d])" 57 | "\n movq 16(%[s]), %[t]" 58 | "\n movq %[t], 16(%[d])" 59 | "\n movq 24(%[s]), %[t]" 60 | "\n movq %[t], 24(%[d])" 61 | "\n addq $32, %[s]" 62 | "\n addq $32, %[d]" 63 | "\n cmpq %[e], %[d]" 64 | "\n jl 1b" 65 | # if defined(ZAHL_ISA_MISSING_INDIRECT_JUMP) 66 | "\n 2:" 67 | # endif 68 | : [t]"=r"(t), [d]"+r"(d), [s]"+r"(s), [e]"+r"(n)); 69 | #else 70 | size_t i; 71 | for (i = 0; i < n; i += 4) { 72 | d[i + 0] = s[i + 0]; 73 | d[i + 1] = s[i + 1]; 74 | d[i + 2] = s[i + 2]; 75 | d[i + 3] = s[i + 3]; 76 | } 77 | #endif 78 | } 79 | LIBZAHL_SMALL_INPUT_END; 80 | #undef LIBZAHL_X 81 | } 82 | 83 | 84 | ZAHL_INLINE void 85 | libzahl_memset(register zahl_char_t *a, register zahl_char_t v, size_t n) 86 | { 87 | size_t i; 88 | for (i = 0; i < n; i += 4) { 89 | a[i + 0] = v; 90 | a[i + 1] = v; 91 | a[i + 2] = v; 92 | a[i + 3] = v; 93 | } 94 | } 95 | 96 | ZAHL_INLINE void 97 | libzahl_memset_precise(register zahl_char_t *a, register zahl_char_t v, size_t n) 98 | { 99 | size_t i; 100 | if (n <= 4) { 101 | if (n >= 1) 102 | a[0] = v; 103 | if (n >= 2) 104 | a[1] = v; 105 | if (n >= 3) 106 | a[2] = v; 107 | if (n >= 4) 108 | a[3] = v; 109 | } else { 110 | for (i = 0; (i += 4) <= n;) { 111 | a[i - 1] = v; 112 | a[i - 2] = v; 113 | a[i - 3] = v; 114 | a[i - 4] = v; 115 | } 116 | if (i > n) 117 | for (i -= 4; i < n; i++) 118 | a[i] = v; 119 | } 120 | } 121 | 122 | 123 | ZAHL_INLINE void 124 | libzahl_memmovef(register zahl_char_t *d, register const zahl_char_t *s, size_t n) 125 | { 126 | if (n && n < 4) { 127 | d[0] = s[0]; 128 | d[1] = s[1]; 129 | d[2] = s[2]; 130 | } else { 131 | size_t i; 132 | for (i = 0; i < n; i += 4) { 133 | d[i + 0] = s[i + 0]; 134 | d[i + 1] = s[i + 1]; 135 | d[i + 2] = s[i + 2]; 136 | d[i + 3] = s[i + 3]; 137 | } 138 | } 139 | } 140 | 141 | ZAHL_INLINE void 142 | libzahl_memmoveb(register zahl_char_t *d, register const zahl_char_t *s, size_t n) 143 | { 144 | ssize_t i; 145 | #define LIBZAHL_X(I) case I: d[I - 1] = s[I - 1]; 146 | LIBZAHL_SMALL_INPUT_BEGIN(n); 147 | for (i = ((ssize_t)n + 3) & ~3; (i -= 4) >= 0;) { 148 | d[i + 3] = s[i + 3]; 149 | d[i + 2] = s[i + 2]; 150 | d[i + 1] = s[i + 1]; 151 | d[i + 0] = s[i + 0]; 152 | } 153 | LIBZAHL_SMALL_INPUT_END; 154 | #undef LIBZAHL_X 155 | } 156 | 157 | ZAHL_INLINE void 158 | libzahl_memmove(register zahl_char_t *d, register const zahl_char_t *s, size_t n) 159 | { 160 | if (d < s) 161 | libzahl_memmovef(d, s, n); 162 | else 163 | libzahl_memmoveb(d, s, n); 164 | } 165 | --------------------------------------------------------------------------------