blob: b3fdaf9fdca4e6d35a2058b73105e5fa28d2e2e5 [file] [log] [blame]
Gavin Howard3eb626f2018-02-14 13:54:35 -07001/*
Gavin Howardb5904bf2018-02-20 13:28:18 -07002 * *****************************************************************************
Gavin Howard3eb626f2018-02-14 13:54:35 -07003 *
Gavin Howardb5904bf2018-02-20 13:28:18 -07004 * Copyright 2018 Gavin D. Howard
Gavin Howard3eb626f2018-02-14 13:54:35 -07005 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 *
Gavin Howardb5904bf2018-02-20 13:28:18 -070017 * *****************************************************************************
Gavin Howard3eb626f2018-02-14 13:54:35 -070018 *
19 * Code for the number type.
20 *
21 */
22
23#include <assert.h>
24#include <stdbool.h>
25#include <string.h>
26
Gavin Howard8e2cc692018-02-15 17:39:14 -070027#include <math.h>
28
29#include <limits.h>
30
Gavin Howard29493062018-03-20 19:57:37 -060031#include <status.h>
Gavin Howard3ba6c8d2018-02-15 12:23:35 -070032#include <num.h>
Gavin Howardf507f232018-02-23 21:10:24 -070033#include <vector.h>
Gavin Howard29493062018-03-20 19:57:37 -060034#include <bc.h>
Gavin Howard3eb626f2018-02-14 13:54:35 -070035
Gavin Howardaa53f7c2018-03-23 13:22:36 -060036void bc_num_subArrays(BcDigit *n1, BcDigit *n2, size_t len) {
Gavin Howard3f68df72018-03-22 20:30:27 -060037
Gavin Howarde1e74942018-03-20 15:51:52 -060038 size_t i, j;
39
40 for (i = 0; i < len; ++i) {
41
Gavin Howardcfc5faa2018-03-20 18:22:42 -060042 n1[i] -= n2[i];
Gavin Howarde1e74942018-03-20 15:51:52 -060043
Gavin Howardcfc5faa2018-03-20 18:22:42 -060044 for (j = 0; n1[i + j] < 0;) {
Gavin Howard9c4358c2018-03-22 20:11:28 -060045 n1[i + j++] += 10;
Gavin Howardcfc5faa2018-03-20 18:22:42 -060046 n1[i + j] -= 1;
Gavin Howarde1e74942018-03-20 15:51:52 -060047 }
48 }
Gavin Howarde1e74942018-03-20 15:51:52 -060049}
50
Gavin Howard3f68df72018-03-22 20:30:27 -060051int bc_num_compare(BcDigit *n1, BcDigit *n2, size_t len, size_t *digits) {
52
Gavin Howard08bf5292018-03-20 14:59:33 -060053 size_t i, digs;
54 BcDigit c;
55
Gavin Howard2168fb82018-03-24 10:40:37 -060056 for (c = 0, digs = 0, i = len - 1; i < len; ++digs, --i) {
Gavin Howard2a064fd2018-03-20 15:56:12 -060057 if ((c = n1[i] - n2[i])) break;
Gavin Howard08bf5292018-03-20 14:59:33 -060058 }
59
60 if (digits) *digits = digs;
61
62 return c;
63}
64
Gavin Howard2a064fd2018-03-20 15:56:12 -060065int bc_num_cmp(BcNum *a, BcNum *b, size_t *digits) {
Gavin Howard4681d1b2018-03-05 19:49:33 -070066
Gavin Howard9c4358c2018-03-22 20:11:28 -060067 size_t i, min, a_int, b_int, diff;
Gavin Howard6b5f5bb2018-03-22 23:16:57 -060068 BcDigit *max_num, *min_num;
Gavin Howard4681d1b2018-03-05 19:49:33 -070069 bool a_max;
Gavin Howard08bf5292018-03-20 14:59:33 -060070 int cmp, neg;
Gavin Howard4681d1b2018-03-05 19:49:33 -070071
Gavin Howard08bf5292018-03-20 14:59:33 -060072 if (digits) *digits = 0;
Gavin Howard4681d1b2018-03-05 19:49:33 -070073
Gavin Howard9c4358c2018-03-22 20:11:28 -060074 if (!a) return !b ? 0 : !b->neg * -2 + 1;
75 else if (!b) return a->neg * -2 + 1;
Gavin Howard4681d1b2018-03-05 19:49:33 -070076
Gavin Howard08bf5292018-03-20 14:59:33 -060077 neg = 1;
Gavin Howard4681d1b2018-03-05 19:49:33 -070078
Gavin Howard4e5ee2b2018-03-10 15:10:17 -070079 if (a->neg) {
Gavin Howard08bf5292018-03-20 14:59:33 -060080 if (b->neg) neg = -1;
Gavin Howard4681d1b2018-03-05 19:49:33 -070081 else return -1;
82 }
Gavin Howard4e5ee2b2018-03-10 15:10:17 -070083 else if (b->neg) return 1;
Gavin Howard4681d1b2018-03-05 19:49:33 -070084
Gavin Howard9c4358c2018-03-22 20:11:28 -060085 if (!a->len) return (!b->neg * -2 + 1) * !!b->len;
86 else if (!b->len) return a->neg * -2 + 1;
Gavin Howard4681d1b2018-03-05 19:49:33 -070087
Gavin Howard4e5ee2b2018-03-10 15:10:17 -070088 a_int = a->len - a->rdx;
89 b_int = b->len - b->rdx;
Gavin Howard43ab9332018-03-20 15:02:48 -060090 a_int -= b_int;
Gavin Howard4681d1b2018-03-05 19:49:33 -070091
Gavin Howard43ab9332018-03-20 15:02:48 -060092 if (a_int) return a_int;
Gavin Howard4681d1b2018-03-05 19:49:33 -070093
Gavin Howard4e5ee2b2018-03-10 15:10:17 -070094 a_max = a->rdx > b->rdx;
Gavin Howard4681d1b2018-03-05 19:49:33 -070095
96 if (a_max) {
Gavin Howard4e5ee2b2018-03-10 15:10:17 -070097 min = b->rdx;
Gavin Howard4e5ee2b2018-03-10 15:10:17 -070098 diff = a->rdx - b->rdx;
Gavin Howard4e5ee2b2018-03-10 15:10:17 -070099 max_num = a->num + diff;
100 min_num = b->num;
Gavin Howard4681d1b2018-03-05 19:49:33 -0700101 }
102 else {
Gavin Howard4e5ee2b2018-03-10 15:10:17 -0700103 min = a->rdx;
Gavin Howard4e5ee2b2018-03-10 15:10:17 -0700104 diff = b->rdx - a->rdx;
Gavin Howard4e5ee2b2018-03-10 15:10:17 -0700105 max_num = b->num + diff;
106 min_num = a->num;
Gavin Howard4681d1b2018-03-05 19:49:33 -0700107 }
108
Gavin Howard2a064fd2018-03-20 15:56:12 -0600109 cmp = bc_num_compare(max_num, min_num, b_int + min, digits);
Gavin Howard4681d1b2018-03-05 19:49:33 -0700110
Gavin Howard2ba07112018-03-20 15:40:58 -0600111 if (cmp) return cmp * (!a_max * -2 + 1) * neg;
Gavin Howard021150b2018-03-10 15:40:42 -0700112
Gavin Howard08bf5292018-03-20 14:59:33 -0600113 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard86f32e92018-03-20 19:21:12 -0600114 if (max_num[i]) return neg * (!a_max * -2 + 1);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700115 }
116
117 return 0;
118}
119
Gavin Howardd9734e52018-03-29 15:54:41 -0600120void bc_num_truncate(BcNum *n, size_t places) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700121
Gavin Howard021150b2018-03-10 15:40:42 -0700122 BcDigit *ptr;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700123
Gavin Howard27fdfb92018-03-21 07:56:59 -0600124 assert(places <= n->rdx);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700125
Gavin Howardd9734e52018-03-29 15:54:41 -0600126 if (!places) return;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700127
128 ptr = n->num + places;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700129 n->len -= places;
130 n->rdx -= places;
131
Gavin Howard021150b2018-03-10 15:40:42 -0700132 memmove(n->num, ptr, n->len * sizeof(BcDigit));
Gavin Howard021150b2018-03-10 15:40:42 -0700133 memset(n->num + n->len, 0, sizeof(BcDigit) * (n->cap - n->len));
Gavin Howard6fbdb292018-02-27 15:44:48 -0700134}
135
Gavin Howard3f68df72018-03-22 20:30:27 -0600136BcStatus bc_num_extend(BcNum *n, size_t places) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700137
138 BcStatus status;
Gavin Howard021150b2018-03-10 15:40:42 -0700139 BcDigit *ptr;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700140 size_t len;
141
Gavin Howard9c4358c2018-03-22 20:11:28 -0600142 if (!places) return BC_STATUS_SUCCESS;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700143
144 len = n->len + places;
145
Gavin Howard9c4358c2018-03-22 20:11:28 -0600146 if (n->cap < len && (status = bc_num_expand(n, len))) return status;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700147
148 ptr = n->num + places;
149
Gavin Howard021150b2018-03-10 15:40:42 -0700150 memmove(ptr, n->num, sizeof(BcDigit) * n->len);
Gavin Howard021150b2018-03-10 15:40:42 -0700151 memset(n->num, 0, sizeof(BcDigit) * places);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700152
153 n->len += places;
Gavin Howardcde142c2018-02-28 17:33:44 -0700154 n->rdx += places;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700155
156 return BC_STATUS_SUCCESS;
157}
158
Gavin Howard9c4358c2018-03-22 20:11:28 -0600159BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale) {
160
161 BcStatus status;
162 BcNum one;
163
164 if ((status = bc_num_init(&one, BC_NUM_DEF_SIZE))) return status;
165
166 bc_num_one(&one);
167 status = bc_num_div(&one, a, b, scale);
168 bc_num_free(&one);
169
170 return status;
171}
172
Gavin Howard3f68df72018-03-22 20:30:27 -0600173BcStatus bc_num_alg_a(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700174
Gavin Howard6b5f5bb2018-03-22 23:16:57 -0600175 BcDigit *ptr, *ptr_a, *ptr_b, *ptr_c;
Gavin Howard647a8802018-03-22 09:42:46 -0600176 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
Gavin Howard021150b2018-03-10 15:40:42 -0700177 BcDigit carry;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700178
179 (void) scale;
180
Gavin Howardf6964a12018-03-14 10:52:31 -0600181 if (!a->len) return bc_num_copy(c, b);
182 else if (!b->len) return bc_num_copy(c, a);
183
Gavin Howard6fbdb292018-02-27 15:44:48 -0700184 c->neg = a->neg;
185
Gavin Howard021150b2018-03-10 15:40:42 -0700186 memset(c->num, 0, c->cap * sizeof(BcDigit));
Gavin Howard6fbdb292018-02-27 15:44:48 -0700187
188 c->rdx = BC_MAX(a->rdx, b->rdx);
Gavin Howard647a8802018-03-22 09:42:46 -0600189 min_rdx = BC_MIN(a->rdx, b->rdx);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700190
191 c->len = 0;
192
193 if (a->rdx > b->rdx) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700194 diff = a->rdx - b->rdx;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700195 ptr = a->num;
196 ptr_a = a->num + diff;
197 ptr_b = b->num;
198 }
199 else {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700200 diff = b->rdx - a->rdx;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700201 ptr = b->num;
202 ptr_a = a->num;
203 ptr_b = b->num + diff;
204 }
205
Gavin Howard647a8802018-03-22 09:42:46 -0600206 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
Gavin Howard6fbdb292018-02-27 15:44:48 -0700207
208 ptr_c += diff;
209
Gavin Howard647a8802018-03-22 09:42:46 -0600210 a_int = a->len - a->rdx;
211 b_int = b->len - b->rdx;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700212
Gavin Howard647a8802018-03-22 09:42:46 -0600213 if (a_int > b_int) {
214 min_int = b_int;
215 max = a_int;
216 ptr = ptr_a;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700217 }
Gavin Howard647a8802018-03-22 09:42:46 -0600218 else {
219 min_int = a_int;
220 max = b_int;
221 ptr = ptr_b;
222 }
Gavin Howard6fbdb292018-02-27 15:44:48 -0700223
Gavin Howard647a8802018-03-22 09:42:46 -0600224 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700225 ptr_c[i] = ptr_a[i] + ptr_b[i] + carry;
Gavin Howard647a8802018-03-22 09:42:46 -0600226 carry = ptr_c[i] / 10;
227 ptr_c[i] %= 10;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700228 }
229
Gavin Howardb29674f2018-03-22 22:24:58 -0600230 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700231 ptr_c[i] += ptr[i] + carry;
Gavin Howard647a8802018-03-22 09:42:46 -0600232 carry = ptr_c[i] / 10;
233 ptr_c[i] %= 10;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700234 }
235
Gavin Howard647a8802018-03-22 09:42:46 -0600236 if (carry) c->num[c->len++] = carry;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700237
238 return BC_STATUS_SUCCESS;
239}
240
Gavin Howard3f68df72018-03-22 20:30:27 -0600241BcStatus bc_num_alg_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700242
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700243 BcStatus status;
244 int cmp;
Gavin Howard6b5f5bb2018-03-22 23:16:57 -0600245 BcNum *minuend, *subtrahend;
Gavin Howard2de93992018-03-20 15:58:13 -0600246 size_t start;
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700247 bool aneg, bneg, neg;
Gavin Howarda1c090a2018-03-05 14:20:33 -0700248
249 // Because this function doesn't need to use scale (per the bc spec),
250 // I am hijacking it to tell this function whether it is doing an add
251 // or a subtract.
Gavin Howard6fbdb292018-02-27 15:44:48 -0700252
Gavin Howardeb9a8222018-03-13 09:25:56 -0600253 if (!a->len) {
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700254 status = bc_num_copy(c, b);
255 c->neg = !b->neg;
256 return status;
257 }
Gavin Howardeb9a8222018-03-13 09:25:56 -0600258 else if (!b->len) return bc_num_copy(c, a);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700259
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700260 aneg = a->neg;
261 bneg = b->neg;
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700262 a->neg = b->neg = false;
263
Gavin Howard2a064fd2018-03-20 15:56:12 -0600264 cmp = bc_num_cmp(a, b, NULL);
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700265
266 a->neg = aneg;
267 b->neg = bneg;
268
269 if (!cmp) {
270 bc_num_zero(c);
271 return BC_STATUS_SUCCESS;
272 }
273 else if (cmp > 0) {
Gavin Howard8694e132018-03-14 13:43:28 -0600274 neg = sub && a->neg;
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700275 minuend = a;
276 subtrahend = b;
277 }
278 else {
Gavin Howard8694e132018-03-14 13:43:28 -0600279 neg = sub && !b->neg;
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700280 minuend = b;
281 subtrahend = a;
282 }
283
Gavin Howard9c4358c2018-03-22 20:11:28 -0600284 if ((status = bc_num_copy(c, minuend))) return status;
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700285
286 c->neg = neg;
287
288 if (c->rdx < subtrahend->rdx) {
Gavin Howard9c4358c2018-03-22 20:11:28 -0600289 if ((status = bc_num_extend(c, subtrahend->rdx - c->rdx))) return status;
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700290 start = 0;
291 }
Gavin Howardd9f5c8e2018-03-10 14:08:13 -0700292 else start = c->rdx - subtrahend->rdx;
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700293
Gavin Howardaa53f7c2018-03-23 13:22:36 -0600294 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700295
Gavin Howard9a6f7a42018-03-05 14:07:06 -0700296 while (c->len > c->rdx && !c->num[c->len - 1]) --c->len;
297
298 return status;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700299}
300
Gavin Howard3f68df72018-03-22 20:30:27 -0600301BcStatus bc_num_alg_m(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700302
303 BcStatus status;
Gavin Howard021150b2018-03-10 15:40:42 -0700304 BcDigit carry;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600305 size_t i, j, len;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700306
Gavin Howardeb9a8222018-03-13 09:25:56 -0600307 if (!a->len || !b->len) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700308 bc_num_zero(c);
309 return BC_STATUS_SUCCESS;
310 }
Gavin Howardb11bc8a2018-03-01 17:23:00 -0700311 else if (BC_NUM_ONE(a)) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700312 status = bc_num_copy(c, b);
313 if (a->neg) c->neg = !c->neg;
314 return status;
315 }
Gavin Howardb11bc8a2018-03-01 17:23:00 -0700316 else if (BC_NUM_ONE(b)) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700317 status = bc_num_copy(c, a);
318 if (b->neg) c->neg = !c->neg;
319 return status;
320 }
321
322 scale = BC_MAX(scale, a->rdx);
323 scale = BC_MAX(scale, b->rdx);
324 c->rdx = a->rdx + b->rdx;
325
Gavin Howard021150b2018-03-10 15:40:42 -0700326 memset(c->num, 0, sizeof(BcDigit) * c->cap);
Gavin Howard9c4358c2018-03-22 20:11:28 -0600327 c->len = carry = len = 0;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700328
329 for (i = 0; i < b->len; ++i) {
330
331 for (j = 0; j < a->len; ++j) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700332 c->num[i + j] += a->num[j] * b->num[i] + carry;
Gavin Howard5f806ee2018-03-03 23:30:31 -0700333 carry = c->num[i + j] / 10;
334 c->num[i + j] %= 10;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700335 }
336
337 if (carry) {
338 c->num[i + j] += carry;
339 carry = 0;
340 len = BC_MAX(len, i + j + 1);
341 }
342 else len = BC_MAX(len, i + j);
343 }
344
345 c->len = BC_MAX(len, c->rdx);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700346 c->neg = !a->neg != !b->neg;
347
Gavin Howard27fdfb92018-03-21 07:56:59 -0600348 if (scale < c->rdx) status = bc_num_truncate(c, c->rdx - scale);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700349 else status = BC_STATUS_SUCCESS;
350
Gavin Howardd2e917d2018-02-28 16:03:10 -0700351 while (c->len > c->rdx && !c->num[c->len - 1]) --c->len;
352
Gavin Howard6fbdb292018-02-27 15:44:48 -0700353 return status;
354}
355
Gavin Howard3f68df72018-03-22 20:30:27 -0600356BcStatus bc_num_alg_d(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700357
358 BcStatus status;
Gavin Howard6b5f5bb2018-03-22 23:16:57 -0600359 BcDigit *ptr, *bptr, q;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600360 size_t len, end, i;
Gavin Howardb651f1a2018-02-28 17:34:18 -0700361 BcNum copy;
Gavin Howard5b24c3f2018-03-13 23:57:15 -0600362 bool zero;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700363
Gavin Howardeb9a8222018-03-13 09:25:56 -0600364 if (!b->len) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
365 else if (!a->len) {
Gavin Howardb651f1a2018-02-28 17:34:18 -0700366 bc_num_zero(c);
367 return BC_STATUS_SUCCESS;
368 }
Gavin Howardb11bc8a2018-03-01 17:23:00 -0700369 else if (BC_NUM_ONE(b)) {
Gavin Howardae6e7d52018-03-14 10:13:43 -0600370
Gavin Howard9c4358c2018-03-22 20:11:28 -0600371 if ((status = bc_num_copy(c, a))) return status;
Gavin Howardae6e7d52018-03-14 10:13:43 -0600372
Gavin Howardb651f1a2018-02-28 17:34:18 -0700373 if (b->neg) c->neg = !c->neg;
Gavin Howardae6e7d52018-03-14 10:13:43 -0600374
375 if (c->rdx < scale) status = bc_num_extend(c, scale - c->rdx);
Gavin Howard27fdfb92018-03-21 07:56:59 -0600376 else status = bc_num_truncate(c, c->rdx - scale);
Gavin Howardae6e7d52018-03-14 10:13:43 -0600377
Gavin Howardb651f1a2018-02-28 17:34:18 -0700378 return status;
379 }
380
Gavin Howard9c4358c2018-03-22 20:11:28 -0600381 if ((status = bc_num_init(&copy, a->len + b->rdx + scale + 1))) return status;
382 if ((status = bc_num_copy(&copy, a))) goto err;
Gavin Howardb651f1a2018-02-28 17:34:18 -0700383
Gavin Howard021150b2018-03-10 15:40:42 -0700384 len = b->len;
385
386 if (len > copy.len) {
Gavin Howard9c4358c2018-03-22 20:11:28 -0600387 if ((status = bc_num_expand(&copy, len + 2))) goto err;
388 if ((status = bc_num_extend(&copy, len - copy.len))) goto err;
Gavin Howard021150b2018-03-10 15:40:42 -0700389 }
390
Gavin Howard9c4358c2018-03-22 20:11:28 -0600391 if (b->rdx > copy.rdx && (status = bc_num_extend(&copy, b->rdx - copy.rdx)))
392 goto err;
Gavin Howardb651f1a2018-02-28 17:34:18 -0700393
394 copy.rdx -= b->rdx;
395
Gavin Howard9c4358c2018-03-22 20:11:28 -0600396 if (scale > copy.rdx && (status = bc_num_extend(&copy, scale - copy.rdx)))
397 goto err;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700398
Gavin Howardc1a6a342018-03-05 12:10:14 -0700399 if (b->rdx == b->len) {
400
Gavin Howard9c4358c2018-03-22 20:11:28 -0600401 bool zero = true;
Gavin Howardc1a6a342018-03-05 12:10:14 -0700402
Gavin Howard9c4358c2018-03-22 20:11:28 -0600403 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
Gavin Howardc1a6a342018-03-05 12:10:14 -0700404
405 if (i == len) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
406
407 len -= i - 1;
408 }
409
410 if (copy.cap == copy.len) {
411 status = bc_num_expand(&copy, copy.len + 1);
Gavin Howardb651f1a2018-02-28 17:34:18 -0700412 if (status) goto err;
413 }
414
Gavin Howardb651f1a2018-02-28 17:34:18 -0700415 // We want an extra zero in front to make things simpler.
Gavin Howard9c4358c2018-03-22 20:11:28 -0600416 copy.num[copy.len++] = 0;
Gavin Howardac7656d2018-03-01 17:18:40 -0700417 end = copy.len - len;
418
Gavin Howard9c4358c2018-03-22 20:11:28 -0600419 if ((status = bc_num_expand(c, copy.len))) goto err;
Gavin Howardac7656d2018-03-01 17:18:40 -0700420
Gavin Howardb651f1a2018-02-28 17:34:18 -0700421 bc_num_zero(c);
422 c->rdx = copy.rdx;
423 c->len = copy.len;
Gavin Howard021150b2018-03-10 15:40:42 -0700424 bptr = b->num;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700425
426 for (i = end - 1; i < end; --i) {
427
Gavin Howard021150b2018-03-10 15:40:42 -0700428 ptr = copy.num + i;
Gavin Howardb651f1a2018-02-28 17:34:18 -0700429
Gavin Howard9c4358c2018-03-22 20:11:28 -0600430 for (q = 0; ptr[len] || bc_num_compare(ptr, bptr, len, NULL) >= 0; ++q)
Gavin Howardaa53f7c2018-03-23 13:22:36 -0600431 bc_num_subArrays(ptr, bptr, len);
Gavin Howardb651f1a2018-02-28 17:34:18 -0700432
Gavin Howard9c4358c2018-03-22 20:11:28 -0600433 c->num[i] = q;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700434 }
435
Gavin Howardac7656d2018-03-01 17:18:40 -0700436 c->neg = !a->neg != !b->neg;
437
Gavin Howardb651f1a2018-02-28 17:34:18 -0700438 while (c->len > c->rdx && !c->num[c->len - 1]) --c->len;
439
Gavin Howard27fdfb92018-03-21 07:56:59 -0600440 if (c->rdx > scale) status = bc_num_truncate(c, c->rdx - scale);
Gavin Howardb651f1a2018-02-28 17:34:18 -0700441
Gavin Howard5b24c3f2018-03-13 23:57:15 -0600442 for (i = 0, zero = true; zero && i < c->len; ++i) zero = !c->num[i];
443 if (zero) bc_num_zero(c);
444
Gavin Howardb651f1a2018-02-28 17:34:18 -0700445err:
446
447 bc_num_free(&copy);
448
Gavin Howard6fbdb292018-02-27 15:44:48 -0700449 return status;
450}
451
Gavin Howard3f68df72018-03-22 20:30:27 -0600452BcStatus bc_num_alg_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700453
454 BcStatus status;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600455 BcNum c1, c2;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700456 size_t len;
457
Gavin Howard8b254872018-03-14 01:13:35 -0600458 if (!b->len) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
459
460 if (!a->len) {
461 bc_num_zero(c);
462 return BC_STATUS_SUCCESS;
463 }
464
Gavin Howard6fbdb292018-02-27 15:44:48 -0700465 len = a->len + b->len + scale;
466
Gavin Howard9c4358c2018-03-22 20:11:28 -0600467 if ((status = bc_num_init(&c1, len))) return status;
468 if ((status = bc_num_init(&c2, len))) goto c2_err;
469 if ((status = bc_num_div(a, b, &c1, scale))) goto err;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700470
471 c->rdx = BC_MAX(scale + b->rdx, a->rdx);
472
Gavin Howard9c4358c2018-03-22 20:11:28 -0600473 if ((status = bc_num_mul(&c1, b, &c2, scale))) goto err;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700474
475 status = bc_num_sub(a, &c2, c, scale);
476
477err:
478
479 bc_num_free(&c2);
480
481c2_err:
482
483 bc_num_free(&c1);
484
485 return status;
486}
487
Gavin Howard3f68df72018-03-22 20:30:27 -0600488BcStatus bc_num_alg_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700489
490 BcStatus status;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700491 BcNum copy;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600492 unsigned long pow;
493 size_t i, powrdx, resrdx;
494 bool neg, zero;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700495
Gavin Howard23958582018-03-03 09:30:20 -0700496 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700497
Gavin Howard9c4358c2018-03-22 20:11:28 -0600498 if (!b->len) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700499 bc_num_one(c);
500 return BC_STATUS_SUCCESS;
501 }
Gavin Howardeb9a8222018-03-13 09:25:56 -0600502 else if (!a->len) {
Gavin Howard1d959152018-03-03 23:33:13 -0700503 bc_num_zero(c);
504 return BC_STATUS_SUCCESS;
505 }
Gavin Howard9c4358c2018-03-22 20:11:28 -0600506 else if (BC_NUM_ONE(b)) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700507
Gavin Howard9c4358c2018-03-22 20:11:28 -0600508 if (!b->neg) status = bc_num_copy(c, a);
509 else status = bc_num_inv(a, c, scale);
Gavin Howard5fc40e72018-03-05 12:11:09 -0700510
511 return status;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700512 }
Gavin Howard6fbdb292018-02-27 15:44:48 -0700513
Gavin Howard9c4358c2018-03-22 20:11:28 -0600514 neg = b->neg;
515 b->neg = false;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700516
Gavin Howard9c4358c2018-03-22 20:11:28 -0600517 if ((status = bc_num_ulong(b, &pow))) return status;
518 if ((status = bc_num_init(&copy, a->len))) return status;
519 if ((status = bc_num_copy(&copy, a))) goto err;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700520
Gavin Howardb29674f2018-03-22 22:24:58 -0600521 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
522
523 b->neg = neg;
524
Gavin Howard9c4358c2018-03-22 20:11:28 -0600525 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard1d959152018-03-03 23:33:13 -0700526 powrdx <<= 1;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600527 if ((status = bc_num_mul(&copy, &copy, &copy, powrdx))) goto err;
Gavin Howard1d959152018-03-03 23:33:13 -0700528 }
Gavin Howard6fb635f2018-03-03 12:45:42 -0700529
Gavin Howard9c4358c2018-03-22 20:11:28 -0600530 if ((status = bc_num_copy(c, &copy))) goto err;
Gavin Howard6fb635f2018-03-03 12:45:42 -0700531
Gavin Howard1d959152018-03-03 23:33:13 -0700532 resrdx = powrdx;
Gavin Howard6fb635f2018-03-03 12:45:42 -0700533
Gavin Howard9c4358c2018-03-22 20:11:28 -0600534 for (pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard1d959152018-03-03 23:33:13 -0700535
536 powrdx <<= 1;
537
Gavin Howard9c4358c2018-03-22 20:11:28 -0600538 if ((status = bc_num_mul(&copy, &copy, &copy, powrdx))) goto err;
Gavin Howard1d959152018-03-03 23:33:13 -0700539
Gavin Howard9c4358c2018-03-22 20:11:28 -0600540 if (pow & 1) {
Gavin Howard1d959152018-03-03 23:33:13 -0700541 resrdx += powrdx;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600542 if ((status = bc_num_mul(c, &copy, c, resrdx))) goto err;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700543 }
Gavin Howard6fbdb292018-02-27 15:44:48 -0700544 }
545
Gavin Howardb29674f2018-03-22 22:24:58 -0600546 if (neg && (status = bc_num_inv(c, c, scale))) goto err;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700547
Gavin Howard9c4358c2018-03-22 20:11:28 -0600548 if (c->rdx > scale && (status = bc_num_truncate(c, c->rdx - scale))) goto err;
Gavin Howard1d959152018-03-03 23:33:13 -0700549
Gavin Howardb29674f2018-03-22 22:24:58 -0600550 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
Gavin Howard1d959152018-03-03 23:33:13 -0700551 if (zero) bc_num_zero(c);
552
Gavin Howard6fbdb292018-02-27 15:44:48 -0700553err:
554
Gavin Howard1d959152018-03-03 23:33:13 -0700555 bc_num_free(&copy);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700556
557 return status;
558}
559
Gavin Howard3f68df72018-03-22 20:30:27 -0600560BcStatus bc_num_sqrt_newton(BcNum *a, BcNum *b, size_t scale) {
Gavin Howard62f8c912018-03-02 10:45:50 -0700561
562 BcStatus status;
Gavin Howard6b5f5bb2018-03-22 23:16:57 -0600563 BcNum num1, num2, two, f, fprime, *x0, *x1, *temp;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600564 size_t pow, len, digits, resrdx;
Gavin Howardfa485732018-03-05 19:51:03 -0700565 int cmp;
Gavin Howard62f8c912018-03-02 10:45:50 -0700566
Gavin Howardeb9a8222018-03-13 09:25:56 -0600567 if (!a->len) {
Gavin Howard62e52ed2018-03-05 14:48:26 -0700568 bc_num_zero(b);
569 return BC_STATUS_SUCCESS;
570 }
Gavin Howard98e44ce2018-03-20 18:11:52 -0600571 else if (a->neg) return BC_STATUS_MATH_NEG_SQRT;
572 else if (BC_NUM_ONE(a)) {
Gavin Howard62e52ed2018-03-05 14:48:26 -0700573 bc_num_one(b);
574 return bc_num_extend(b, scale);
575 }
Gavin Howard62e52ed2018-03-05 14:48:26 -0700576
Gavin Howard021150b2018-03-10 15:40:42 -0700577 memset(b->num, 0, b->cap * sizeof(BcDigit));
Gavin Howard9c4358c2018-03-22 20:11:28 -0600578 len = a->len;
Gavin Howard62e52ed2018-03-05 14:48:26 -0700579
Gavin Howard62f8c912018-03-02 10:45:50 -0700580 scale = BC_MAX(scale, a->rdx) + 1;
581
Gavin Howard9c4358c2018-03-22 20:11:28 -0600582 if ((status = bc_num_init(&num1, len))) return status;
583 if ((status = bc_num_init(&num2, num1.len))) goto num2_err;
584 if ((status = bc_num_init(&two, BC_NUM_DEF_SIZE))) goto two_err;
Gavin Howard62f8c912018-03-02 10:45:50 -0700585
586 bc_num_one(&two);
587 two.num[0] = 2;
588
589 len += scale;
590
Gavin Howard9c4358c2018-03-22 20:11:28 -0600591 if ((status = bc_num_init(&f, len))) goto f_err;
592 if ((status = bc_num_init(&fprime, len + scale))) goto fprime_err;
Gavin Howard62f8c912018-03-02 10:45:50 -0700593
594 x0 = &num1;
595 x1 = &num2;
596
597 bc_num_one(x0);
598
599 pow = a->len - a->rdx;
600
Gavin Howardfa485732018-03-05 19:51:03 -0700601 if (pow) {
602
603 if (pow & 1) {
604 x0->num[0] = 2;
605 pow -= 1;
606 }
607 else {
608 x0->num[0] = 6;
609 pow -= 2;
610 }
611
Gavin Howard9c4358c2018-03-22 20:11:28 -0600612 if ((status = bc_num_extend(x0, pow))) goto err;
Gavin Howard62f8c912018-03-02 10:45:50 -0700613 }
614
Gavin Howardfa485732018-03-05 19:51:03 -0700615 cmp = 1;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600616 x0->rdx = digits = 0;
Gavin Howardfa485732018-03-05 19:51:03 -0700617 resrdx = scale + 1;
618 len = (x0->len - x0->rdx) + resrdx;
Gavin Howard62f8c912018-03-02 10:45:50 -0700619
Gavin Howardfa485732018-03-05 19:51:03 -0700620 while (cmp && digits <= len) {
Gavin Howard62f8c912018-03-02 10:45:50 -0700621
Gavin Howard9c4358c2018-03-22 20:11:28 -0600622 if ((status = bc_num_mul(x0, x0, &f, resrdx))) goto err;
623 if ((status = bc_num_sub(&f, a, &f, resrdx))) goto err;
624 if ((status = bc_num_mul(x0, &two, &fprime, resrdx))) goto err;
625 if ((status = bc_num_div(&f, &fprime, &f, resrdx))) goto err;
626 if ((status = bc_num_sub(x0, &f, x1, resrdx))) goto err;
Gavin Howard62f8c912018-03-02 10:45:50 -0700627
Gavin Howard2a064fd2018-03-20 15:56:12 -0600628 cmp = bc_num_cmp(x1, x0, &digits);
Gavin Howardfa485732018-03-05 19:51:03 -0700629
Gavin Howard62f8c912018-03-02 10:45:50 -0700630 temp = x0;
631 x0 = x1;
632 x1 = temp;
633 }
634
Gavin Howard9c4358c2018-03-22 20:11:28 -0600635 if ((status = bc_num_copy(b, x0))) goto err;
Gavin Howard62f8c912018-03-02 10:45:50 -0700636
Gavin Howard62e52ed2018-03-05 14:48:26 -0700637 --scale;
638
Gavin Howard27fdfb92018-03-21 07:56:59 -0600639 if (b->rdx > scale) status = bc_num_truncate(b, b->rdx - scale);
Gavin Howard62e52ed2018-03-05 14:48:26 -0700640 else if (b->rdx < scale) status = bc_num_extend(b, scale - b->rdx);
Gavin Howard62f8c912018-03-02 10:45:50 -0700641
642err:
643
644 bc_num_free(&fprime);
645
646fprime_err:
647
648 bc_num_free(&f);
649
650f_err:
651
652 bc_num_free(&two);
653
654two_err:
655
656 bc_num_free(&num2);
657
658num2_err:
659
660 bc_num_free(&num1);
661
662 return status;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700663}
664
Gavin Howard3f68df72018-03-22 20:30:27 -0600665BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
666 BcNumBinaryFunc op, size_t req)
Gavin Howard6fbdb292018-02-27 15:44:48 -0700667{
668 BcStatus status;
Gavin Howard6b5f5bb2018-03-22 23:16:57 -0600669 BcNum num2, *ptr_a, *ptr_b;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700670 bool init;
671
Gavin Howard27fdfb92018-03-21 07:56:59 -0600672 assert(a && b && c && op);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700673
674 init = false;
675
676 if (c == a) {
Gavin Howard1cc23f32018-02-28 16:09:33 -0700677 memcpy(&num2, c, sizeof(BcNum));
678 ptr_a = &num2;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700679 init = true;
680 }
681 else ptr_a = a;
682
683 if (c == b) {
684
685 if (c == a) {
686 ptr_b = ptr_a;
687 }
688 else {
Gavin Howard1cc23f32018-02-28 16:09:33 -0700689 memcpy(&num2, c, sizeof(BcNum));
690 ptr_b = &num2;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700691 init = true;
692 }
693 }
694 else ptr_b = b;
695
696 if (init) status = bc_num_init(c, req);
697 else status = bc_num_expand(c, req);
698
Gavin Howard9c4358c2018-03-22 20:11:28 -0600699 if (status) goto err;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700700
701 status = op(ptr_a, ptr_b, c, scale);
702
Gavin Howard9c4358c2018-03-22 20:11:28 -0600703err:
704
Gavin Howard1cc23f32018-02-28 16:09:33 -0700705 if (c == a || c == b) bc_num_free(&num2);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700706
707 return status;
708}
709
Gavin Howard3f68df72018-03-22 20:30:27 -0600710BcStatus bc_num_unary(BcNum *a, BcNum *b, size_t scale,
711 BcNumUnaryFunc op, size_t req)
Gavin Howard6fbdb292018-02-27 15:44:48 -0700712{
713 BcStatus status;
Gavin Howard6b5f5bb2018-03-22 23:16:57 -0600714 BcNum a2, *ptr_a;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700715
Gavin Howard27fdfb92018-03-21 07:56:59 -0600716 assert(a && b && op);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700717
718 if (b == a) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700719 memcpy(&a2, b, sizeof(BcNum));
720 ptr_a = &a2;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700721 status = bc_num_init(b, req);
722 }
723 else {
724 ptr_a = a;
725 status = bc_num_expand(b, req);
726 }
727
Gavin Howard9c4358c2018-03-22 20:11:28 -0600728 if (status) goto err;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700729
730 status = op(ptr_a, b, scale);
731
Gavin Howard9c4358c2018-03-22 20:11:28 -0600732err:
733
Gavin Howard6fbdb292018-02-27 15:44:48 -0700734 if (b == a) bc_num_free(&a2);
735
736 return status;
737}
738
Gavin Howard3f68df72018-03-22 20:30:27 -0600739bool bc_num_strValid(const char *val, size_t base) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700740
Gavin Howard9c4358c2018-03-22 20:11:28 -0600741 size_t len, i;
742 BcDigit c, b;
743 bool small, radix;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700744
745 radix = false;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700746 len = strlen(val);
747
748 if (!len) return true;
749
Gavin Howard9c4358c2018-03-22 20:11:28 -0600750 small = base <= 10;
751 b = small ? base + '0' : base - 9 + 'A';
Gavin Howard6fbdb292018-02-27 15:44:48 -0700752
Gavin Howard9c4358c2018-03-22 20:11:28 -0600753 for (i = 0; i < len; ++i) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700754
Gavin Howard9c4358c2018-03-22 20:11:28 -0600755 c = val[i];
Gavin Howard6fbdb292018-02-27 15:44:48 -0700756
Gavin Howard9c4358c2018-03-22 20:11:28 -0600757 if (c == '.') {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700758
Gavin Howard9c4358c2018-03-22 20:11:28 -0600759 if (radix) return false;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700760
Gavin Howard9c4358c2018-03-22 20:11:28 -0600761 radix = true;
762 continue;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700763 }
Gavin Howard6fbdb292018-02-27 15:44:48 -0700764
Gavin Howard9c4358c2018-03-22 20:11:28 -0600765 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
766 return false;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700767 }
768
769 return true;
770}
771
Gavin Howard3f68df72018-03-22 20:30:27 -0600772BcStatus bc_num_parseDecimal(BcNum *n, const char *val) {
Gavin Howard6fbdb292018-02-27 15:44:48 -0700773
774 BcStatus status;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600775 size_t len, i;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700776 const char *ptr;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600777 bool zero;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700778
779 for (i = 0; val[i] == '0'; ++i);
780
781 val += i;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700782 len = strlen(val);
783
784 bc_num_zero(n);
Gavin Howard9c4358c2018-03-22 20:11:28 -0600785 zero = true;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700786
787 if (len) {
Gavin Howard9c4358c2018-03-22 20:11:28 -0600788 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
789 if ((status = bc_num_expand(n, len))) return status;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700790 }
Gavin Howard9c4358c2018-03-22 20:11:28 -0600791
792 if (zero) {
Gavin Howard021150b2018-03-10 15:40:42 -0700793 memset(n->num, 0, sizeof(BcDigit) * n->cap);
Gavin Howard6fbdb292018-02-27 15:44:48 -0700794 n->neg = false;
795 return BC_STATUS_SUCCESS;
796 }
797
798 ptr = strchr(val, '.');
799
Gavin Howardb29674f2018-03-22 22:24:58 -0600800 // Explicitly test for NULL here to produce either a 0 or 1.
801 n->rdx = (ptr != NULL) * ((val + len) - (ptr + 1));
Gavin Howard6fbdb292018-02-27 15:44:48 -0700802
Gavin Howard595886d2018-03-28 19:57:37 -0600803 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
Gavin Howardb29674f2018-03-22 22:24:58 -0600804 n->num[n->len] = val[i] - '0';
Gavin Howard6fbdb292018-02-27 15:44:48 -0700805
806 return BC_STATUS_SUCCESS;
807}
808
Gavin Howard3f68df72018-03-22 20:30:27 -0600809BcStatus bc_num_parseBase(BcNum *n, const char *val, BcNum *base) {
Gavin Howardede51f02018-03-02 12:30:00 -0700810
811 BcStatus status;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600812 BcNum temp, mult, result;
813 size_t i, len, digits;
Gavin Howard021150b2018-03-10 15:40:42 -0700814 BcDigit c;
Gavin Howardede51f02018-03-02 12:30:00 -0700815 bool zero;
Gavin Howard5b24c3f2018-03-13 23:57:15 -0600816 unsigned long v;
Gavin Howardede51f02018-03-02 12:30:00 -0700817
818 len = strlen(val);
Gavin Howardb29674f2018-03-22 22:24:58 -0600819 bc_num_zero(n);
Gavin Howardede51f02018-03-02 12:30:00 -0700820
Gavin Howard9c4358c2018-03-22 20:11:28 -0600821 for (zero = true, i = 0; zero && i < len; ++i)
822 zero = (val[i] == '.' || val[i] == '0');
Gavin Howardede51f02018-03-02 12:30:00 -0700823
Gavin Howardb29674f2018-03-22 22:24:58 -0600824 if (zero) return BC_STATUS_SUCCESS;
Gavin Howardede51f02018-03-02 12:30:00 -0700825
Gavin Howard9c4358c2018-03-22 20:11:28 -0600826 if ((status = bc_num_init(&temp, BC_NUM_DEF_SIZE))) return status;
827 if ((status = bc_num_init(&mult, BC_NUM_DEF_SIZE))) goto mult_err;
Gavin Howardede51f02018-03-02 12:30:00 -0700828
Gavin Howardede51f02018-03-02 12:30:00 -0700829 for (i = 0; i < len && (c = val[i]) != '.'; ++i) {
830
Gavin Howard5b24c3f2018-03-13 23:57:15 -0600831 v = c <= '9' ? c - '0' : c - 'A' + 10;
Gavin Howardfcb6ebb2018-03-09 10:41:06 -0700832
Gavin Howard9c4358c2018-03-22 20:11:28 -0600833 if ((status = bc_num_mul(n, base, &mult, 0))) goto int_err;
834 if ((status = bc_num_ulong2num(&temp, v))) goto int_err;
835 if ((status = bc_num_add(&mult, &temp, n, 0))) goto int_err;
Gavin Howardede51f02018-03-02 12:30:00 -0700836 }
837
Gavin Howardb29674f2018-03-22 22:24:58 -0600838 if (i == len && !(c = val[i])) goto int_err;
Gavin Howardede51f02018-03-02 12:30:00 -0700839
840 assert(c == '.');
841
Gavin Howard9c4358c2018-03-22 20:11:28 -0600842 if ((status = bc_num_init(&result, base->len))) goto int_err;
Gavin Howardede51f02018-03-02 12:30:00 -0700843
Gavin Howardede51f02018-03-02 12:30:00 -0700844 bc_num_zero(&result);
845 bc_num_one(&mult);
846
Gavin Howardb29674f2018-03-22 22:24:58 -0600847 for (i += 1, digits = 0; i < len && (c = val[i]); ++i, ++digits) {
Gavin Howardede51f02018-03-02 12:30:00 -0700848
Gavin Howard5b24c3f2018-03-13 23:57:15 -0600849 v = c <= '9' ? c - '0' : c - 'A' + 10;
Gavin Howardede51f02018-03-02 12:30:00 -0700850
Gavin Howard9c4358c2018-03-22 20:11:28 -0600851 if ((status = bc_num_mul(&result, base, &result, 0))) goto err;
852 if ((status = bc_num_ulong2num(&temp, v))) goto err;
853 if ((status = bc_num_add(&result, &temp, &result, 0))) goto err;
854 if ((status = bc_num_mul(&mult, base, &mult, 0))) goto err;
Gavin Howardede51f02018-03-02 12:30:00 -0700855 }
856
Gavin Howard9c4358c2018-03-22 20:11:28 -0600857 if ((status = bc_num_div(&result, &mult, &result, digits))) goto err;
858 if ((status = bc_num_add(n, &result, n, digits))) goto err;
Gavin Howard5b24c3f2018-03-13 23:57:15 -0600859
860 if (n->len) {
Gavin Howard9c4358c2018-03-22 20:11:28 -0600861 if (n->rdx < digits && n->len) status = bc_num_extend(n, digits - n->rdx);
Gavin Howard5b24c3f2018-03-13 23:57:15 -0600862 }
863 else bc_num_zero(n);
Gavin Howardede51f02018-03-02 12:30:00 -0700864
865err:
866
867 bc_num_free(&result);
868
869int_err:
870
871 bc_num_free(&mult);
872
873mult_err:
874
875 bc_num_free(&temp);
876
877 return status;
Gavin Howard6fbdb292018-02-27 15:44:48 -0700878}
879
Gavin Howard3f68df72018-03-22 20:30:27 -0600880BcStatus bc_num_printDigits(unsigned long num, size_t width,
881 bool radix, size_t *nchars)
Gavin Howard2682a1f2018-03-03 09:09:13 -0700882{
Gavin Howard2ed2bfb2018-03-14 02:42:32 -0600883 size_t exp, pow, div;
884
885 if (*nchars == BC_NUM_PRINT_WIDTH - 1) {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600886 if (putchar('\\') == EOF) return BC_STATUS_IO_ERR;
887 if (putchar('\n') == EOF) return BC_STATUS_IO_ERR;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700888 *nchars = 0;
889 }
Gavin Howard2ed2bfb2018-03-14 02:42:32 -0600890
Gavin Howarda141a0f2018-03-23 13:16:10 -0600891 if (*nchars || radix) {
892 if (putchar(radix ? '.' : ' ') == EOF) return BC_STATUS_IO_ERR;
893 ++(*nchars);
894 }
Gavin Howard2ed2bfb2018-03-14 02:42:32 -0600895
896 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10);
897
Gavin Howarda141a0f2018-03-23 13:16:10 -0600898 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Gavin Howard2ed2bfb2018-03-14 02:42:32 -0600899
900 if (*nchars == BC_NUM_PRINT_WIDTH - 1) {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600901 if (putchar('\\') == EOF) return BC_STATUS_IO_ERR;
902 if (putchar('\n') == EOF) return BC_STATUS_IO_ERR;
Gavin Howard2ed2bfb2018-03-14 02:42:32 -0600903 *nchars = 0;
904 }
905
906 div = num / pow;
Gavin Howard2ed2bfb2018-03-14 02:42:32 -0600907 num -= div * pow;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600908
Gavin Howarda141a0f2018-03-23 13:16:10 -0600909 if (putchar(((char) div) + '0') == EOF) return BC_STATUS_IO_ERR;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700910 }
911
Gavin Howard6fbdb292018-02-27 15:44:48 -0700912 return BC_STATUS_SUCCESS;
913}
Gavin Howardfe679f02018-02-14 15:50:09 -0700914
Gavin Howard3f68df72018-03-22 20:30:27 -0600915BcStatus bc_num_printHex(unsigned long num, size_t width,
916 bool radix, size_t *nchars)
Gavin Howard2682a1f2018-03-03 09:09:13 -0700917{
Gavin Howard881645c2018-03-14 01:44:20 -0600918 width += !!radix;
919 if (*nchars + width >= BC_NUM_PRINT_WIDTH) {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600920 if (putchar('\\') == EOF) return BC_STATUS_IO_ERR;
921 if (putchar('\n') == EOF) return BC_STATUS_IO_ERR;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700922 *nchars = 0;
923 }
924
Gavin Howarda141a0f2018-03-23 13:16:10 -0600925 if (radix && putchar('.') == EOF) return BC_STATUS_IO_ERR;
926 if (putchar(bc_num_hex_digits[num]) == EOF) return BC_STATUS_IO_ERR;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700927
928 *nchars = *nchars + width;
929
930 return BC_STATUS_SUCCESS;
931}
932
Gavin Howard3f68df72018-03-22 20:30:27 -0600933BcStatus bc_num_printDecimal(BcNum *n, size_t *nchars) {
Gavin Howard32f2beb2018-03-09 11:43:20 -0700934
935 BcStatus status;
936 size_t i;
Gavin Howard32f2beb2018-03-09 11:43:20 -0700937
Gavin Howard32f2beb2018-03-09 11:43:20 -0700938 if (n->neg) {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600939 if (putchar('-') == EOF) return BC_STATUS_IO_ERR;
Gavin Howardbc7cae82018-03-14 13:43:04 -0600940 ++(*nchars);
Gavin Howard32f2beb2018-03-09 11:43:20 -0700941 }
942
943 status = BC_STATUS_SUCCESS;
944
Gavin Howard9c4358c2018-03-22 20:11:28 -0600945 for (i = n->len - 1; !status && i < n->len; --i)
946 status = bc_num_printHex(n->num[i], 1, i == n->rdx - 1, nchars);
Gavin Howard32f2beb2018-03-09 11:43:20 -0700947
948 return status;
949}
950
Gavin Howard3f68df72018-03-22 20:30:27 -0600951BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t, size_t *nchars)
Gavin Howardbc7cae82018-03-14 13:43:04 -0600952{
Gavin Howard2682a1f2018-03-03 09:09:13 -0700953 BcStatus status;
954 BcVec stack;
Gavin Howard9c4358c2018-03-22 20:11:28 -0600955 BcNum intp, fracp, digit, frac_len;
956 size_t width, i;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700957 BcNumDigitFunc print;
Gavin Howard6b5f5bb2018-03-22 23:16:57 -0600958 unsigned long dig, *ptr;
Gavin Howard53ed5bb2018-03-14 01:15:59 -0600959 bool neg, radix;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700960
Gavin Howard53ed5bb2018-03-14 01:15:59 -0600961 neg = n->neg;
962 n->neg = false;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700963
Gavin Howard53ed5bb2018-03-14 01:15:59 -0600964 if (neg) {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600965 if (putchar('-') == EOF) return BC_STATUS_IO_ERR;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700966 ++nchars;
967 }
968
Gavin Howardcb3ce022018-03-21 09:13:24 -0600969 if (base_t <= BC_NUM_MAX_INPUT_BASE) {
Gavin Howard2682a1f2018-03-03 09:09:13 -0700970 width = 1;
971 print = bc_num_printHex;
972 }
973 else {
974 width = (size_t) floor(log10((double) (base_t - 1)) + 1.0);
975 print = bc_num_printDigits;
976 }
977
Gavin Howard9c4358c2018-03-22 20:11:28 -0600978 if ((status = bc_vec_init(&stack, sizeof(long), NULL))) return status;
979 if ((status = bc_num_init(&intp, n->len))) goto int_err;
980 if ((status = bc_num_init(&fracp, n->rdx))) goto frac_err;
981 if ((status = bc_num_init(&digit, width))) goto digit_err;
982 if ((status = bc_num_copy(&intp, n))) goto frac_len_err;
983 if ((status = bc_num_truncate(&intp, intp.rdx))) goto frac_len_err;
984 if ((status = bc_num_sub(n, &intp, &fracp, 0))) goto frac_len_err;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700985
Gavin Howard53ed5bb2018-03-14 01:15:59 -0600986 while (intp.len) {
Gavin Howard9c4358c2018-03-22 20:11:28 -0600987 if ((status = bc_num_mod(&intp, base, &digit, 0))) goto frac_len_err;
988 if ((status = bc_num_ulong(&digit, &dig))) goto frac_len_err;
989 if ((status = bc_vec_push(&stack, &dig))) goto frac_len_err;
990 if ((status = bc_num_div(&intp, base, &intp, 0))) goto frac_len_err;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700991 }
992
993 for (i = 0; i < stack.len; ++i) {
Gavin Howard2682a1f2018-03-03 09:09:13 -0700994 ptr = bc_vec_item_rev(&stack, i);
Gavin Howard9c4358c2018-03-22 20:11:28 -0600995 assert(ptr);
996 if ((status = print(*ptr, width, false, nchars))) goto frac_len_err;
Gavin Howard2682a1f2018-03-03 09:09:13 -0700997 }
998
999 if (!n->rdx) goto frac_len_err;
1000
Gavin Howard9c4358c2018-03-22 20:11:28 -06001001 if ((status = bc_num_init(&frac_len, n->len - n->rdx))) goto frac_len_err;
Gavin Howard2682a1f2018-03-03 09:09:13 -07001002
1003 bc_num_one(&frac_len);
1004
Gavin Howard1819ecc2018-03-14 01:15:41 -06001005 for (radix = true; frac_len.len <= n->rdx; radix = false) {
Gavin Howard9c4358c2018-03-22 20:11:28 -06001006 if ((status = bc_num_mul(&fracp, base, &fracp, n->rdx))) goto err;
1007 if ((status = bc_num_ulong(&fracp, &dig))) goto err;
1008 if ((status = bc_num_ulong2num(&intp, dig))) goto err;
1009 if ((status = bc_num_sub(&fracp, &intp, &fracp, 0))) goto err;
1010 if ((status = print(dig, width, radix, nchars))) goto err;
1011 if ((status = bc_num_mul(&frac_len, base, &frac_len, 0))) goto err;
Gavin Howard2682a1f2018-03-03 09:09:13 -07001012 }
1013
1014err:
1015
Gavin Howard53ed5bb2018-03-14 01:15:59 -06001016 n->neg = neg;
1017
Gavin Howard2682a1f2018-03-03 09:09:13 -07001018 bc_num_free(&frac_len);
1019
1020frac_len_err:
1021
1022 bc_num_free(&digit);
1023
1024digit_err:
1025
1026 bc_num_free(&fracp);
1027
1028frac_err:
1029
1030 bc_num_free(&intp);
1031
1032int_err:
1033
1034 bc_vec_free(&stack);
1035
1036 return status;
1037}
1038
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001039BcStatus bc_num_init(BcNum *n, size_t request) {
Gavin Howardb5c77212018-02-14 17:12:34 -07001040
Gavin Howard27fdfb92018-03-21 07:56:59 -06001041 assert(n);
Gavin Howardb5c77212018-02-14 17:12:34 -07001042
Gavin Howard0b465d02018-02-15 11:41:16 -07001043 memset(n, 0, sizeof(BcNum));
Gavin Howardb5c77212018-02-14 17:12:34 -07001044
Gavin Howard5d74e962018-02-26 13:44:13 -07001045 request = request >= BC_NUM_DEF_SIZE ? request : BC_NUM_DEF_SIZE;
1046
Gavin Howard9c4358c2018-03-22 20:11:28 -06001047 if (!(n->num = malloc(request))) return BC_STATUS_MALLOC_FAIL;
Gavin Howardb5c77212018-02-14 17:12:34 -07001048
Gavin Howard6f6dc942018-02-15 16:58:50 -07001049 n->cap = request;
Gavin Howardb5c77212018-02-14 17:12:34 -07001050
1051 return BC_STATUS_SUCCESS;
1052}
1053
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001054BcStatus bc_num_expand(BcNum *n, size_t request) {
Gavin Howardb5c77212018-02-14 17:12:34 -07001055
Gavin Howard9c4358c2018-03-22 20:11:28 -06001056 BcDigit *temp;
1057
Gavin Howard27fdfb92018-03-21 07:56:59 -06001058 assert(n && request);
Gavin Howardb5c77212018-02-14 17:12:34 -07001059
Gavin Howard9c4358c2018-03-22 20:11:28 -06001060 if (request <= n->cap) return BC_STATUS_SUCCESS;
Gavin Howardb5c77212018-02-14 17:12:34 -07001061
Gavin Howard9c4358c2018-03-22 20:11:28 -06001062 if (!(temp = realloc(n->num, request))) return BC_STATUS_MALLOC_FAIL;
Gavin Howardb5c77212018-02-14 17:12:34 -07001063
Gavin Howard9c4358c2018-03-22 20:11:28 -06001064 memset(temp + n->cap, 0, sizeof(char) * (request - n->cap));
Gavin Howardb5c77212018-02-14 17:12:34 -07001065
Gavin Howard9c4358c2018-03-22 20:11:28 -06001066 n->num = temp;
1067 n->cap = request;
Gavin Howardb5c77212018-02-14 17:12:34 -07001068
1069 return BC_STATUS_SUCCESS;
1070}
1071
Gavin Howarded392aa2018-02-27 13:09:26 -07001072void bc_num_free(void *num) {
Gavin Howard9c4358c2018-03-22 20:11:28 -06001073 BcNum *n = (BcNum*) num;
Gavin Howardd9734e52018-03-29 15:54:41 -06001074 if (n && n->num) free(n->num);
Gavin Howardb5c77212018-02-14 17:12:34 -07001075}
1076
Gavin Howard9c4358c2018-03-22 20:11:28 -06001077BcStatus bc_num_copy(BcNum *d, BcNum *s) {
Gavin Howard5a049c42018-02-15 11:24:11 -07001078
1079 BcStatus status;
Gavin Howard5a049c42018-02-15 11:24:11 -07001080
Gavin Howard9c4358c2018-03-22 20:11:28 -06001081 assert(d && s);
Gavin Howardf23448c2018-02-27 20:36:24 -07001082
Gavin Howard9c4358c2018-03-22 20:11:28 -06001083 if (d == s) return BC_STATUS_SUCCESS;
Gavin Howard4515e2a2018-03-05 10:52:01 -07001084
Gavin Howard9c4358c2018-03-22 20:11:28 -06001085 if ((status = bc_num_expand(d, s->cap))) return status;
Gavin Howard5a049c42018-02-15 11:24:11 -07001086
1087 d->len = s->len;
1088 d->neg = s->neg;
Gavin Howard8389bb22018-02-15 17:40:34 -07001089 d->rdx = s->rdx;
Gavin Howard5a049c42018-02-15 11:24:11 -07001090
Gavin Howard188b4ac2018-03-24 14:49:19 -06001091 memcpy(d->num, s->num, sizeof(BcDigit) * d->len);
1092 memset(d->num + d->len, 0, sizeof(BcDigit) * (d->cap - d->len));
Gavin Howard5a049c42018-02-15 11:24:11 -07001093
1094 return BC_STATUS_SUCCESS;
1095}
1096
Gavin Howard5cea43b2018-03-02 11:32:11 -07001097BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base, size_t base_t) {
Gavin Howard025d04d2018-02-20 13:53:28 -07001098
Gavin Howard3eb626f2018-02-14 13:54:35 -07001099 BcStatus status;
1100
Gavin Howard27fdfb92018-03-21 07:56:59 -06001101 assert(n && val && base && base_t >= BC_NUM_MIN_BASE &&
1102 base_t <= BC_NUM_MAX_INPUT_BASE);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001103
Gavin Howardbdb2f922018-03-15 09:25:18 -06001104 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
Gavin Howard3eb626f2018-02-14 13:54:35 -07001105
Gavin Howard5cea43b2018-03-02 11:32:11 -07001106 if (base_t == 10) status = bc_num_parseDecimal(n, val);
Gavin Howardede51f02018-03-02 12:30:00 -07001107 else status = bc_num_parseBase(n, val, base);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001108
1109 return status;
1110}
1111
Gavin Howard9c4358c2018-03-22 20:11:28 -06001112BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t,
1113 bool newline, size_t *nchars)
Gavin Howard152f3e82018-03-07 12:33:15 -07001114{
Gavin Howard3eb626f2018-02-14 13:54:35 -07001115 BcStatus status;
1116
Gavin Howard9c4358c2018-03-22 20:11:28 -06001117 assert(n && base && nchars && base_t >= BC_NUM_MIN_BASE &&
Gavin Howard0dd566d2018-03-28 19:29:34 -06001118 base_t <= BC_MAX_BASE);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001119
Gavin Howardbc7cae82018-03-14 13:43:04 -06001120 if (*nchars >= BC_NUM_PRINT_WIDTH) {
Gavin Howarda141a0f2018-03-23 13:16:10 -06001121 if (putchar('\\') == EOF) return BC_STATUS_IO_ERR;
1122 if (putchar('\n') == EOF) return BC_STATUS_IO_ERR;
Gavin Howardbc7cae82018-03-14 13:43:04 -06001123 *nchars = 0;
1124 }
1125
Gavin Howardeb9a8222018-03-13 09:25:56 -06001126 if (!n->len) {
Gavin Howarda141a0f2018-03-23 13:16:10 -06001127 if (putchar('0') == EOF) return BC_STATUS_IO_ERR;
Gavin Howardbc7cae82018-03-14 13:43:04 -06001128 ++(*nchars);
Gavin Howardec8f8f12018-03-03 09:47:19 -07001129 status = BC_STATUS_SUCCESS;
Gavin Howard9576c382018-03-03 08:11:53 -07001130 }
Gavin Howard9c4358c2018-03-22 20:11:28 -06001131 else if (base_t == 10) status = bc_num_printDecimal(n, nchars);
1132 else status = bc_num_printBase(n, base, base_t, nchars);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001133
Gavin Howard152f3e82018-03-07 12:33:15 -07001134 if (status) return status;
1135
1136 if (newline) {
Gavin Howarda141a0f2018-03-23 13:16:10 -06001137 if (putchar('\n') == EOF) return BC_STATUS_IO_ERR;
Gavin Howardbc7cae82018-03-14 13:43:04 -06001138 *nchars = 0;
Gavin Howard152f3e82018-03-07 12:33:15 -07001139 }
1140
Gavin Howard3eb626f2018-02-14 13:54:35 -07001141 return status;
1142}
1143
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001144BcStatus bc_num_ulong(BcNum *n, unsigned long *result) {
Gavin Howard68b8a5c2018-02-15 11:41:24 -07001145
1146 size_t i;
Gavin Howard9c4358c2018-03-22 20:11:28 -06001147 unsigned long prev, pow;
Gavin Howard68b8a5c2018-02-15 11:41:24 -07001148
Gavin Howard27fdfb92018-03-21 07:56:59 -06001149 assert(n && result);
Gavin Howard68b8a5c2018-02-15 11:41:24 -07001150
Gavin Howard68b8a5c2018-02-15 11:41:24 -07001151 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
1152
1153 *result = 0;
Gavin Howard025d04d2018-02-20 13:53:28 -07001154 pow = 1;
Gavin Howard68b8a5c2018-02-15 11:41:24 -07001155
Gavin Howard23958582018-03-03 09:30:20 -07001156 for (i = n->rdx; i < n->len; ++i) {
Gavin Howard68b8a5c2018-02-15 11:41:24 -07001157
1158 prev = *result;
Gavin Howard025d04d2018-02-20 13:53:28 -07001159 *result += n->num[i] * pow;
Gavin Howard025d04d2018-02-20 13:53:28 -07001160 pow *= 10;
Gavin Howard68b8a5c2018-02-15 11:41:24 -07001161
1162 if (*result < prev) return BC_STATUS_MATH_OVERFLOW;
1163 }
1164
1165 return BC_STATUS_SUCCESS;
1166}
1167
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001168BcStatus bc_num_ulong2num(BcNum *n, unsigned long val) {
Gavin Howard8e2cc692018-02-15 17:39:14 -07001169
1170 BcStatus status;
Gavin Howard9c4358c2018-03-22 20:11:28 -06001171 size_t len, i;
Gavin Howard021150b2018-03-10 15:40:42 -07001172 BcDigit *ptr;
Gavin Howard8e2cc692018-02-15 17:39:14 -07001173
Gavin Howard27fdfb92018-03-21 07:56:59 -06001174 assert(n);
Gavin Howard8e2cc692018-02-15 17:39:14 -07001175
Gavin Howard025d04d2018-02-20 13:53:28 -07001176 bc_num_zero(n);
1177
Gavin Howard8e2cc692018-02-15 17:39:14 -07001178 if (!val) {
Gavin Howard8e2cc692018-02-15 17:39:14 -07001179 memset(n->num, 0, sizeof(char) * n->cap);
Gavin Howard8e2cc692018-02-15 17:39:14 -07001180 return BC_STATUS_SUCCESS;
1181 }
1182
Gavin Howarda83e3dc2018-02-15 18:57:08 -07001183 len = (size_t) ceil(log10(((double) ULONG_MAX) + 1.0f));
Gavin Howard8e2cc692018-02-15 17:39:14 -07001184
Gavin Howard9c4358c2018-03-22 20:11:28 -06001185 if ((status = bc_num_expand(n, len))) return status;
Gavin Howard8e2cc692018-02-15 17:39:14 -07001186
Gavin Howard9c4358c2018-03-22 20:11:28 -06001187 for (ptr = n->num, i = 0; val; ++i, ++n->len) {
Gavin Howard025d04d2018-02-20 13:53:28 -07001188 ptr[i] = (char) (val % 10);
Gavin Howard8e2cc692018-02-15 17:39:14 -07001189 val /= 10;
Gavin Howard8e2cc692018-02-15 17:39:14 -07001190 }
1191
Gavin Howard025d04d2018-02-20 13:53:28 -07001192 return BC_STATUS_SUCCESS;
1193}
1194
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001195BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *result, size_t scale) {
Gavin Howarda1c090a2018-03-05 14:20:33 -07001196 (void) scale;
Gavin Howard8694e132018-03-14 13:43:28 -06001197 BcNumBinaryFunc op = (!!a->neg == !!b->neg) ? bc_num_alg_a : bc_num_alg_s;
Gavin Howarda1c090a2018-03-05 14:20:33 -07001198 return bc_num_binary(a, b, result, false, op, a->len + b->len + 1);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001199}
1200
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001201BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *result, size_t scale) {
Gavin Howarda1c090a2018-03-05 14:20:33 -07001202 (void) scale;
Gavin Howard8694e132018-03-14 13:43:28 -06001203 BcNumBinaryFunc op = (!!a->neg == !!b->neg) ? bc_num_alg_s : bc_num_alg_a;
Gavin Howarda1c090a2018-03-05 14:20:33 -07001204 return bc_num_binary(a, b, result, true, op, a->len + b->len + 1);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001205}
1206
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001207BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *result, size_t scale) {
Gavin Howard57440052018-02-23 11:55:30 -07001208 return bc_num_binary(a, b, result, scale, bc_num_alg_m,
Gavin Howarddff6d852018-03-09 11:25:00 -07001209 a->len + b->len + scale + 1);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001210}
1211
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001212BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *result, size_t scale) {
Gavin Howard57440052018-02-23 11:55:30 -07001213 return bc_num_binary(a, b, result, scale, bc_num_alg_d,
Gavin Howarddff6d852018-03-09 11:25:00 -07001214 a->len + b->len + scale + 1);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001215}
1216
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001217BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *result, size_t scale) {
Gavin Howard57440052018-02-23 11:55:30 -07001218 return bc_num_binary(a, b, result, scale, bc_num_alg_mod,
Gavin Howarddff6d852018-03-09 11:25:00 -07001219 a->len + b->len + scale + 1);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001220}
1221
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001222BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *result, size_t scale) {
Gavin Howardb15ce1c2018-03-03 12:57:19 -07001223 return bc_num_binary(a, b, result, scale, bc_num_alg_p,
1224 (a->len + 1) * (b->len + 1));
Gavin Howard3eb626f2018-02-14 13:54:35 -07001225}
1226
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001227BcStatus bc_num_sqrt(BcNum *a, BcNum *result, size_t scale) {
Gavin Howard72701cc2018-02-14 15:50:00 -07001228 return bc_num_unary(a, result, scale, bc_num_sqrt_newton,
Gavin Howarddac9f522018-03-05 14:09:06 -07001229 a->rdx + (a->len - a->rdx) * 2 + 1);
Gavin Howard3eb626f2018-02-14 13:54:35 -07001230}
1231
Gavin Howard43a027f2018-02-26 13:27:10 -07001232void bc_num_zero(BcNum *n) {
Gavin Howard6455db12018-02-15 17:38:20 -07001233
1234 if (!n) return;
1235
Gavin Howard43a027f2018-02-26 13:27:10 -07001236 memset(n->num, 0, n->cap * sizeof(char));
1237
Gavin Howard6455db12018-02-15 17:38:20 -07001238 n->neg = false;
1239 n->len = 0;
Gavin Howard8389bb22018-02-15 17:40:34 -07001240 n->rdx = 0;
Gavin Howard6455db12018-02-15 17:38:20 -07001241}
1242
Gavin Howard43a027f2018-02-26 13:27:10 -07001243void bc_num_one(BcNum *n) {
Gavin Howardf507f232018-02-23 21:10:24 -07001244
1245 if (!n) return;
1246
Gavin Howard5d74e962018-02-26 13:44:13 -07001247 bc_num_zero(n);
Gavin Howard43a027f2018-02-26 13:27:10 -07001248
Gavin Howardf507f232018-02-23 21:10:24 -07001249 n->len = 1;
Gavin Howardf507f232018-02-23 21:10:24 -07001250 n->num[0] = 1;
1251}
1252
Gavin Howard5d74e962018-02-26 13:44:13 -07001253void bc_num_ten(BcNum *n) {
1254
1255 if (!n) return;
1256
1257 bc_num_zero(n);
1258
1259 n->len = 2;
1260 n->num[0] = 0;
1261 n->num[1] = 1;
1262}