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 }