commit 76d0af5599554d11f104d582cdac8fbaa8569fcc
parent aff09967d194d062ae8d83c0fbe1edf158804ef9
Author: Mattias Andrée <maandree@kth.se>
Date: Fri, 4 Mar 2016 23:50:00 +0100
Clean up, add zerror and zperror, fix bugs and add more tests
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat:
29 files changed, 533 insertions(+), 119 deletions(-)
diff --git a/Makefile b/Makefile
@@ -17,6 +17,7 @@ FUN =\
zcmpu\
zdiv\
zdivmod\
+ zerror\
zfree\
zgcd\
zinit\
@@ -32,6 +33,7 @@ FUN =\
zneg\
znot\
zor\
+ zperror\
zpow\
zpowu\
zptest\
diff --git a/man/zerror.3 b/man/zerror.3
@@ -0,0 +1,41 @@
+.TH ZERROR 3 libzahl
+.SH NAME
+zerror - Get the error that caused a jump to the jmp_buf passed to zsetup
+.SH SYNOPSIS
+.nf
+#include <zahl.h>
+
+enum zerror zerror(const char **\fIdesc\fP);
+.fi
+.SH DESCRIPTION
+.B zerror
+shall return the error that caused a libzahl
+function to perform a long jump to the point
+specified to
+.BR zsetup (3).
+If
+.I desc
+is not
+.BR 0 ,
+a textual description is set stored in
+.IR *desc .
+This string may be changed by a subsequent
+call to
+.BR strerror (3),
+.BR perror (3),
+.BR zperror (3),
+and similar functions.
+.P
+Currently available
+.B "enum zerror"
+values are:
+.P
+.TP
+.B ZERROR_ERRNO_SET
+The error is stored in
+.IR errno .
+(The error may not be stored in
+.I errno
+until this function is called.)
+.SH SEE ALSO
+.BR zperror (3)
diff --git a/man/zperror.3 b/man/zperror.3
@@ -0,0 +1,21 @@
+.TH ZPERROR 3 libzahl
+.SH NAME
+zperror - Print a libzahl error message
+.SH SYNOPSIS
+.nf
+#include <zahl.h>
+
+void zperror(const char *\fIprefix\fP);
+.fi
+.SH DESCRIPTION
+.B zperror
+prints a libzahl error message to standard error.
+Unless
+.I prefix
+is
+.B 0
+or an empty string, the message is prefixed by
+.IR prefix ,
+a colon and a blank space.
+.SH SEE ALSO
+.BR zerror (3)
diff --git a/man/zsetup.3 b/man/zsetup.3
@@ -56,4 +56,6 @@ code. Instead libzahl goes directly to the
part of the program that handles the error.
.SH SEE ALSO
.BR zunsetup (3),
-.BR zinit (3)
+.BR zinit (3),
+.BR zerror (3),
+.BR zperror (3)
diff --git a/src/internals.h b/src/internals.h
@@ -54,8 +54,9 @@ LIST_CONSTS
extern z_t libzahl_tmp_divmod_ds[BITS_PER_CHAR];
extern jmp_buf libzahl_jmp_buf;
extern int libzahl_set_up;
+extern int libzahl_error;
-#define FAILURE_JUMP() longjmp(libzahl_jmp_buf, 1)
+#define FAILURE(error) (libzahl_error = (error), longjmp(libzahl_jmp_buf, 1))
#define zmemcpy(d, s, n) memcpy(d, s, (n) * sizeof(zahl_char_t))
#define zmemmove(d, s, n) memmove(d, s, (n) * sizeof(zahl_char_t))
#define zmemset(a, v, n) memset(a, v, (n) * sizeof(zahl_char_t))
@@ -72,7 +73,10 @@ static inline void
zahl_realloc(z_t p, size_t n)
{
p->chars = realloc(p->chars, n * sizeof(zahl_char_t));
- if (!p->chars)
- FAILURE_JUMP();
+ if (!p->chars) {
+ if (!errno) /* sigh... */
+ errno = ENOMEM;
+ FAILURE(errno);
+ }
p->alloced = n;
}
diff --git a/src/zadd.c b/src/zadd.c
@@ -49,8 +49,8 @@ zadd_unsigned(z_t a, z_t b, z_t c)
a->chars[i] += addend[i] + carry[i & 1];
}
- while (carry[~i & 1]) {
- carry[i & 1] = a->chars[i] == ZAHL_CHAR_MAX;
+ while (carry[i & 1]) {
+ carry[~i & 1] = a->chars[i] == ZAHL_CHAR_MAX;
a->chars[i++] += 1;
}
diff --git a/src/zdivmod.c b/src/zdivmod.c
@@ -18,15 +18,13 @@ zdivmod(z_t a, z_t b, z_t c, z_t d)
if (!sign) {
if (zzero(c)) {
if (zzero(d)) {
- errno = EDOM; /* Indeterminate form: 0 divided by 0 */
- FAILURE_JUMP();
+ FAILURE(EDOM); /* Indeterminate form: 0 divided by 0 */
} else {
SET_SIGNUM(a, 0);
SET_SIGNUM(b, 0);
}
} else {
- errno = EDOM; /* Undefined form: Division by 0 */
- FAILURE_JUMP();
+ FAILURE(EDOM); /* Undefined form: Division by 0 */
}
return;
} else if ((cmpmag = zcmpmag(c, d)) <= 0) {
@@ -64,7 +62,7 @@ zdivmod(z_t a, z_t b, z_t c, z_t d)
zsub(tb, tb, td);
zbset(ta, ta, bit, 1);
}
- if (!bit--)
+ if (!bit-- || zzero(tb))
goto done;
zrsh(td, td, 1);
}
@@ -78,11 +76,10 @@ zdivmod(z_t a, z_t b, z_t c, z_t d)
zsub(tb, tb, tds[i]);
zbset(ta, ta, bit, 1);
}
- if (!bit--)
+ if (!bit-- || zzero(tb))
goto done;
- zrsh(tds[i], tds[i], 1);
}
- for (i = MIN(bit, BITS_PER_CHAR); i--;)
+ for (i = MIN(bit, BITS_PER_CHAR - 1) + 1; i--;)
zrsh(tds[i], tds[i], BITS_PER_CHAR);
}
}
diff --git a/src/zerror.c b/src/zerror.c
@@ -0,0 +1,19 @@
+/* See LICENSE file for copyright and license details. */
+#include "internals.h"
+
+
+enum zerror
+zerror(const char **desc)
+{
+ if (libzahl_error >= 0) {
+ if (desc)
+ *desc = strerror(libzahl_error);
+ errno = libzahl_error;
+ return ZERROR_ERRNO_SET;
+ } else {
+ /* Current, we should not be able to get here. */
+ if (desc)
+ abort();
+ return -libzahl_error;
+ }
+}
diff --git a/src/zload.c b/src/zload.c
@@ -6,15 +6,14 @@ size_t
zload(z_t a, const void *buffer)
{
const char *buf = buffer;
- 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);
+ a->alloced = 0;
+ if (a->sign)
+ ENSURE_SIZE(a, a->used);
else
a->chars = 0;
if (!zzero(a))
zmemcpy(a->chars, buf, a->used);
- return sizeof(z_t) - sizeof(a->chars) + (zzero(a) ? 0 : a->used * sizeof(*(a->chars)));
+ return sizeof(int) + sizeof(size_t) + (zzero(a) ? 0 : a->used * sizeof(zahl_char_t));
}
diff --git a/src/zlsh.c b/src/zlsh.c
@@ -19,25 +19,27 @@ zlsh(z_t a, z_t b, size_t bits)
chars = FLOOR_BITS_TO_CHARS(bits);
bits = BITS_IN_LAST_CHAR(bits);
- cbits = BITS_PER_CHAR - 1 - bits;
+ cbits = BITS_PER_CHAR - bits;
- a->used = b->used + chars;
- ENSURE_SIZE(a, a->used);
+ ENSURE_SIZE(a, b->used + chars);
if (a == b)
- zmemmove(a->chars + chars, b->chars, a->used);
+ zmemmove(a->chars + chars, b->chars, b->used);
else
- zmemcpy(a->chars + chars, b->chars, a->used);
+ zmemcpy(a->chars + chars, b->chars, b->used);
zmemset(a->chars, 0, chars);
+ a->used = b->used + chars;
- for (i = chars; i < a->used; i++) {
- carry[~i & 1] = a->chars[i] >> cbits;
- a->chars[i] <<= bits;
- a->chars[i] |= carry[i & 1];
- }
- if (carry[i & 1]) {
- ENSURE_SIZE(a, a->alloced << 1);
- a->chars[i] = carry[i & 1];
- a->used++;
+ if (bits) { /* This if statement is very important in C. */
+ for (i = chars; i < a->used; i++) {
+ carry[~i & 1] = a->chars[i] >> cbits;
+ a->chars[i] <<= bits;
+ a->chars[i] |= carry[i & 1];
+ }
+ if (carry[i & 1]) {
+ ENSURE_SIZE(a, a->used + 1);
+ a->chars[i] = carry[i & 1];
+ a->used++;
+ }
}
SET_SIGNUM(a, zsignum(b));
diff --git a/src/zmodpow.c b/src/zmodpow.c
@@ -14,21 +14,19 @@ zmodpow(z_t a, z_t b, z_t c, z_t d)
if (zsignum(c) <= 0) {
if (zzero(c)) {
- if (zzero(b)) {
- errno = EDOM; /* Indeterminate form: 0:th power of 0 */
- FAILURE_JUMP();
- }
+ if (zzero(b))
+ FAILURE(EDOM); /* Indeterminate form: 0:th power of 0 */
+ else if (zzero(d))
+ FAILURE(EDOM); /* Undefined form: Division by 0 */
zsetu(a, 1);
} else if (zzero(b) || zzero(d)) {
- errno = EDOM; /* Undefined form: Division by 0 */
- FAILURE_JUMP();
+ FAILURE(EDOM); /* Undefined form: Division by 0 */
} else {
SET_SIGNUM(a, 0);
}
return;
} else if (zzero(d)) {
- errno = EDOM; /* Undefined form: Division by 0 */
- FAILURE_JUMP();
+ FAILURE(EDOM); /* Undefined form: Division by 0 */
} else if (zzero(b)) {
SET_SIGNUM(a, 0);
return;
diff --git a/src/zmodpowu.c b/src/zmodpowu.c
@@ -9,19 +9,15 @@ void
zmodpowu(z_t a, z_t b, unsigned long long int c, z_t d)
{
if (!c) {
- if (zzero(b)) {
- errno = EDOM; /* Indeterminate form: 0:th power of 0 */
- FAILURE_JUMP();
- } else if (zzero(d)) {
- errno = EDOM; /* Undefined form: Division by 0 */
- FAILURE_JUMP();
- } else {
+ if (zzero(b))
+ FAILURE(EDOM); /* Indeterminate form: 0:th power of 0 */
+ else if (zzero(d))
+ FAILURE(EDOM); /* Undefined form: Division by 0 */
+ else
zsetu(a, 1);
- }
return;
} else if (zzero(d)) {
- errno = EDOM; /* Undefined form: Division by 0 */
- FAILURE_JUMP();
+ FAILURE(EDOM); /* Undefined form: Division by 0 */
} else if (zzero(b)) {
SET_SIGNUM(a, 0);
return;
diff --git a/src/zmul.c b/src/zmul.c
@@ -13,7 +13,10 @@ zmul(z_t a, z_t b, z_t c)
z_t z0, z1, z2, b_high, b_low, c_high, c_low;
int b_sign, c_sign;
- if (zzero(b) || zzero(c)) {
+ b_sign = zsignum(b);
+ c_sign = zsignum(c);
+
+ if (!b_sign || !c_sign) {
SET_SIGNUM(a, 0);
return;
}
@@ -21,11 +24,12 @@ zmul(z_t a, z_t b, z_t c)
m = zbits(b);
m2 = b == c ? m : zbits(c);
- b_sign = zsignum(b);
- c_sign = zsignum(c);
-
- if (m <= BITS_PER_CHAR / 2 && m2 <= BITS_PER_CHAR / 2) {
- zsetu(a, b->chars[0] * c->chars[0]);
+ if (m + m2 <= BITS_PER_CHAR) {
+ /* zsetu(a, b->chars[0] * c->chars[0]); { */
+ ENSURE_SIZE(a, 1);
+ a->used = 1;
+ a->chars[0] = b->chars[0] * c->chars[0];
+ /* } */
SET_SIGNUM(a, b_sign * c_sign);
return;
}
@@ -47,7 +51,7 @@ zmul(z_t a, z_t b, z_t c)
zsplit(b_high, b_low, b, m2);
zsplit(c_high, c_low, c, m2);
-#if 0
+#if 1
zmul(z0, b_low, c_low);
zmul(z2, b_high, c_high);
zadd(b_low, b_low, b_high);
@@ -57,9 +61,9 @@ zmul(z_t a, z_t b, z_t c)
zsub(z1, z1, z0);
zsub(z1, z1, z2);
- zlsh(z2, z2, m2);
- m2 <<= 1;
zlsh(z1, z1, m2);
+ m2 <<= 1;
+ zlsh(z2, z2, m2);
zadd(a, z2, z1);
zadd(a, a, z0);
diff --git a/src/zor.c b/src/zor.c
@@ -20,6 +20,7 @@ zor(z_t a, z_t b, z_t c)
m = MAX(b->used, c->used);
n = b->used + c->used - m;
+ a->used = m;
ENSURE_SIZE(a, m);
diff --git a/src/zperror.c b/src/zperror.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "internals.h"
+
+#include <stdio.h>
+
+
+void
+zperror(const char *prefix)
+{
+ if (libzahl_error >= 0) {
+ errno = libzahl_error;
+ perror(prefix);
+ } else {
+ /* Current, we should not be able to get here. */
+ abort();
+ }
+}
diff --git a/src/zpow.c b/src/zpow.c
@@ -13,14 +13,11 @@ zpow(z_t a, z_t b, z_t c)
if (zsignum(c) <= 0) {
if (zzero(c)) {
- if (zzero(b)) {
- errno = EDOM; /* Indeterminate form: 0:th power of 0 */
- FAILURE_JUMP();
- }
+ if (zzero(b))
+ FAILURE(EDOM); /* Indeterminate form: 0:th power of 0 */
zsetu(a, 1);
} else if (zzero(b)) {
- errno = EDOM; /* Undefined form: Division by 0 */
- FAILURE_JUMP();
+ FAILURE(EDOM); /* Undefined form: Division by 0 */
} else {
SET_SIGNUM(a, 0);
}
diff --git a/src/zpowu.c b/src/zpowu.c
@@ -8,10 +8,8 @@ void
zpowu(z_t a, z_t b, unsigned long long int c)
{
if (!c) {
- if (zzero(b)) {
- errno = EDOM; /* Indeterminate form: 0:th power of 0 */
- FAILURE_JUMP();
- }
+ if (zzero(b))
+ FAILURE(EDOM); /* Indeterminate form: 0:th power of 0 */
zsetu(a, 1);
return;
} else if (zzero(b)) {
diff --git a/src/zrand.c b/src/zrand.c
@@ -27,7 +27,7 @@ zrand_get_random_bits(z_t r, size_t bits, int fd)
for (n = chars * sizeof(zahl_char_t); n;) {
read_just = read(fd, buf + read_total, n);
if (read_just < 0)
- FAILURE_JUMP();
+ FAILURE(errno);
read_total += (size_t)read_just;
n -= (size_t)read_just;
}
@@ -72,14 +72,12 @@ zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n)
fd = open(pathname, O_RDONLY);
if (fd < 0)
- FAILURE_JUMP();
+ FAILURE(errno);
switch (dist) {
case QUASIUNIFORM:
- if (zsignum(n) < 0) {
- errno = EDOM; /* n must be non-negative. */
- FAILURE_JUMP();
- }
+ if (zsignum(n) < 0)
+ FAILURE(EDOM); /* n must be non-negative. */
bits = zbits(n);
zrand_get_random_bits(r, bits, fd);
zadd(r, r, libzahl_const_1);
@@ -88,10 +86,8 @@ 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();
- }
+ if (zsignum(n) < 0)
+ FAILURE(EDOM); /* n must be non-negative. */
bits = zbits(n);
do
zrand_get_random_bits(r, bits, fd);
diff --git a/src/zrsh.c b/src/zrsh.c
@@ -20,7 +20,7 @@ zrsh(z_t a, z_t b, size_t bits)
}
bits = BITS_IN_LAST_CHAR(bits);
- cbits = BITS_PER_CHAR - 1 - bits;
+ cbits = BITS_PER_CHAR - bits;
if (chars && a == b) {
a->used -= chars;
@@ -31,10 +31,14 @@ zrsh(z_t a, z_t b, size_t bits)
zmemcpy(a->chars, b->chars + chars, a->used);
}
- a->chars[0] >>= bits;
- for (i = 1; i < a->used; i++) {
- a->chars[i - 1] |= a->chars[i] >> cbits;
- a->chars[i] >>= bits;
+ if (bits) { /* This if statement is very important in C. */
+ a->chars[0] >>= bits;
+ for (i = 1; i < a->used; i++) {
+ a->chars[i - 1] |= a->chars[i] << cbits;
+ a->chars[i] >>= bits;
+ }
+ while (!a->chars[a->used - 1])
+ a->used--;
}
SET_SIGNUM(a, zsignum(b));
diff --git a/src/zsave.c b/src/zsave.c
@@ -9,9 +9,8 @@ zsave(z_t a, void *buffer)
char *buf = buffer;
*((int *)buf) = a->sign, buf += sizeof(int);
*((size_t *)buf) = a->used, buf += sizeof(size_t);
- *((size_t *)buf) = a->alloced, buf += sizeof(size_t);
if (!zzero(a))
zmemcpy(buf, a->chars, a->used);
}
- return sizeof(z_t) - sizeof(a->chars) + (zzero(a) ? 0 : a->used * sizeof(*(a->chars)));
+ return sizeof(int) + sizeof(size_t) + (zzero(a) ? 0 : a->used * sizeof(zahl_char_t));
}
diff --git a/src/zset.c b/src/zset.c
@@ -8,7 +8,7 @@ zset(z_t a, z_t b)
if (zzero(b)) {
SET_SIGNUM(a, 0);
} else {
- ENSURE_SIZE(a, b->alloced);
+ ENSURE_SIZE(a, b->used);
a->sign = b->sign;
a->used = b->used;
zmemcpy(a->chars, b->chars, b->used);
diff --git a/src/zsets.c b/src/zsets.c
@@ -26,21 +26,45 @@ zsets(z_t a, const char *str)
SET_SIGNUM(a, 0);
+#if 1
+ zset(libzahl_tmp_str_num, libzahl_const_1e19);
switch ((str_end - str) % 19) {
while (*str) {
+ zmul(a, a, libzahl_const_1e19);
+ temp = 0;
#define X(n)\
case n:\
temp *= 10, temp += *str++ & 15;
- X(0) X(18) X(17) X(16) X(15) X(14) X(13) X(12) X(11)
- X(10) X(9) X(8) X(7) X(6) X(5) X(4) X(3) X(2) X(1)
+ X(0) X(18) X(17) X(16) X(15) X(14) X(13) X(12) X(11)
+ X(10) X(9) X(8) X(7) X(6) X(5) X(4) X(3) X(2) X(1)
#undef X
-
- zmul(a, a, libzahl_const_1e19);
- zsetu(libzahl_tmp_str_num, temp);
+ if (!temp)
+ continue;
+ libzahl_tmp_str_num->chars[0] = (zahl_char_t)temp;
+ temp >>= BITS_PER_CHAR;
+ libzahl_tmp_str_num->chars[1] = (zahl_char_t)temp;
+ libzahl_tmp_str_num->used = 1 + !!temp;
zadd(a, a, libzahl_tmp_str_num);
+ }
+ }
+#else
+ zset(libzahl_tmp_str_num, libzahl_const_1);
+ switch ((str_end - str) % 9) {
+ while (*str) {
+ zmul(a, a, libzahl_const_1e9);
temp = 0;
+#define X(n)\
+ case n:\
+ temp *= 10, temp += *str++ & 15;
+ X(0) X(8) X(7) X(6) X(5) X(4) X(3) X(2) X(1)
+#undef X
+ if (!temp)
+ continue;
+ libzahl_tmp_str_num->chars[0] = temp;
+ zadd(a, a, libzahl_tmp_str_num);
}
}
+#endif
if (neg)
SET_SIGNUM(a, -zsignum(a));
diff --git a/src/zsetup.c b/src/zsetup.c
@@ -11,6 +11,7 @@ LIST_CONSTS
z_t libzahl_tmp_divmod_ds[BITS_PER_CHAR];
jmp_buf libzahl_jmp_buf;
int libzahl_set_up = 0;
+int libzahl_error;
void
diff --git a/src/zsqr.c b/src/zsqr.c
@@ -21,7 +21,11 @@ zsqr(z_t a, z_t b)
m2 = zbits(b);
if (m2 <= BITS_PER_CHAR / 2) {
- zsetu(a, b->chars[0] * b->chars[0]);
+ /* zsetu(a, b->chars[0] * b->chars[0]); { */
+ ENSURE_SIZE(a, 1);
+ a->used = 1;
+ a->chars[0] = b->chars[0] * b->chars[0];
+ /* } */
SET_SIGNUM(a, 1);
return;
}
@@ -38,14 +42,14 @@ zsqr(z_t a, z_t b)
zsplit(high, low, b, m2);
-#if 0
+#if 1
zsqr(z0, low);
zsqr(z2, high);
zmul(z1, low, high);
+ zlsh(z1, z1, m2 + 1);
+ m2 <<= 1;
zlsh(z2, z2, m2);
- m2 = (m2 << 1) | 1;
- zlsh(z1, z1, m2);
zadd(a, z2, z1);
zadd(a, a, z0);
diff --git a/src/zstr.c b/src/zstr.c
@@ -15,15 +15,16 @@
char *
zstr(z_t a, char *b)
{
- size_t n;
- char overridden;
+ char buf[9 + 1];
+ size_t n, len;
+ char overridden = 0;
int neg;
if (zzero(a)) {
if (!b) {
b = malloc(2);
if (!b)
- FAILURE_JUMP();
+ FAILURE(errno);
}
b[0] = '0';
b[1] = 0;
@@ -31,30 +32,32 @@ zstr(z_t a, char *b)
}
n = zstr_length(a, 10);
+
if (!b) {
b = malloc(n + 1);
if (!b)
- FAILURE_JUMP();
+ FAILURE(errno);
}
neg = zsignum(a) < 0;
zabs(num, a);
- n -= (size_t)neg;
- n = n > 9 ? (n - 9) : 0;
b[0] = '-';
b += neg;
- overridden = 0;
+ n -= neg;
+ n = n > 9 ? (n - 9) : 0;
for (;;) {
zdivmod(num, rem, num, libzahl_const_1e9);
if (!zzero(num)) {
- sprintf(b + n, "%09lu", (unsigned long)(rem->chars[0]));
+ sprintf(b + n, "%09lu", zzero(rem) ? 0UL : (unsigned long)(rem->chars[0]));
b[n + 9] = overridden;
- overridden = b[n + (9 - 1)];
+ overridden = b[n];
n = n > 9 ? (n - 9) : 0;
} else {
- n += (size_t)sprintf(b + n, "%lu", (unsigned long)(rem->chars[0]));
- b[n] = overridden;
+ len = (size_t)sprintf(buf, "%lu", (unsigned long)(rem->chars[0]));
+ if (overridden)
+ buf[len] = b[n + len];
+ memcpy(b + n, buf, len + 1);
break;
}
}
diff --git a/src/zsub.c b/src/zsub.c
@@ -30,7 +30,7 @@ zsub_unsigned(z_t a, z_t b, z_t c)
a->chars[i] -= carry[i & 1];
}
- if (carry[i] & 1) {
+ if (carry[i & 1]) {
while (!a->chars[i])
a->chars[i++] = ZAHL_CHAR_MAX;
a->chars[i] -= 1;
diff --git a/src/ztrunc.c b/src/ztrunc.c
@@ -19,7 +19,7 @@ ztrunc(z_t a, z_t b, size_t bits)
if (a->used < chars)
bits = 0;
if (a != b) {
- ENSURE_SIZE(a, b->alloced);
+ ENSURE_SIZE(a, a->used);
zmemcpy(a->chars, b->chars, a->used);
}
bits = BITS_IN_LAST_CHAR(bits);
diff --git a/test.c b/test.c
@@ -11,7 +11,8 @@
fprintf(stderr,\
"Failure at line %i: %s, expected %s, but got %i.\n",\
__LINE__, #expr, #expected, got);\
- return 1;\
+ ret = 1;\
+ goto done;\
}\
} while (0)
@@ -22,7 +23,8 @@
fprintf(stderr,\
"Failure at line %i: %s, expected %zu, but got %zu.\n",\
__LINE__, #expr, (size_t)(expected), got);\
- return 1;\
+ ret = 1;\
+ goto done;\
}\
} while (0)
@@ -33,7 +35,24 @@
fprintf(stderr,\
"Failure at line %i: %s, expected %s, but got %s.\n",\
__LINE__, #expr, expected, got);\
- return 1;\
+ ret = 1;\
+ goto done;\
+ }\
+ } while (0)
+
+#define assert_nr(expr)\
+ do {\
+ if (setjmp(env2)) {\
+ ret = 0;\
+ zsetup(env);\
+ } else {\
+ zsetup(env2);\
+ expr;\
+ fprintf(stderr,\
+ "Failure at line %i: %s, should not have returned.\n",\
+ __LINE__, #expr);\
+ ret = 1;\
+ goto done;\
}\
} while (0)
@@ -43,14 +62,14 @@ 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;
+ static char buf[1000];
+ static int ret = 0;
+ static jmp_buf env, env2;
+ static size_t n;
if (setjmp(env)) {
- ret = 1;
+ zperror(0);
+ ret = 2;
goto done;
}
@@ -183,6 +202,9 @@ main(void)
zneg(b, _3);
assert(zcmp(a, b), == 0);
+ zunsetup();
+ zsetup(env);
+
zsub(a, _2, _1);
assert(zcmpmag(_2, _1), > 0);
assert(zcmpmag(_2, _0), > 0);
@@ -471,6 +493,11 @@ main(void)
znot(a, a);
assert(zcmp(a, _0), == 0);
+ zsetu(a, 0x1234);
+ zsetu(c, 0x234);
+ ztrunc(a, a, 12);
+ assert(zcmp(a, c), == 0);
+
zsetu(a, 0xEEFF);
zsetu(c, 0xEE);
zsetu(d, 0xFF);
@@ -717,6 +744,254 @@ main(void)
assert((zseti(a, 11), zptest(0, a, 100)), != NONPRIME);
assert((zseti(a, 101), zptest(0, a, 100)), != NONPRIME);
+ assert_nr(zdivmod(a, b, _0, _0));
+ assert_nr(zdivmod(a, b, _1, _0));
+ zdivmod(a, b, _0, _1);
+ zdivmod(a, b, _1, _1);
+ assert_nr(zdiv(a, _0, _0));
+ assert_nr(zdiv(a, _1, _0));
+ zdiv(a, _0, _1);
+ zdiv(a, _1, _1);
+ assert_nr(zmod(a, _0, _0));
+ assert_nr(zmod(a, _1, _0));
+ zmod(a, _0, _1);
+ zmod(a, _1, _1);
+ assert_nr(zpow(a, _0, _0));
+ assert_nr((zneg(_1, _1), zpow(a, _0, _1))); zneg(_1, _1);
+ zpow(a, _0, _1);
+ zpow(a, _1, _0);
+ zneg(_1, _1), zpow(a, _1, _0), zneg(_1, _1);
+ assert_nr(zmodmul(a, _1, _1, _0));
+ assert_nr(zmodpow(a, _0, _0, _1));
+ assert_nr((zneg(_1, _1), zmodpow(a, _0, _1, _1))); zneg(_1, _1);
+ zmodpow(a, _0, _1, _1);
+ zmodpow(a, _1, _0, _1);
+ zneg(_1, _1), zmodpow(a, _1, _0, _1), zneg(_1, _1);
+ assert_nr(zmodpow(a, _0, _0, _0));
+ assert_nr((zneg(_1, _1), zmodpow(a, _0, _1, _0))); zneg(_1, _1);
+ assert_nr(zmodpow(a, _0, _1, _0));
+ assert_nr(zmodpow(a, _1, _0, _0));
+ assert_nr((zneg(_1, _1), zmodpow(a, _1, _0, _0))); zneg(_1, _1);
+ assert_nr(zpowu(a, _0, 0));
+ zpowu(a, _0, 1);
+ zpowu(a, _1, 0);
+ zneg(_1, _1), zpowu(a, _1, 0), zneg(_1, _1);
+ assert_nr(zmodpowu(a, _0, 0, _1));
+ zmodpowu(a, _0, 1, _1);
+ zmodpowu(a, _1, 0, _1);
+ zneg(_1, _1), zmodpowu(a, _1, 0, _1), zneg(_1, _1);
+ assert_nr(zmodpowu(a, _0, 0, _0));
+ assert_nr((zneg(_1, _1), zmodpowu(a, _0, 1, _0))); zneg(_1, _1);
+ assert_nr(zmodpowu(a, _0, 1, _0));
+ assert_nr(zmodpowu(a, _1, 0, _0));
+ assert_nr((zneg(_1, _1), zmodpowu(a, _1, 0, _0))); zneg(_1, _1);
+
+ zsetu(a, 1LL);
+ assert_s(zstr(a, buf), "1");
+ zsetu(a, 10LL);
+ assert_s(zstr(a, buf), "10");
+ zsetu(a, 100LL);
+ assert_s(zstr(a, buf), "100");
+ zsetu(a, 1000LL);
+ assert_s(zstr(a, buf), "1000");
+ zsetu(a, 10000LL);
+ assert_s(zstr(a, buf), "10000");
+ zsetu(a, 100000LL);
+ assert_s(zstr(a, buf), "100000");
+ zsetu(a, 1000000LL);
+ assert_s(zstr(a, buf), "1000000");
+ zsetu(a, 10000000LL);
+ assert_s(zstr(a, buf), "10000000");
+ zsetu(a, 100000000LL);
+ assert_s(zstr(a, buf), "100000000");
+ zsetu(a, 999999999LL);
+ assert_s(zstr(a, buf), "999999999");
+ zsetu(a, 1000000000LL);
+ assert_s(zstr(a, buf), "1000000000");
+ zsetu(a, 1000000001LL);
+ assert_s(zstr(a, buf), "1000000001");
+ zsetu(a, 2000000000LL);
+ assert_s(zstr(a, buf), "2000000000");
+ zsetu(a, 2050000000LL);
+ assert_s(zstr(a, buf), "2050000000");
+ zsetu(a, 2100000000LL);
+ assert_s(zstr(a, buf), "2100000000");
+ zsetu(a, 2140000000LL);
+ assert_s(zstr(a, buf), "2140000000");
+ zsetu(a, 2147000000LL);
+ assert_s(zstr(a, buf), "2147000000");
+ zsetu(a, 2147483000LL);
+ assert_s(zstr(a, buf), "2147483000");
+ zsetu(a, 2147483640LL);
+ assert_s(zstr(a, buf), "2147483640");
+ zsetu(a, 2147483646LL);
+ assert_s(zstr(a, buf), "2147483646");
+
+ zseti(a, 2147483647LL);
+ assert_s(zstr(a, buf), "2147483647");
+ zseti(a, -2147483647LL);
+ assert_s(zstr(a, buf), "-2147483647");
+ zseti(a, -2147483647LL - 1LL);
+ assert_s(zstr(a, buf), "-2147483648");
+
+ zsetu(a, 2147483647ULL);
+ assert_s(zstr(a, buf), "2147483647");
+ zsetu(a, 2147483648ULL);
+ assert_s(zstr(a, buf), "2147483648");
+ zsetu(a, 2147483649ULL);
+ assert_s(zstr(a, buf), "2147483649");
+
+ zsetu(a, 3000000000ULL);
+ assert_s(zstr(a, buf), "3000000000");
+ zsetu(a, 3100000000ULL);
+ assert_s(zstr(a, buf), "3100000000");
+ zsetu(a, 3200000000ULL);
+ assert_s(zstr(a, buf), "3200000000");
+ zsetu(a, 3300000000ULL);
+ assert_s(zstr(a, buf), "3300000000");
+ zsetu(a, 3400000000ULL);
+ assert_s(zstr(a, buf), "3400000000");
+ zsetu(a, 3500000000ULL);
+ assert_s(zstr(a, buf), "3500000000");
+ zsetu(a, 3600000000ULL);
+ assert_s(zstr(a, buf), "3600000000");
+ zsetu(a, 3700000000ULL);
+ assert_s(zstr(a, buf), "3700000000");
+ zsetu(a, 3800000000ULL);
+ assert_s(zstr(a, buf), "3800000000");
+ zsetu(a, 3900000000ULL);
+ assert_s(zstr(a, buf), "3900000000");
+ zsetu(a, 3999999999ULL);
+ assert_s(zstr(a, buf), "3999999999");
+ zsetu(a, 4000000000ULL);
+ assert_s(zstr(a, buf), "4000000000");
+ zsetu(a, 4000000001ULL);
+ assert_zu(zstr_length(a, 10), 10);
+ assert_s(zstr(a, buf), "4000000001");
+
+ zsetu(a, 4000000000ULL);
+ zsetu(b, 4000000000ULL);
+ zadd(c, a, a);
+ zsets(d, "8000000000");
+ assert(zcmp(c, d), == 0);
+ zadd(c, a, b);
+ assert(zcmp(c, d), == 0);
+ zadd(c, c, a);
+ zsets(d, "12000000000");
+ assert(zcmp(c, d), == 0);
+ zsub(c, c, a);
+ zsets(d, "8000000000");
+ assert(zcmp(c, d), == 0);
+ zsub(c, c, a);
+ zsets(d, "4000000000");
+ assert(zcmp(c, d), == 0);
+ zsets(d, "8000000000");
+ zrsh(d, d, 1);
+ assert(zcmp(c, d), == 0);
+ zsets(a, "6234216714");
+ zsets(b, "9424614147");
+ zsets(d, "830476546");
+ zand(c, a, b);
+ assert(zcmp(c, d), == 0);
+ zsets(a, "234216714");
+ zsets(b, "9424614147");
+ zsets(d, "9629466379");
+ zor(c, a, b);
+ assert(zcmp(c, d), == 0);
+ zsets(a, "6234216714");
+ zsets(b, "9424614147");
+ zsets(d, "13997877769");
+ zxor(c, a, b);
+ assert(zcmp(c, d), == 0);
+ zsets(a, "34216714");
+ zsets(b, "9424614147");
+ zsets(d, "9458821129");
+ zxor(c, a, b);
+ assert(zcmp(c, d), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(d, "1000000000000000000");
+ zmul(c, a, a);
+ assert(zcmp(c, d), == 0);
+ zdiv(c, c, a);
+ assert(zcmp(c, a), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(d, "1000000000000000000");
+ zsqr(c, a);
+ assert(zcmp(c, d), == 0);
+ zsetu(a, 1000000000ULL);
+ zmodpowu(c, a, 5, _3);
+ assert(zcmpu(c, 1), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(d, "1");
+ zpowu(c, a, 0);
+ assert(zcmp(c, d), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(d, "1000000000");
+ zpowu(c, a, 1);
+ assert(zcmp(c, d), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(d, "1000000000000000000");
+ zpowu(c, a, 2);
+ assert(zcmp(c, d), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(b, "1000000000000000000");
+ zsets(d, "1000000000000000000000000000");
+ zmul(c, a, b);
+ assert(zcmp(c, d), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(d, "1000000000000000000000000000");
+ zmul(b, a, a);
+ zmul(b, b, a);
+ assert(zcmp(c, d), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(d, "1000000000000000000000000000");
+ zpowu(c, a, 3);
+ assert(zcmp(c, d), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(d, "1000000000000000000000000000000000000");
+ zpowu(c, a, 4);
+ assert(zcmp(c, d), == 0);
+ zsetu(a, 1000000000ULL);
+ zsets(d, "1000000000000000000000000000000000000000000000");
+ zpowu(c, a, 5);
+ assert(zcmp(c, d), == 0);
+
+ zsetu(a, 4294967294ULL);
+ assert_s(zstr(a, buf), "4294967294");
+ zsetu(a, 4294967295ULL);
+ assert_s(zstr(a, buf), "4294967295");
+ zsetu(a, 4294967296ULL);
+ assert_s(zstr(a, buf), "4294967296");
+ zsetu(a, 4294967297ULL);
+ assert_s(zstr(a, buf), "4294967297");
+
+ zseti(a, 9223372036854775807LL);
+ assert_s(zstr(a, buf), "9223372036854775807");
+ zseti(a, -9223372036854775807LL);
+ assert_s(zstr(a, buf), "-9223372036854775807");
+ zseti(a, -9223372036854775807LL - 1LL);
+ assert_s(zstr(a, buf), "-9223372036854775808");
+
+ zsetu(a, 18446744073709551614ULL);
+ assert_s(zstr(a, buf), "18446744073709551614");
+ zsetu(a, 18446744073709551615ULL);
+ assert_s(zstr(a, buf), "18446744073709551615");
+ zadd(a, a, _1);
+ assert_s(zstr(a, buf), "18446744073709551616");
+ zadd(a, a, _1);
+ assert_s(zstr(a, buf), "18446744073709551617");
+
+ zsets(a, "1000000000000000000000000000000");
+ assert_s(zstr(a, buf), "1000000000000000000000000000000");
+ zsets(a, "+1000000000000000000000000000000");
+ assert_s(zstr(a, buf), "1000000000000000000000000000000");
+ zsets(a, "-1000000000000000000000000000000");
+ assert_s(zstr(a, buf), "-1000000000000000000000000000000");
+
+ zsetu(a, 1000000000000000ULL);
+ zsqr(a, a);
+ assert_s(zstr(a, buf), "1000000000000000000000000000000");
+
done:
zfree(a), zfree(b), zfree(c), zfree(d), zfree(_0), zfree(_1), zfree(_2), zfree(_3);
zunsetup();
diff --git a/zahl.h b/zahl.h
@@ -25,6 +25,10 @@ enum zprimality { NONPRIME = 0, PROBABLY_PRIME, PRIME };
enum zranddev { FAST_RANDOM = 0, SECURE_RANDOM };
enum zranddist { QUASIUNIFORM = 0, UNIFORM };
+enum zerror {
+ ZERROR_ERRNO_SET = 0
+};
+
/* The parameters in the functions below are numbers a, b, c, ... */
@@ -128,6 +132,12 @@ int zsets(z_t, const char *); /* a := b */
size_t zstr_length(z_t, unsigned long long int);
+/* Error handling functions. */
+
+enum zerror zerror(const char **); /* Return the current error code, and unless a is 0, a description in *a. */
+void zperror(const char *); /* Identical to perror(3p) except it supports libzahl errors. */
+
+
/* Inline functions. */
static inline int zeven(z_t a) { return !a->sign || !(a->chars[0] & 1); } /* Is a even? */