libzahl

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

zdivmod.c (1979B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include "internals.h"
      3 
      4 #define ta          libzahl_tmp_divmod_a
      5 #define tb          libzahl_tmp_divmod_b
      6 #define td          libzahl_tmp_divmod_d
      7 #define tds_proper  libzahl_tmp_divmod_ds
      8 
      9 
     10 static inline void
     11 zdivmod_impl(z_t a, z_t b, z_t c, z_t d)
     12 {
     13 	size_t c_bits, d_bits, bit, i;
     14 	static z_t tds[BITS_PER_CHAR];
     15 
     16 	c_bits = zbits(c);
     17 	d_bits = zbits(d);
     18 
     19 	bit = c_bits - d_bits;
     20 	zlsh(td, d, bit);
     21 	SET_SIGNUM(td, 1);
     22 	if (zcmpmag(td, c) > 0) {
     23 		zrsh(td, td, 1);
     24 		bit -= 1;
     25 	}
     26 
     27 	SET_SIGNUM(ta, 0);
     28 	zabs(tb, c);
     29 
     30 	if (unlikely(bit <= BITS_PER_CHAR)) {
     31 		for (;;) {
     32 			if (zcmpmag(td, tb) <= 0) {
     33 				zsub_unsigned(tb, tb, td);
     34 				zbset(ta, ta, bit, 1);
     35 			}
     36 			if (!bit-- || zzero(tb))
     37 				goto done;
     38 			zrsh(td, td, 1);
     39 		}
     40 	} else {
     41 		for (i = 0; i < BITS_PER_CHAR; i++) {
     42 			zrsh(tds_proper[i], td, i);
     43 			tds[i]->used = tds_proper[i]->used;
     44 			tds[i]->sign = tds_proper[i]->sign;
     45 			tds[i]->chars = tds_proper[i]->chars;
     46 		}
     47 		for (;;) {
     48 			for (i = 0; i < BITS_PER_CHAR; i++) {
     49 				if (zcmpmag(tds[i], tb) <= 0) {
     50 					zsub_unsigned(tb, tb, tds[i]);
     51 					zbset(ta, ta, bit, 1);
     52 				}
     53 				if (!bit-- || zzero(tb))
     54 					goto done;
     55 			}
     56 			for (i = MIN(bit, BITS_PER_CHAR - 1) + 1; i--;)
     57 				zrsh_taint(tds[i], BITS_PER_CHAR);
     58 		}
     59 	}
     60 done:
     61 
     62 	zswap(a, ta);
     63 	zswap(b, tb);
     64 }
     65 
     66 
     67 void
     68 zdivmod(z_t a, z_t b, z_t c, z_t d)
     69 {
     70 	int c_sign, sign, cmpmag;
     71 
     72 	c_sign = zsignum(c);
     73 	sign = c_sign * zsignum(d);
     74 
     75 	if (unlikely(!sign)) {
     76 		if (check(!zzero(c))) {
     77 			libzahl_failure(-ZERROR_DIV_0);
     78 		} else if (check(zzero(d))) {
     79 			libzahl_failure(-ZERROR_0_DIV_0);
     80 		} else {
     81 			SET_SIGNUM(a, 0);
     82 			SET_SIGNUM(b, 0);
     83 		}
     84 		return;
     85 	} else if (cmpmag = zcmpmag(c, d), unlikely(cmpmag <= 0)) {
     86 		if (unlikely(cmpmag == 0)) {
     87 			zseti(a, sign);
     88 			SET_SIGNUM(b, 0);
     89 		} else {
     90 			SET(b, c);
     91 			SET_SIGNUM(a, 0);
     92 		}
     93 		return;
     94 	}
     95 
     96 	zdivmod_impl(a, b, c, d);
     97 	SET_SIGNUM(a, sign);
     98 	if (zsignum(b) > 0)
     99 		SET_SIGNUM(b, c_sign);
    100 }