zsub.c - libzahl - big integer library
 (HTM) git clone git://git.suckless.org/libzahl
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       zsub.c (1941B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include "internals.h"
            3 
            4 
            5 static inline void
            6 zsub_impl(z_t a, z_t b, size_t n)
            7 {
            8         zahl_char_t carry = 0, tcarry;
            9         size_t i;
           10 
           11         for (i = 0; i < n; i++) {
           12                 tcarry = carry ? (a->chars[i] <= b->chars[i]) : (a->chars[i] < b->chars[i]);
           13                 a->chars[i] -= b->chars[i];
           14                 a->chars[i] -= carry;
           15                 carry = tcarry;
           16         }
           17 
           18         if (carry) {
           19                 while (!a->chars[i])
           20                         a->chars[i++] = ZAHL_CHAR_MAX;
           21                 if (a->chars[i] == 1)
           22                         a->used--;
           23                 else
           24                         a->chars[i] -= 1;
           25         }
           26 }
           27 
           28 static inline void
           29 libzahl_zsub_unsigned(z_t a, z_t b, z_t c)
           30 {
           31         int magcmp;
           32         size_t n;
           33 
           34         if (unlikely(zzero(b))) {
           35                 zabs(a, c);
           36                 zneg(a, a);
           37                 return;
           38         } else if (unlikely(zzero(c))) {
           39                 zabs(a, b);
           40                 return;
           41         }
           42 
           43         magcmp = zcmpmag(b, c);
           44         if (unlikely(magcmp <= 0)) {
           45                 if (unlikely(magcmp == 0)) {
           46                         SET_SIGNUM(a, 0);
           47                         return;
           48                 }
           49                 n = b->used;
           50                 if (a == b) {
           51                         zset(libzahl_tmp_sub, b);
           52                         SET(a, c);
           53                         zsub_impl(a, libzahl_tmp_sub, n);
           54                 } else {
           55                         SET(a, c);
           56                         zsub_impl(a, b, n);
           57                 }
           58         } else {
           59                 n = c->used;
           60                 if (unlikely(a == c)) {
           61                         zset(libzahl_tmp_sub, c);
           62                         SET(a, b);
           63                         zsub_impl(a, libzahl_tmp_sub, n);
           64                 } else {
           65                         SET(a, b);
           66                         zsub_impl(a, c, n);
           67                 }
           68         }
           69 
           70         SET_SIGNUM(a, magcmp);
           71 }
           72 
           73 void
           74 zsub_unsigned(z_t a, z_t b, z_t c)
           75 {
           76         libzahl_zsub_unsigned(a, b, c);
           77 }
           78 
           79 void
           80 zsub_nonnegative_assign(z_t a, z_t b)
           81 {
           82         if (unlikely(zzero(b)))
           83                 zabs(a, a);
           84         else if (unlikely(!zcmpmag(a, b)))
           85                 SET_SIGNUM(a, 0);
           86         else
           87                 zsub_impl(a, b, b->used);
           88 }
           89 
           90 void
           91 zsub_positive_assign(z_t a, z_t b)
           92 {
           93         zsub_impl(a, b, b->used);
           94 }
           95 
           96 void
           97 zsub(z_t a, z_t b, z_t c)
           98 {
           99         if (unlikely(zzero(b))) {
          100                 zneg(a, c);
          101         } else if (unlikely(zzero(c))) {
          102                 SET(a, b);
          103         } else if (unlikely(znegative(b))) {
          104                 if (znegative(c)) {
          105                         libzahl_zsub_unsigned(a, c, b);
          106                 } else {
          107                         zadd_unsigned(a, b, c);
          108                         SET_SIGNUM(a, -zsignum(a));
          109                 }
          110         } else if (znegative(c)) {
          111                 zadd_unsigned(a, b, c);
          112         } else {
          113                 libzahl_zsub_unsigned(a, b, c);
          114         }
          115 }