libzahl

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

commit aff09967d194d062ae8d83c0fbe1edf158804ef9
parent 0a7e36380717fe926d43ab30ef6162db9bd71723
Author: Mattias Andrée <maandree@kth.se>
Date:   Fri,  4 Mar 2016 10:45:10 +0100

Clean up, fix a few bugs, and add a test

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

Diffstat:
M.gitignore | 1+
MMakefile | 7+++++--
Msrc/internals.h | 3++-
Msrc/zadd.c | 3+--
Msrc/zand.c | 3+--
Msrc/zbset.c | 18+++++++++---------
Msrc/zload.c | 11++++++-----
Msrc/zlsh.c | 6++----
Msrc/zmodpow.c | 8+++++++-
Msrc/zmul.c | 2+-
Msrc/zor.c | 3+--
Msrc/zpow.c | 8+++++++-
Msrc/zrand.c | 23++++++++++++++++-------
Msrc/zrsh.c | 3+--
Msrc/zset.c | 3+--
Msrc/zsetu.c | 3+--
Msrc/zsqr.c | 2+-
Msrc/ztrunc.c | 7++++---
Msrc/zxor.c | 3+--
Atest.c | 724+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20 files changed, 792 insertions(+), 49 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -3,3 +3,4 @@ *.su *.a *.so +/test diff --git a/Makefile b/Makefile @@ -56,7 +56,7 @@ FUN =\ OBJ = $(FUN:=.o) MAN = $(foreach F,$(FUN),man/$(F).3) man/libzahl.7 -all: libzahl.a +all: libzahl.a test %.o: src/%.c $(HDR) config.mk $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< @@ -65,7 +65,10 @@ libzahl.a: $(OBJ) $(AR) rc $@ $? $(RANLIB) $@ +test: test.c libzahl.a + $(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ $^ + clean: - -rm -- *.o *.su *.a *.so 2>/dev/null + -rm -- *.o *.su *.a *.so test 2>/dev/null .PHONY: all clean diff --git a/src/internals.h b/src/internals.h @@ -62,7 +62,8 @@ extern int libzahl_set_up; #define zmemcmp(a, b, n) memcmp(a, b, (n) * sizeof(zahl_char_t)) #define SET_SIGNUM(a, signum) ((a)->sign = (signum)) -#define SET(a, b) do { if (a != b) zset(a, b); } while (0) +#define SET(a, b) do { if ((a) != (b)) zset(a, b); } while (0) +#define ENSURE_SIZE(a, n) do { if ((a)->alloced < (n)) zahl_realloc(a, (n)); } while (0) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) diff --git a/src/zadd.c b/src/zadd.c @@ -15,8 +15,7 @@ zadd_unsigned(z_t a, z_t b, z_t c) } size = MAX(b->used, c->used); - if (a->alloced < size + 1) - zahl_realloc(a, size + 1); + ENSURE_SIZE(a, size + 1); a->chars[size] = 0; n = b->used + c->used - size; diff --git a/src/zand.c b/src/zand.c @@ -28,8 +28,7 @@ found_highest: while (n--) a->chars[n] &= b->chars[n]; } else { - if (a->alloced < a->used) - zahl_realloc(a, a->used); + ENSURE_SIZE(a, a->used); zmemcpy(a->chars, c->chars, a->used); while (n--) a->chars[n] &= b->chars[n]; diff --git a/src/zbset.c b/src/zbset.c @@ -5,12 +5,12 @@ void zbset(z_t a, z_t b, size_t bit, int action) { - zahl_char_t x = 1; + zahl_char_t mask = 1; size_t chars; chars = FLOOR_BITS_TO_CHARS(bit); bit = BITS_IN_LAST_CHAR(bit); - x <<= bit; + mask <<= bit; SET(a, b); @@ -20,19 +20,19 @@ zbset(z_t a, z_t b, size_t bit, int action) SET_SIGNUM(a, 1); } if (a->used <= chars) { - if (a->alloced <= chars) - zahl_realloc(a, chars + 1); - zmemset(a->chars + a->used, 0, chars - a->used + 1); + ENSURE_SIZE(a, chars + 1); + zmemset(a->chars + a->used, 0, chars + 1 - a->used); + a->used = chars + 1; } } if (action > 0) { - a->chars[chars] |= x; + a->chars[chars] |= mask; return; } else if (action < 0) { - a->chars[chars] ^= x; - } else if (a->used > chars) { - a->chars[chars] &= ~x; + a->chars[chars] ^= mask; + } else if (chars < a->used) { + a->chars[chars] &= ~mask; } while (a->used && !a->chars[a->used - 1]) diff --git a/src/zload.c b/src/zload.c @@ -6,11 +6,12 @@ size_t zload(z_t a, const void *buffer) { const char *buf = buffer; - a->sign = *((const int *)buf), buf += sizeof(int); - a->used = *((const size_t *)buf), buf += sizeof(size_t); - a->alloced = *((const size_t *)buf), buf += sizeof(size_t); - if (a->alloced) - zahl_realloc(a, a->alloced); + size_t alloced; + a->sign = *((const int *)buf), buf += sizeof(int); + a->used = *((const size_t *)buf), buf += sizeof(size_t); + alloced = *((const size_t *)buf), buf += sizeof(size_t); + if (alloced) + ENSURE_SIZE(a, alloced); else a->chars = 0; if (!zzero(a)) diff --git a/src/zlsh.c b/src/zlsh.c @@ -22,8 +22,7 @@ zlsh(z_t a, z_t b, size_t bits) cbits = BITS_PER_CHAR - 1 - bits; a->used = b->used + chars; - if (a->alloced < a->used) - zahl_realloc(a, a->used); + ENSURE_SIZE(a, a->used); if (a == b) zmemmove(a->chars + chars, b->chars, a->used); else @@ -36,8 +35,7 @@ zlsh(z_t a, z_t b, size_t bits) a->chars[i] |= carry[i & 1]; } if (carry[i & 1]) { - if (a->alloced == a->used) - zahl_realloc(a, a->alloced << 1); + ENSURE_SIZE(a, a->alloced << 1); a->chars[i] = carry[i & 1]; a->used++; } diff --git a/src/zmodpow.c b/src/zmodpow.c @@ -42,7 +42,7 @@ zmodpow(z_t a, z_t b, z_t c, z_t d) zset(td, d); zsetu(a, 1); - for (i = 0; i < n; i++) { + for (i = 0; i < n; i++) { /* Remember, n is floored. */ x = tc->chars[i]; for (j = BITS_PER_CHAR; j--; x >>= 1) { if (x & 1) @@ -50,4 +50,10 @@ zmodpow(z_t a, z_t b, z_t c, z_t d) zmodsqr(tb, tb, td); } } + x = tc->chars[i]; + for (; x; x >>= 1) { + if (x & 1) + zmodmul(a, a, tb, td); + zmodsqr(tb, tb, td); + } } diff --git a/src/zmul.c b/src/zmul.c @@ -24,7 +24,7 @@ zmul(z_t a, z_t b, z_t c) b_sign = zsignum(b); c_sign = zsignum(c); - if (m <= 16 && m2 <= 16) { + if (m <= BITS_PER_CHAR / 2 && m2 <= BITS_PER_CHAR / 2) { zsetu(a, b->chars[0] * c->chars[0]); SET_SIGNUM(a, b_sign * c_sign); return; diff --git a/src/zor.c b/src/zor.c @@ -21,8 +21,7 @@ zor(z_t a, z_t b, z_t c) m = MAX(b->used, c->used); n = b->used + c->used - m; - if (a->alloced < m) - zahl_realloc(a, m); + ENSURE_SIZE(a, m); if (a == b) { zmemcpy(a->chars + n, m == b->used ? b->chars : c->chars, m - n); diff --git a/src/zpow.c b/src/zpow.c @@ -37,7 +37,7 @@ zpow(z_t a, z_t b, z_t c) zset(tc, c); zsetu(a, 1); - for (i = 0; i < n; i++) { + for (i = 0; i < n; i++) { /* Remember, n is floored. */ x = tc->chars[i]; for (j = BITS_PER_CHAR; j--; x >>= 1) { if (x & 1) @@ -45,4 +45,10 @@ zpow(z_t a, z_t b, z_t c) zsqr(tb, tb); } } + x = tc->chars[i]; + for (; x; x >>= 1) { + if (x & 1) + zmul(a, a, tb); + zsqr(tb, tb); + } } diff --git a/src/zrand.c b/src/zrand.c @@ -16,15 +16,16 @@ static void zrand_get_random_bits(z_t r, size_t bits, int fd) { - size_t read_total, n, chars = CEILING_BITS_TO_CHARS(bits); + size_t read_total = 0, n, chars = CEILING_BITS_TO_CHARS(bits); ssize_t read_just; - uint32_t mask = 1; + zahl_char_t mask = 1; + char *buf; - if (r->alloced < chars) - zahl_realloc(r, chars); + ENSURE_SIZE(r, chars); + buf = (char *)(r->chars); - for (n = chars << LB_BITS_PER_CHAR; n;) { - read_just = read(fd, (char *)(r->chars) + read_total, n); + for (n = chars * sizeof(zahl_char_t); n;) { + read_just = read(fd, buf + read_total, n); if (read_just < 0) FAILURE_JUMP(); read_total += (size_t)read_just; @@ -75,6 +76,10 @@ zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n) switch (dist) { case QUASIUNIFORM: + if (zsignum(n) < 0) { + errno = EDOM; /* n must be non-negative. */ + FAILURE_JUMP(); + } bits = zbits(n); zrand_get_random_bits(r, bits, fd); zadd(r, r, libzahl_const_1); @@ -83,10 +88,14 @@ zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n) break; case UNIFORM: + if (zsignum(n) < 0) { + errno = EDOM; /* n must be non-negative. */ + FAILURE_JUMP(); + } bits = zbits(n); do zrand_get_random_bits(r, bits, fd); - while (zcmp(r, n) > 0); + while (zcmpmag(r, n) > 0); break; default: diff --git a/src/zrsh.c b/src/zrsh.c @@ -27,8 +27,7 @@ zrsh(z_t a, z_t b, size_t bits) zmemmove(a->chars, a->chars + chars, a->used); } else if (a != b) { a->used = b->used - chars; - if (a->alloced < a->used) - zahl_realloc(a, a->used); + ENSURE_SIZE(a, a->used); zmemcpy(a->chars, b->chars + chars, a->used); } diff --git a/src/zset.c b/src/zset.c @@ -8,8 +8,7 @@ zset(z_t a, z_t b) if (zzero(b)) { SET_SIGNUM(a, 0); } else { - if (a->alloced < b->alloced) - zahl_realloc(a, b->alloced); + ENSURE_SIZE(a, b->alloced); a->sign = b->sign; a->used = b->used; zmemcpy(a->chars, b->chars, b->used); diff --git a/src/zsetu.c b/src/zsetu.c @@ -11,8 +11,7 @@ zsetu(z_t a, unsigned long long int b) SET_SIGNUM(a, 0); return; } - if (a->alloced < SIZE_MULTIPLE(b, *(a->chars))) - zahl_realloc(a, SIZE_MULTIPLE(b, *(a->chars))); + ENSURE_SIZE(a, SIZE_MULTIPLE(b, *(a->chars))); SET_SIGNUM(a, 1); a->used = 0; while (b) { diff --git a/src/zsqr.c b/src/zsqr.c @@ -20,7 +20,7 @@ zsqr(z_t a, z_t b) m2 = zbits(b); - if (m2 <= 16) { + if (m2 <= BITS_PER_CHAR / 2) { zsetu(a, b->chars[0] * b->chars[0]); SET_SIGNUM(a, 1); return; diff --git a/src/ztrunc.c b/src/ztrunc.c @@ -18,9 +18,10 @@ ztrunc(z_t a, z_t b, size_t bits) a->used = MIN(chars, b->used); if (a->used < chars) bits = 0; - if (a->alloced < b->alloced) - zahl_realloc(a, b->alloced); - zmemcpy(a->chars, b->chars, a->used); + if (a != b) { + ENSURE_SIZE(a, b->alloced); + zmemcpy(a->chars, b->chars, a->used); + } bits = BITS_IN_LAST_CHAR(bits); if (bits) { mask <<= bits; diff --git a/src/zxor.c b/src/zxor.c @@ -26,8 +26,7 @@ zxor(z_t a, z_t b, z_t c) return; } - if (a->alloced < m) - zahl_realloc(a, m); + ENSURE_SIZE(a, m); if (a == b) { zmemcpy(a->chars + n, m == b->used ? b->chars : c->chars, m - n); diff --git a/test.c b/test.c @@ -0,0 +1,724 @@ +/* See LICENSE file for copyright and license details. */ +#include "zahl.h" + +#include <stdio.h> +#include <string.h> + +#define assert(expr, expected)\ + do {\ + int got = (expr);\ + if (!(got expected)) {\ + fprintf(stderr,\ + "Failure at line %i: %s, expected %s, but got %i.\n",\ + __LINE__, #expr, #expected, got);\ + return 1;\ + }\ + } while (0) + +#define assert_zu(expr, expected)\ + do {\ + size_t got = (expr);\ + if (got != (expected)) {\ + fprintf(stderr,\ + "Failure at line %i: %s, expected %zu, but got %zu.\n",\ + __LINE__, #expr, (size_t)(expected), got);\ + return 1;\ + }\ + } while (0) + +#define assert_s(expr, expected)\ + do {\ + const char *got = (expr);\ + if (strcmp(got, expected)) {\ + fprintf(stderr,\ + "Failure at line %i: %s, expected %s, but got %s.\n",\ + __LINE__, #expr, expected, got);\ + return 1;\ + }\ + } while (0) + +int +main(void) +{ + /* static because otherwise it would have to be volatile yeilding a lot of stupid + * warnings. auto variables are not guaranteed to be readable after a long jump. */ + static z_t a, b, c, d, _0, _1, _2, _3; + + jmp_buf env; + char buf[1000]; + int ret = 0; + size_t n; + + if (setjmp(env)) { + ret = 1; + goto done; + } + + zsetup(env); + zinit(a), zinit(b), zinit(c), zinit(d), zinit(_0), zinit(_1), zinit(_2), zinit(_3); + + zsetu(_0, 0); + zsetu(_1, 1); + zsetu(_2, 2); + zsetu(_3, 3); + + assert(zeven(_0), == 1); + assert(zodd(_0), == 0); + assert(zzero(_0), == 1); + assert(zsignum(_0), == 0); + assert(zeven(_1), == 0); + assert(zodd(_1), == 1); + assert(zzero(_1), == 0); + assert(zsignum(_1), == 1); + assert(zeven(_2), == 1); + assert(zodd(_2), == 0); + assert(zzero(_2), == 0); + assert(zsignum(_2), == 1); + + zswap(_1, _2); + assert(zeven(_2), == 0); + assert(zodd(_2), == 1); + assert(zzero(_2), == 0); + assert(zsignum(_2), == 1); + assert(zeven(_1), == 1); + assert(zodd(_1), == 0); + assert(zzero(_1), == 0); + assert(zsignum(_1), == 1); + zswap(_2, _1); + assert(zeven(_1), == 0); + assert(zodd(_1), == 1); + assert(zzero(_1), == 0); + assert(zsignum(_1), == 1); + assert(zeven(_2), == 1); + assert(zodd(_2), == 0); + assert(zzero(_2), == 0); + assert(zsignum(_2), == 1); + + assert((zneg(_2, _2), zsignum(_2)), == -1); zneg(_2, _2); + assert(zsignum(_2), == 1); + + assert(zcmp(_0, _0), == 0); + assert(zcmp(_1, _1), == 0); + assert(zcmp(_0, _1), < 0); + assert(zcmp(_1, _0), > 0); + assert(zcmp(_1, _2), < 0); + assert(zcmp(_2, _1), > 0); + assert(zcmp(_0, _2), < 0); + assert(zcmp(_2, _0), > 0); + + zbset(a, _0, 0, 1); + assert(zcmp(a, _1), == 0); + zbset(a, a, 1, 1); + assert(zcmp(a, _3), == 0); + zbset(a, a, 0, 0); + assert(zcmp(a, _2), == 0); + zbset(a, a, 0, 0); + assert(zcmp(a, _2), == 0); + zbset(a, a, 0, -1); + assert(zcmp(a, _3), == 0); + zbset(a, a, 0, -1); + assert(zcmp(a, _2), == 0); + + zadd(a, _0, _1); + assert(zsignum(a), == 1); + assert(zcmp(a, _1), == 0); + assert(zcmpi(a, 1), == 0); + assert(zcmpu(a, 1), == 0); + zneg(a, a); + assert(zsignum(a), == -1); + assert(zcmp(a, _1), < 0); + assert(zcmpi(a, 1), < 0); + assert(zcmpu(a, 1), < 0); + zadd(a, _2, _0); + assert(zsignum(a), == 1); + assert(zcmp(a, _2), == 0); + assert(zcmpi(a, 2), == 0); + assert(zcmpu(a, 2), == 0); + zneg(a, a); + assert(zsignum(a), == -1); + assert(zcmp(a, _2), < 0); + assert(zcmpi(a, 2), < 0); + assert(zcmpu(a, 2), < 0); + assert(zsignum(_1), == 1); + zadd(a, _1, _1); + assert(zsignum(a), == 1); + assert(zcmp(a, _2), == 0); + assert(zcmpi(a, 2), == 0); + assert(zcmpu(a, 2), == 0); + zset(b, _1); + zadd(a, b, _1); + assert(zsignum(a), == 1); + assert(zcmp(a, _2), == 0); + assert(zcmpi(a, 2), == 0); + assert(zcmpu(a, 2), == 0); + zneg(a, a); + zset(b, _2); + zneg(b, b); + assert(zsignum(a), == -1); + assert(zcmp(a, b), == 0); + assert(zcmp(a, _2), < 0); + assert(zcmpmag(a, b), == 0); + assert(zcmpmag(a, _2), == 0); + assert(zcmpi(a, 2), < 0); + assert(zcmpu(a, 2), < 0); + assert(zcmpi(a, -2), == 0); + assert((zneg(_2, _2), zcmp(a, _2)), == 0); zneg(_2, _2); + zadd(a, _1, _2); + assert(zsignum(a), == 1); + assert(zcmp(a, _2), > 0); + assert(zcmpi(a, 2), > 0); + assert(zcmpu(a, 2), > 0); + zneg(a, a); + zset(b, _2); + zneg(b, b); + assert(zsignum(a), == -1); + assert(zcmpmag(a, _2), > 0); + assert(zcmpmag(a, b), > 0); + assert(zcmp(a, b), < 0); + assert(zcmp(a, _2), < 0); + assert(zcmpi(a, 2), < 0); + assert(zcmpu(a, 2), < 0); + assert(zcmpi(a, -2), < 0); + assert((zneg(_2, _2), zcmp(a, _2)), < 0); zneg(_2, _2); + zneg(b, _3); + assert(zcmp(a, b), == 0); + + zsub(a, _2, _1); + assert(zcmpmag(_2, _1), > 0); + assert(zcmpmag(_2, _0), > 0); + assert(zcmpmag(_1, _0), > 0); + zsub(b, _1, _2); + assert(zcmpmag(_2, _0), > 0); + assert(zcmpmag(_1, _0), > 0); + assert(zcmpmag(_2, _1), > 0); + assert(zcmpmag(a, b), == 0); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, b), > 0); + assert(zcmp(a, _1), == 0); + assert(zcmp(b, _1), < 0); + zsub(a, _1, _1); + assert(zcmp(a, _0), == 0); + zseti(b, 0); + zsetu(c, 0); + zsub(a, b, c); + assert(zcmp(a, _0), == 0); + assert(zcmpmag(_2, _1), > 0); + assert(zcmp(_2, _1), > 0); + zsub(a, _2, _1); + assert(zsignum(a), == 1); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), == 0); + zsub(a, a, _1); + assert(zcmp(a, _0), == 0); + zsub(a, a, _0); + assert(zcmp(a, _0), == 0); + zsub(a, _1, _2); + assert(zcmp(a, _1), < 0); + assert(zcmpmag(a, _1), == 0); + zabs(a, a); + assert(zcmp(a, _1), == 0); + zabs(a, a); + assert(zcmp(a, _1), == 0); + zabs(a, _1); + assert(zcmp(a, _1), == 0); + zabs(a, _0); + assert(zcmp(a, _0), == 0); + + zseti(b, -1); + zseti(c, -2); + zadd(a, _0, b); + assert(zcmp(a, _0), < 0); + assert(zcmpi(a, -1), == 0); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), < 0); + zadd(a, b, _0); + assert(zcmp(a, _0), < 0); + assert(zcmpi(a, -1), == 0); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), < 0); + zadd(a, b, c); + assert(zcmp(a, c), < 0); + assert(zcmpmag(a, _2), > 0); + zadd(a, c, b); + assert(zcmp(a, c), < 0); + assert(zcmpmag(a, _2), > 0); + zadd(a, b, _1); + assert(zcmp(a, _0), == 0); + assert(zcmpmag(a, _0), == 0); + zadd(a, _1, b); + assert(zcmp(a, _0), == 0); + assert(zcmpmag(a, _0), == 0); + + zneg(b, _1); + zneg(c, _2); + zsub(a, _0, b); + assert(zcmp(a, _1), == 0); + zsub(a, b, _0); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), < 0); + zsub(a, b, c); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), == 0); + zsub(a, c, b); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), < 0); + zsub(a, b, _1); + assert(zcmpmag(a, _2), == 0); + assert(zcmp(a, _2), < 0); + assert(zcmp(a, c), == 0); + zsub(a, _1, b); + assert(zcmp(b, _1), < 0); + assert(zcmpmag(b, _1), == 0); + assert(zcmp(a, _2), == 0); + + zsetu(a, 1000); + zsetu(b, 0); + assert(zcmp(a, b), != 0); + n = zsave(a, buf); + assert(n, > 0); + assert_zu(zload(b, buf), n); + assert(zcmp(a, b), == 0); + + zneg(b, _1); + zneg(c, _2); + + assert((zadd_unsigned(a, b, c), zcmp(a, _3)), == 0); + assert((zadd_unsigned(a, b, c), zcmp(a, _3)), == 0); + assert((zadd_unsigned(a, b, _2), zcmp(a, _3)), == 0); + assert((zadd_unsigned(a, _1, c), zcmp(a, _3)), == 0); + + assert((zsub_unsigned(a, _2, _1), zcmp(a, _1)), == 0); + assert((zsub_unsigned(a, _2, b), zcmp(a, _1)), == 0); + assert((zsub_unsigned(a, c, _1), zcmp(a, _1)), == 0); + assert((zsub_unsigned(a, c, b), zcmp(a, _1)), == 0); + + assert((zsub_unsigned(a, _1, _2), zcmp(a, b)), == 0); + assert((zsub_unsigned(a, b, _2), zcmp(a, b)), == 0); + assert((zsub_unsigned(a, _1, c), zcmp(a, b)), == 0); + assert((zsub_unsigned(a, b, c), zcmp(a, b)), == 0); + + assert_zu(zbits(_0), 1); + assert_zu(zbits(_1), 1); + assert_zu(zbits(_2), 2); + assert_zu(zbits(_3), 2); + + assert_zu(zlsb(_0), SIZE_MAX); + assert_zu(zlsb(_1), 0); + assert_zu(zlsb(_2), 1); + assert_zu(zlsb(_3), 0); + + assert((zand(a, _0, _0), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zand(a, _0, _1), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zand(a, _0, _2), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zand(a, _0, _3), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zand(a, _1, _1), zcmp(a, _1)), == 0); + assert((zand(a, _1, _2), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zand(a, _1, _3), zcmp(a, _1)), == 0); + assert((zand(a, _2, _2), zcmp(a, _2)), == 0); + assert((zand(a, _2, _3), zcmp(a, _2)), == 0); + assert((zand(a, _3, _3), zcmp(a, _3)), == 0); + + assert((zor(a, _0, _0), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zor(a, _0, _1), zcmp(a, _1)), == 0); + assert((zor(a, _0, _2), zcmp(a, _2)), == 0); + assert((zor(a, _0, _3), zcmp(a, _3)), == 0); + assert((zor(a, _1, _1), zcmp(a, _1)), == 0); + assert((zor(a, _1, _2), zcmp(a, _3)), == 0); + assert((zor(a, _1, _3), zcmp(a, _3)), == 0); + assert((zor(a, _2, _2), zcmp(a, _2)), == 0); + assert((zor(a, _2, _3), zcmp(a, _3)), == 0); + assert((zor(a, _3, _3), zcmp(a, _3)), == 0); + + assert((zxor(a, _0, _0), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zxor(a, _0, _1), zcmp(a, _1)), == 0); + assert((zxor(a, _0, _2), zcmp(a, _2)), == 0); + assert((zxor(a, _0, _3), zcmp(a, _3)), == 0); + assert((zxor(a, _1, _1), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zxor(a, _1, _2), zcmp(a, _3)), == 0); + assert((zxor(a, _1, _3), zcmp(a, _2)), == 0); + assert((zxor(a, _2, _2), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zxor(a, _2, _3), zcmp(a, _1)), == 0); + assert((zxor(a, _3, _3), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + + zneg(b, _1); + zneg(c, _3); + zneg(_1, _1); + zand(a, b, c); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), == 0); + zneg(_1, _1); + assert((zand(a, b, _3), zcmp(a, _1)), == 0); + assert((zand(a, _1, c), zcmp(a, _1)), == 0); + assert((zand(a, _0, c), zcmp(a, _0)), == 0); + assert((zand(a, b, _0), zcmp(a, _0)), == 0); + + zneg(b, _1); + zneg(c, _2); + zneg(_3, _3); + zor(a, b, c); + assert(zcmpmag(a, _3), == 0); + assert(zcmp(a, _3), == 0); + zor(a, b, _2); + assert(zcmpmag(a, _3), == 0); + assert(zcmp(a, _3), == 0); + zor(a, _1, c); + assert((zcmpmag(a, _3)), == 0); + assert((zcmp(a, _3)), == 0); + assert((zor(a, _0, c), zcmp(a, c)), == 0); + assert((zor(a, b, _0), zcmp(a, b)), == 0); + zneg(_3, _3); + + zneg(b, _1); + zneg(c, _2); + zxor(a, b, c); + assert(zcmpmag(a, _3), == 0); + assert(zcmp(a, _3), == 0); + zneg(_3, _3); + zxor(a, b, _2); + assert(zcmpmag(a, _3), == 0); + assert(zcmp(a, _3), == 0); + zxor(a, _1, c); + assert(zcmpmag(a, _3), == 0); + assert(zcmp(a, _3), == 0); + zxor(a, b, _0); + assert(zcmpmag(a, b), == 0); + assert(zcmp(a, b), == 0); + zxor(a, _0, c); + assert(zcmpmag(a, c), == 0); + assert(zcmp(a, c), == 0); + zneg(_3, _3); + + assert((zlsh(a, _0, 0), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zlsh(a, _0, 1), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zlsh(a, _1, 0), zcmp(a, _1)), == 0); + assert((zlsh(a, _1, 1), zcmp(a, _2)), == 0); + assert((zlsh(a, _1, 2), zcmp(a, _2)), > 0); + assert((zlsh(a, _2, 0), zcmp(a, _2)), == 0); + assert((zlsh(a, _2, 1), zcmp(a, _2)), > 0); + + zset(a, _0); + assert((zlsh(a, a, 0), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zlsh(a, a, 1), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + zset(a, _1); + assert((zlsh(a, a, 0), zcmp(a, _1)), == 0); + assert((zlsh(a, a, 1), zcmp(a, _2)), == 0); + assert((zlsh(a, a, 2), zcmp(a, _2)), > 0); + zset(a, _2); + assert((zlsh(a, a, 0), zcmp(a, _2)), == 0); + assert((zlsh(a, a, 1), zcmp(a, _2)), > 0); + + assert((zrsh(a, _0, 0), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zrsh(a, _0, 1), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zrsh(a, _1, 0), zcmp(a, _1)), == 0); + assert((zrsh(a, _1, 1), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zrsh(a, _1, 2), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zrsh(a, _2, 0), zcmp(a, _2)), == 0); + assert((zrsh(a, _2, 1), zcmp(a, _1)), == 0); + assert((zrsh(a, _2, 2), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + + zset(a, _0); + assert((zrsh(a, a, 0), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zrsh(a, a, 1), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + zset(a, _1); + assert((zrsh(a, a, 0), zcmp(a, _1)), == 0); + assert((zrsh(a, a, 1), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + assert((zrsh(a, a, 2), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + zset(a, _2); + assert((zrsh(a, a, 0), zcmp(a, _2)), == 0); + assert((zrsh(a, a, 1), zcmp(a, _1)), == 0); + assert((zrsh(a, a, 2), zcmp(a, _0)), == 0); + assert(zzero(a), == 1); + + assert(zbtest(_0, 0), == 0); + assert(zbtest(_1, 0), == 1); + assert(zbtest(_2, 0), == 0); + assert(zbtest(_3, 0), == 1); + assert(zbtest(_0, 1), == 0); + assert(zbtest(_1, 1), == 0); + assert(zbtest(_2, 1), == 1); + assert(zbtest(_3, 1), == 1); + assert(zbtest(_0, 2), == 0); + assert(zbtest(_1, 2), == 0); + assert(zbtest(_2, 2), == 0); + assert(zbtest(_3, 2), == 0); + + znot(a, _2); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), != 0); + znot(a, a); + assert(zcmp(a, _0), == 0); + + zsetu(a, 0xEEFF); + zsetu(c, 0xEE); + zsetu(d, 0xFF); + zsplit(a, b, a, 8); + assert(zcmpmag(a, c), == 0); + assert(zcmpmag(b, d), == 0); + zsetu(a, 0xEEFF); + zsplit(b, a, a, 8); + assert(zcmpmag(b, c), == 0); + assert(zcmpmag(a, d), == 0); + + zmul(a, _2, _3); + assert(zcmpi(a, 6), == 0); + zneg(_3, _3); + zmul(a, _2, _3); + assert(zcmpi(a, -6), == 0); + zneg(_3, _3); + zneg(_2, _2); + zmul(a, _2, _3); + assert(zcmpi(a, -6), == 0); + zneg(_3, _3); + zmul(a, _2, _3); + assert(zcmpi(a, 6), == 0); + zneg(_3, _3); + zneg(_2, _2); + + zmul(a, _3, _3); + assert(zcmpi(a, 9), == 0); + zsqr(a, _3); + assert(zcmpi(a, 9), == 0); + zneg(_3, _3); + zmul(a, _3, _3); + assert(zcmpi(a, 9), == 0); + zsqr(a, _3); + assert(zcmpi(a, 9), == 0); + zneg(_3, _3); + + zseti(a, 8); + zseti(b, 2); + zdiv(c, a, b); + assert(zcmpi(c, 4), == 0); + zseti(b, -2); + zdiv(c, a, b); + assert(zcmpi(c, -4), == 0); + zseti(a, -8); + zseti(b, 2); + zdiv(c, a, b); + assert(zcmpi(c, -4), == 0); + zseti(b, -2); + zdiv(c, a, b); + assert(zcmpi(c, 4), == 0); + + zseti(a, 1000); + zseti(b, 10); + zdiv(c, a, b); + assert(zcmpi(c, 100), == 0); + zseti(b, -10); + zdiv(c, a, b); + assert(zcmpi(c, -100), == 0); + zseti(a, -1000); + zseti(b, 10); + zdiv(c, a, b); + assert(zcmpi(c, -100), == 0); + zseti(b, -10); + zdiv(c, a, b); + assert(zcmpi(c, 100), == 0); + + zseti(a, 7); + zseti(b, 3); + zmod(c, a, b); + assert(zcmpi(c, 1), == 0); + zseti(b, -3); + zmod(c, a, b); + assert(zcmpi(c, 1), == 0); + zseti(a, -7); + zseti(b, 3); + zmod(c, a, b); + assert(zcmpi(c, 1), == 0); + zseti(b, -3); + zmod(c, a, b); + assert(zcmpi(c, 1), == 0); + + zseti(a, 7); + zseti(b, 3); + zdivmod(d, c, a, b); + assert(zcmpi(d, 2), == 0); + assert(zcmpi(c, 1), == 0); + zseti(b, -3); + zdivmod(d, c, a, b); + assert(zcmpi(d, -2), == 0); + assert(zcmpi(c, 1), == 0); + zseti(a, -7); + zseti(b, 3); + zdivmod(d, c, a, b); + assert(zcmpi(d, -2), == 0); + assert(zcmpi(c, 1), == 0); + zseti(b, -3); + zdivmod(d, c, a, b); + assert(zcmpi(d, 2), == 0); + assert(zcmpi(c, 1), == 0); + + zseti(a, 10); + zseti(b, -1); + zpow(a, a, b); + assert(zcmp(a, _0), == 0); + + zseti(a, 10); + zseti(b, -1); + zseti(a, 20); + zmodpow(a, a, b, c); + assert(zcmp(a, _0), == 0); + + zseti(a, 10); + zseti(c, 100000L); + zpowu(a, a, 5); + assert(zcmpmag(a, c), == 0); + assert(zcmp(a, c), == 0); + + zseti(a, -10); + zseti(c, -100000L); + zpowu(a, a, 5); + assert(zcmpmag(a, c), == 0); + assert(zcmp(a, c), == 0); + + zseti(a, -10); + zseti(c, 10000L); + zpowu(a, a, 4); + assert(zcmpmag(a, c), == 0); + assert(zcmp(a, c), == 0); + + zseti(a, 10); + zseti(c, 3); + zmodpowu(a, a, 5, c); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), == 0); + + zseti(a, 10); + zseti(b, 5); + zseti(c, 100000L); + zpow(a, a, b); + assert(zcmpmag(a, c), == 0); + assert(zcmp(a, c), == 0); + + zseti(a, -10); + zseti(b, 5); + zseti(c, -100000L); + zpow(a, a, b); + assert(zcmpmag(a, c), == 0); + assert(zcmp(a, c), == 0); + + zseti(a, -10); + zseti(b, 4); + zseti(c, 10000L); + zpow(a, a, b); + assert(zcmpmag(a, c), == 0); + assert(zcmp(a, c), == 0); + + zseti(a, 10); + zseti(b, 5); + zseti(c, 3); + zmodpow(a, a, b, c); + assert(zcmpmag(a, _1), == 0); + assert(zcmp(a, _1), == 0); + + zseti(a, 102); + zseti(b, 501); + zseti(c, 5); + zmodmul(a, a, b, c); + assert(zcmp(a, _2), == 0); + + zseti(b, 2 * 3 * 3 * 7); + zseti(c, 3 * 7 * 11); + zseti(d, 3 * 7); + assert((zgcd(a, _0, _0), zcmp(a, _0)), == 0); + assert((zgcd(a, b, _0), zcmp(a, b)), == 0); + assert((zgcd(a, _0, c), zcmp(a, c)), == 0); + assert((zgcd(a, b, b), zcmp(a, b)), == 0); + assert((zgcd(a, b, _2), zcmp(a, _2)), == 0); + assert((zgcd(a, _2, b), zcmp(a, _2)), == 0); + assert((zgcd(a, _2, _2), zcmp(a, _2)), == 0); + assert((zgcd(a, c, _2), zcmp(a, _1)), == 0); + assert((zgcd(a, _2, c), zcmp(a, _1)), == 0); + assert((zgcd(a, b, _1), zcmp(a, _1)), == 0); + assert((zgcd(a, _1, c), zcmp(a, _1)), == 0); + assert((zgcd(a, _1, _1), zcmp(a, _1)), == 0); + assert((zgcd(a, b, c), zcmp(a, d)), == 0); + assert((zgcd(a, c, b), zcmp(a, d)), == 0); + + zsets(a, "1234"); + assert(zcmpi(a, 1234), == 0); + zsets(b, "+1234"); + assert(zcmp(a, b), == 0); + assert_zu(zstr_length(_0, 10), 1); + assert_zu(zstr_length(_1, 10), 1); + assert_zu(zstr_length(_2, 10), 1); + assert_zu(zstr_length(_3, 10), 1); + zneg(_2, _2); + assert_zu(zstr_length(_2, 10), 2); + zneg(_2, _2); + assert_zu(zstr_length(a, 10), 4); + zstr(a, buf); + assert_s(buf, "1234"); + zsets(a, "-1234"); + zseti(b, -1234); + zseti(c, 1234); + assert(zcmp(a, _0), < 0); + assert(zcmp(a, b), == 0); + assert(zcmpmag(a, c), == 0); + assert(zcmp(a, c), < 0); + zstr(a, buf); + assert_s(buf, "-1234"); + assert_s(zstr(a, buf), "-1234"); + + zsetu(d, 100000UL); + zrand(a, FAST_RANDOM, UNIFORM, d); + assert(zcmp(a, _0), >= 0); + assert(zcmp(a, d), <= 0); + zrand(b, SECURE_RANDOM, UNIFORM, d); + assert(zcmp(b, _0), >= 0); + assert(zcmp(b, d), <= 0); + zrand(c, FAST_RANDOM, UNIFORM, d); + assert(zcmp(c, _0), >= 0); + assert(zcmp(c, d), <= 0); + assert(zcmp(a, b), != 0); + assert(zcmp(a, c), != 0); + assert(zcmp(b, c), != 0); + + assert((zseti(a, -5), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, -4), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, -3), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, -2), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, -1), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, 0), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, 1), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, 2), zptest(0, a, 100)), == PRIME); + assert((zseti(a, 3), zptest(0, a, 100)), == PRIME); + assert((zseti(a, 4), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, 5), zptest(0, a, 100)), != NONPRIME); + assert((zseti(a, 6), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, 7), zptest(0, a, 100)), != NONPRIME); + assert((zseti(a, 8), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, 9), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, 10), zptest(0, a, 100)), == NONPRIME); + assert((zseti(a, 11), zptest(0, a, 100)), != NONPRIME); + assert((zseti(a, 101), zptest(0, a, 100)), != NONPRIME); + +done: + zfree(a), zfree(b), zfree(c), zfree(d), zfree(_0), zfree(_1), zfree(_2), zfree(_3); + zunsetup(); + return ret; +}