libzahl

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

commit a626bacf8e45af60727882250f9d3abeb15ff3cd
parent 851c70c8645fc73a7377996b27c79fa7948fe477
Author: Mattias Andrée <maandree@kth.se>
Date:   Wed,  2 Mar 2016 09:59:52 +0100

Add zsets and zstr

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

Diffstat:
Mman/zstr_length.3 | 2+-
Msrc/internals.h | 10+++++++++-
Asrc/zsets.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
Msrc/zsetup.c | 10+++++++++-
Asrc/zstr.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/zstr_length.c | 2+-
Msrc/zunsetup.c | 7++++++-
7 files changed, 134 insertions(+), 5 deletions(-)

diff --git a/man/zstr_length.3 b/man/zstr_length.3 @@ -10,7 +10,7 @@ size_t zstr_length(z_t \fIa\fP, unsigned long long int\fIradix\fP); .SH DESCRIPTION .B zstr_length calculates the number of digits required to -to represent the absolute value of +to represent .I a in the selected .IR radix . diff --git a/src/internals.h b/src/internals.h @@ -12,11 +12,19 @@ X(libzahl_tmp_cmp)\ X(libzahl_tmp_str_num)\ X(libzahl_tmp_str_mag)\ - X(libzahl_tmp_str_div) + X(libzahl_tmp_str_div)\ + X(libzahl_tmp_str_rem) + +#define LIST_CONSTS\ + X(libzahl_const_1e19, zsetu, 10000000000000000000ULL) /* The largest power of 10 < 2⁶⁴. */\ + X(libzahl_const_1e9, zsetu, 1000000000ULL) /* The largest power of 10 < 2³². */ #define X(x) extern z_t x; LIST_TEMPS #undef X +#define X(x, f, v) extern z_t x; +LIST_CONSTS +#undef X extern jmp_buf libzahl_jmp_buf; extern int libzahl_set_up; diff --git a/src/zsets.c b/src/zsets.c @@ -0,0 +1,47 @@ +/* See LICENSE file for copyright and license details. */ +#include "internals" + +#include <errno.h> + + +int +zsets(z_t a, const char *str) +{ + unsigned long long int temp = 0; + int neg = (*str == '-'); + const char *str_end; + + str += neg || (*str == '+'); + + if (!*str) { + errno = EINVAL; + return -1; + } + for (str_end = str; *str_end; str_end++) { + if (!isdigit(*str_end)) { + errno = EINVAL; + return -1; + } + } + + SET_SIGNUM(a, 0); + + switch ((str_end - str) % 19) { + while (*str) { +#define X(n)\ + temp *= 10, temp += *str++ & 15;\ + case n: + 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) +#undef X + zmul(a, a, libzahl_const_1e19); + zsetu(libzahl_tmp_str_num, temp); + zadd(a, a, libzahl_tmp_str_num); + temp = 0; + } + } + + if (neg) + SET_SIGNUM(a, -zsignum(a)); + return 0; +} diff --git a/src/zsetup.c b/src/zsetup.c @@ -4,6 +4,9 @@ #define X(x) z_t x; LIST_TEMPS #undef X +#define X(x, f, v) z_t x; +LIST_CONSTS +#undef X jmp_buf libzahl_jmp_buf; int libzahl_set_up = 0; @@ -16,8 +19,13 @@ zsetup(jmp_buf env) if (!libzahl_set_up) { libzahl_set_up = 1; -#define X(x) zinit(zahl_tmp_##x); +#define X(x)\ + zinit(x); LIST_TEMPS; #undef X +#define X(x, f, v)\ + zinit(x), f(x, v); + LIST_CONSTS; +#undef X } } diff --git a/src/zstr.c b/src/zstr.c @@ -0,0 +1,61 @@ +/* See LICENSE file for copyright and license details. */ +#include "internals" + +#define num libzahl_tmp_str_num +#define rem libzahl_tmp_str_rem + +/* All 9 you see here is derived from that 10⁹ is the largest + * power of than < 2³², and 32 is the number of bits in + * zahl_char_t. If zahl_char_t is chanced, the value 9, and + * the cast to unsigned long must be changed accordingly. */ + + +char * +zstr(z_t a, char *b) +{ + size_t n; + char overridden; + int neg; + + if (zzero(a)) { + if (!b) { + b = malloc(2); + if (!b) + FAILURE_JUMP(); + } + b[0] = '0'; + b[1] = 0; + return b; + } + + n = zstr_length(a, 10); + if (!b) { + b = malloc(n + 1); + if (!b) + FAILURE_JUMP(); + } + + neg = zsignum(a) < 0; + zabs(num, a); + n -= neg; + n = n > 9 ? (n - 9) : 0; + b[0] = '-'; + b += neg; + overridden = 0; + + for (;;) { + zdivmod(num, rem, num, libzahl_const_1e9); + if (!zzero(num)) { + sprintf(b + n, "%09lu", (unsigned long)(rem->chars[0])); + b[n + 9] = overridden; + overridden = b[n + (9 - 1)]; + n = n > 9 ? (n - 9) : 0; + } else { + n += sprintf(b + n, "%lu", (unsigned long)(rem->chars[0])); + b[n] = overridden; + break; + } + } + + return b - neg; +} diff --git a/src/zstr_length.c b/src/zstr_length.c @@ -24,5 +24,5 @@ zstr_length(z_t a, unsigned long long int radix) size_total += size_temp; zdiv(num, num, div); } - return size_total; + return size_total + (zsignum(a) < 0); } diff --git a/src/zunsetup.c b/src/zunsetup.c @@ -7,8 +7,13 @@ zunsetup(jmp_buf env) { if (libzahl_set_up) { libzahl_set_up = 0; -#define X(x) zfree(zahl_tmp_##x); +#define X(x)\ + zfree(x); LIST_TEMPS; #undef X +#define X(x, f, v)\ + zfree(x); + LIST_CONSTS; +#undef X } }