libzahl

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

commit 56680b5fa737dd7aa1cd7446cad62f5b1da2235c
parent 0e905d00aceaa79849c25d359d7b7a6ee79175d7
Author: Mattias Andrée <maandree@kth.se>
Date:   Thu,  3 Mar 2016 12:23:39 +0100

Add zdivmod

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

Diffstat:
Msrc/internals.h | 6+++++-
Asrc/zdivmod.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/src/internals.h b/src/internals.h @@ -23,7 +23,11 @@ X(libzahl_tmp_pow_b)\ X(libzahl_tmp_pow_c)\ X(libzahl_tmp_pow_d)\ - X(libzahl_tmp_modsqr) + X(libzahl_tmp_modsqr)\ + X(libzahl_tmp_divmod_a)\ + X(libzahl_tmp_divmod_b)\ + X(libzahl_tmp_divmod_d)\ + X(libzahl_tmp_divmod_e) #define LIST_CONSTS\ X(libzahl_const_1e19, zsetu, 10000000000000000000ULL) /* The largest power of 10 < 2⁶⁴. */\ diff --git a/src/zdivmod.c b/src/zdivmod.c @@ -0,0 +1,75 @@ +/* See LICENSE file for copyright and license details. */ +#include "internals" + +#define ta libzahl_tmp_divmod_a +#define tb libzahl_tmp_divmod_b +#define td libzahl_tmp_divmod_d +#define te libzahl_tmp_divmod_e + + +void +zdivmod(z_t a, z_t b, z_t c, z_t d) +{ + size_t c_bits, d_bits, shift; + int sign, cmpmag; + + sign = zsignum(c) * zsignum(d); + + if (!sign) { + if (zzero(c)) { + if (zzero(d)) { + errno = EDOM; /* Indeterminate form: 0 divided by 0 */ + FAILURE_JUMP(); + } else { + SET_SIGNUM(a, 0); + SET_SIGNUM(b, 0); + } + } else { + errno = EDOM; /* Undefined form: Division by 0 */ + FAILURE_JUMP(); + } + return; + } else if ((cmpmag = zcmpmag(c, d)) <= 0) { + if (cmpmag == 0) { + zseti(a, sign); + SET_SIGNUM(b, 0); + return; + } else if (sign < 0) { + zsub_unsigned(b, d, c); + } else if (b != c) { + zset(b, c); + } + SET_SIGNUM(b, 1); + SET_SIGNUM(a, 0); + return; + } + + c_bits = zbits(c); + d_bits = zbits(d); + + shift = c_bits - d_bits; + zlsh(td, d, shift); + SET_SIGNUM(td, 1); + if (zcmpmag(td, c) > 0) { + zrsh(td, td, 1); + shift -= 1; + } + + zsetu(te, 1); + zlsh(te, te, shift); + SET_SIGNUM(ta, 0); + zabs(tb, c); + + while (!zzero(te)) { + if (zcmpmag(td, tb) <= 0) { + zsub(tb, tb, td); + zor(ta, ta, te); + } + zrsh(te, te, 1); + zrsh(td, td, 1); + } + + zset(a, ta); + zset(b, tb); + SET_SIGNUM(a, sign); +}