From 76d0af5599554d11f104d582cdac8fbaa8569fcc Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Fri, 4 Mar 2016 23:50:00 +0100 Subject: Clean up, add zerror and zperror, fix bugs and add more tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/internals.h | 10 +++++++--- src/zadd.c | 4 ++-- src/zdivmod.c | 13 +++++-------- src/zerror.c | 19 +++++++++++++++++++ src/zload.c | 9 ++++----- src/zlsh.c | 30 ++++++++++++++++-------------- src/zmodpow.c | 14 ++++++-------- src/zmodpowu.c | 16 ++++++---------- src/zmul.c | 22 +++++++++++++--------- src/zor.c | 1 + src/zperror.c | 17 +++++++++++++++++ src/zpow.c | 9 +++------ src/zpowu.c | 6 ++---- src/zrand.c | 16 ++++++---------- src/zrsh.c | 14 +++++++++----- src/zsave.c | 3 +-- src/zset.c | 2 +- src/zsets.c | 34 +++++++++++++++++++++++++++++----- src/zsetup.c | 1 + src/zsqr.c | 12 ++++++++---- src/zstr.c | 25 ++++++++++++++----------- src/zsub.c | 2 +- src/ztrunc.c | 2 +- 23 files changed, 172 insertions(+), 109 deletions(-) create mode 100644 src/zerror.c create mode 100644 src/zperror.c (limited to 'src') diff --git a/src/internals.h b/src/internals.h index 5b1f9c3..9f276db 100644 --- 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 index 6ab3ae8..73e5b42 100644 --- 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 index 9340810..e145c27 100644 --- 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 new file mode 100644 index 0000000..c59b092 --- /dev/null +++ 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 index ff54afb..a77ae57 100644 --- 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 index b631c1a..2a76fbc 100644 --- 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 index 884e9ff..6cb50d2 100644 --- 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 index 8a94379..7fb2c3d 100644 --- 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 index f237bc9..53e19f5 100644 --- 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 index f594828..240024e 100644 --- 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 new file mode 100644 index 0000000..37bd5c7 --- /dev/null +++ b/src/zperror.c @@ -0,0 +1,17 @@ +/* See LICENSE file for copyright and license details. */ +#include "internals.h" + +#include + + +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 index c064f60..7388bde 100644 --- 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 index d83a7ac..f8e5897 100644 --- 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 index cb0b375..30dc61d 100644 --- 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 index c5a1a05..a7b886b 100644 --- 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 index bb788d3..9a171d6 100644 --- 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 index b67fe4a..f7fe52e 100644 --- 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 index 24cdd48..2b91864 100644 --- 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 index 8d1cc19..8b5221d 100644 --- 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 index a9cebd0..39f5591 100644 --- 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 index 1b89118..f7273ce 100644 --- 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 index 1e2fe79..8616542 100644 --- 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 index f86fb8e..c634707 100644 --- 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); -- cgit v1.2.3-70-g09d2