1 /*
2 * *****************************************************************************
3 *
4 * Copyright (c) 2018-2019 Gavin D. Howard and contributors.
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * *****************************************************************************
31 *
32 * Code for the number type.
33 *
34 */
35
36 #include <assert.h>
37 #include <ctype.h>
38 #include <stdbool.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include <limits.h>
43
44 #include <status.h>
45 #include <num.h>
46 #include <vm.h>
47
48 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
49
bc_num_neg(size_t n,bool neg)50 static ssize_t bc_num_neg(size_t n, bool neg) {
51 return (((ssize_t) n) ^ -((ssize_t) neg)) + neg;
52 }
53
bc_num_cmpZero(const BcNum * n)54 ssize_t bc_num_cmpZero(const BcNum *n) {
55 return bc_num_neg((n)->len != 0, (n)->neg);
56 }
57
bc_num_int(const BcNum * n)58 static size_t bc_num_int(const BcNum *n) {
59 return n->len ? n->len - n->rdx : 0;
60 }
61
bc_num_expand(BcNum * restrict n,size_t req)62 static void bc_num_expand(BcNum *restrict n, size_t req) {
63 assert(n != NULL);
64 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
65 if (req > n->cap) {
66 n->num = bc_vm_realloc(n->num, BC_NUM_SIZE(req));
67 n->cap = req;
68 }
69 }
70
bc_num_setToZero(BcNum * restrict n,size_t scale)71 static void bc_num_setToZero(BcNum *restrict n, size_t scale) {
72 assert(n != NULL);
73 n->scale = scale;
74 n->len = n->rdx = 0;
75 n->neg = false;
76 }
77
bc_num_zero(BcNum * restrict n)78 static void bc_num_zero(BcNum *restrict n) {
79 bc_num_setToZero(n, 0);
80 }
81
bc_num_one(BcNum * restrict n)82 void bc_num_one(BcNum *restrict n) {
83 bc_num_zero(n);
84 n->len = 1;
85 n->num[0] = 1;
86 }
87
bc_num_clean(BcNum * restrict n)88 static void bc_num_clean(BcNum *restrict n) {
89 while (BC_NUM_NONZERO(n) && !n->num[n->len - 1]) n->len -= 1;
90 if (BC_NUM_ZERO(n)) {
91 n->neg = false;
92 n->rdx = 0;
93 }
94 else if (n->len < n->rdx) n->len = n->rdx;
95 }
96
bc_num_log10(size_t i)97 static size_t bc_num_log10(size_t i) {
98 size_t len;
99 for (len = 1; i; i /= BC_BASE, ++len);
100 assert(len - 1 <= BC_BASE_DIGS + 1);
101 return len - 1;
102 }
103
bc_num_zeroDigits(const BcDig * n)104 static size_t bc_num_zeroDigits(const BcDig *n) {
105 return BC_BASE_DIGS - bc_num_log10((size_t) *n);
106 }
107
bc_num_intDigits(const BcNum * n)108 static size_t bc_num_intDigits(const BcNum *n) {
109 size_t digits = bc_num_int(n) * BC_BASE_DIGS;
110 if (digits > 0) digits -= bc_num_zeroDigits(n->num + n->len - 1);
111 return digits;
112 }
113
bc_num_nonzeroLen(const BcNum * restrict n)114 static size_t bc_num_nonzeroLen(const BcNum *restrict n) {
115 size_t i, len = n->len;
116 assert(len == n->rdx);
117 for (i = len - 1; i < len && !n->num[i]; --i);
118 assert(i + 1 > 0);
119 return i + 1;
120 }
121
bc_num_addDigits(BcDig a,BcDig b,bool * carry)122 static BcDig bc_num_addDigits(BcDig a, BcDig b, bool *carry) {
123
124 assert(((BcBigDig) BC_BASE_POW) * 2 == ((BcDig) BC_BASE_POW) * 2);
125 assert(a < BC_BASE_POW);
126 assert(b < BC_BASE_POW);
127
128 a += b + *carry;
129 *carry = (a >= BC_BASE_POW);
130 if (*carry) a -= BC_BASE_POW;
131
132 assert(a >= 0);
133 assert(a < BC_BASE_POW);
134
135 return a;
136 }
137
bc_num_subDigits(BcDig a,BcDig b,bool * carry)138 static BcDig bc_num_subDigits(BcDig a, BcDig b, bool *carry) {
139
140 assert(a < BC_BASE_POW);
141 assert(b < BC_BASE_POW);
142
143 b += *carry;
144 *carry = (a < b);
145 if (*carry) a += BC_BASE_POW;
146
147 assert(a - b >= 0);
148 assert(a - b < BC_BASE_POW);
149
150 return a - b;
151 }
152
bc_num_addArrays(BcDig * restrict a,const BcDig * restrict b,size_t len)153 static BcStatus bc_num_addArrays(BcDig *restrict a, const BcDig *restrict b,
154 size_t len)
155 {
156 size_t i;
157 bool carry = false;
158
159 for (i = 0; BC_NO_SIG && i < len; ++i)
160 a[i] = bc_num_addDigits(a[i], b[i], &carry);
161
162 for (; BC_NO_SIG && carry; ++i)
163 a[i] = bc_num_addDigits(a[i], 0, &carry);
164
165 return BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
166 }
167
bc_num_subArrays(BcDig * restrict a,const BcDig * restrict b,size_t len)168 static BcStatus bc_num_subArrays(BcDig *restrict a, const BcDig *restrict b,
169 size_t len)
170 {
171 size_t i;
172 bool carry = false;
173
174 for (i = 0; BC_NO_SIG && i < len; ++i)
175 a[i] = bc_num_subDigits(a[i], b[i], &carry);
176
177 for (; BC_NO_SIG && carry; ++i)
178 a[i] = bc_num_subDigits(a[i], 0, &carry);
179
180 return BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
181 }
182
bc_num_mulArray(const BcNum * restrict a,BcBigDig b,BcNum * restrict c)183 static BcStatus bc_num_mulArray(const BcNum *restrict a, BcBigDig b,
184 BcNum *restrict c)
185 {
186 size_t i;
187 BcBigDig carry = 0;
188
189 assert(b <= BC_BASE_POW);
190
191 if (a->len + 1 > c->cap) bc_num_expand(c, a->len + 1);
192
193 memset(c->num, 0, BC_NUM_SIZE(c->cap));
194
195 for (i = 0; BC_NO_SIG && i < a->len; ++i) {
196 BcBigDig in = ((BcBigDig) a->num[i]) * b + carry;
197 c->num[i] = in % BC_BASE_POW;
198 carry = in / BC_BASE_POW;
199 }
200
201 if (BC_NO_SIG) {
202 assert(carry < BC_BASE_POW);
203 c->num[i] = (BcDig) carry;
204 c->len = a->len;
205 c->len += (carry != 0);
206 }
207
208 bc_num_clean(c);
209
210 assert(!c->neg || BC_NUM_NONZERO(c));
211 assert(c->rdx <= c->len || !c->len || BC_SIG);
212 assert(!c->len || c->num[c->len - 1] || c->rdx == c->len);
213
214 return BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
215 }
216
bc_num_divArray(const BcNum * restrict a,BcBigDig b,BcNum * restrict c,BcBigDig * rem)217 static BcStatus bc_num_divArray(const BcNum *restrict a, BcBigDig b,
218 BcNum *restrict c, BcBigDig *rem)
219 {
220 size_t i;
221 BcBigDig carry = 0;
222
223 assert(c->cap >= a->len);
224
225 for (i = a->len - 1; BC_NO_SIG && i < a->len; --i) {
226 BcBigDig in = ((BcBigDig) a->num[i]) + carry * BC_BASE_POW;
227 assert(in / b < BC_BASE_POW);
228 c->num[i] = (BcDig) (in / b);
229 carry = in % b;
230 }
231
232 c->len = a->len;
233 bc_num_clean(c);
234 *rem = carry;
235
236 assert(!c->neg || BC_NUM_NONZERO(c));
237 assert(c->rdx <= c->len || !c->len || BC_SIG);
238 assert(!c->len || c->num[c->len - 1] || c->rdx == c->len);
239
240 return BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
241 }
242
bc_num_compare(const BcDig * restrict a,const BcDig * restrict b,size_t len)243 static ssize_t bc_num_compare(const BcDig *restrict a, const BcDig *restrict b,
244 size_t len)
245 {
246 size_t i;
247 BcDig c = 0;
248 for (i = len - 1; BC_NO_SIG && i < len && !(c = a[i] - b[i]); --i);
249 return BC_SIG ? BC_NUM_CMP_SIGNAL_VAL : bc_num_neg(i + 1, c < 0);
250 }
251
bc_num_cmp(const BcNum * a,const BcNum * b)252 ssize_t bc_num_cmp(const BcNum *a, const BcNum *b) {
253
254 size_t i, min, a_int, b_int, diff;
255 BcDig *max_num, *min_num;
256 bool a_max, neg = false;
257 ssize_t cmp;
258
259 assert(a != NULL && b != NULL);
260
261 if (a == b) return 0;
262 if (BC_NUM_ZERO(a)) return bc_num_neg(b->len != 0, !b->neg);
263 if (BC_NUM_ZERO(b)) return bc_num_cmpZero(a);
264 if (a->neg) {
265 if (b->neg) neg = true;
266 else return -1;
267 }
268 else if (b->neg) return 1;
269
270 a_int = bc_num_int(a);
271 b_int = bc_num_int(b);
272 a_int -= b_int;
273 a_max = (a->rdx > b->rdx);
274
275 if (a_int) return neg ? -((ssize_t) a_int) : (ssize_t) a_int;
276
277 if (a_max) {
278 min = b->rdx;
279 diff = a->rdx - b->rdx;
280 max_num = a->num + diff;
281 min_num = b->num;
282 }
283 else {
284 min = a->rdx;
285 diff = b->rdx - a->rdx;
286 max_num = b->num + diff;
287 min_num = a->num;
288 }
289
290 cmp = bc_num_compare(max_num, min_num, b_int + min);
291
292 #if BC_ENABLE_SIGNALS
293 if (BC_NUM_CMP_SIGNAL(cmp)) return cmp;
294 #endif // BC_ENABLE_SIGNALS
295
296 if (cmp) return bc_num_neg((size_t) cmp, !a_max == !neg);
297
298 for (max_num -= diff, i = diff - 1; BC_NO_SIG && i < diff; --i) {
299 if (max_num[i]) return bc_num_neg(1, !a_max == !neg);
300 }
301
302 return BC_SIG ? BC_NUM_CMP_SIGNAL_VAL : 0;
303 }
304
bc_num_truncate(BcNum * restrict n,size_t places)305 void bc_num_truncate(BcNum *restrict n, size_t places) {
306
307 size_t places_rdx;
308
309 if (!places) return;
310
311 places_rdx = n->rdx ? n->rdx - BC_NUM_RDX(n->scale - places) : 0;
312 assert(places <= n->scale && (BC_NUM_ZERO(n) || places_rdx <= n->len));
313
314 n->scale -= places;
315 n->rdx -= places_rdx;
316
317 if (BC_NUM_NONZERO(n)) {
318
319 size_t pow;
320
321 pow = n->scale % BC_BASE_DIGS;
322 pow = pow ? BC_BASE_DIGS - pow : 0;
323 pow = bc_num_pow10[pow];
324
325 n->len -= places_rdx;
326 memmove(n->num, n->num + places_rdx, BC_NUM_SIZE(n->len));
327
328 // Clear the lower part of the last digit.
329 if (BC_NUM_NONZERO(n)) n->num[0] -= n->num[0] % (BcDig) pow;
330
331 bc_num_clean(n);
332 }
333 }
334
bc_num_extend(BcNum * restrict n,size_t places)335 static void bc_num_extend(BcNum *restrict n, size_t places) {
336
337 size_t places_rdx;
338
339 if (!places) return;
340 if (BC_NUM_ZERO(n)) {
341 n->scale += places;
342 return;
343 }
344
345 places_rdx = BC_NUM_RDX(places + n->scale) - n->rdx;
346
347 if (places_rdx) {
348 bc_num_expand(n, bc_vm_growSize(n->len, places_rdx));
349 memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len));
350 memset(n->num, 0, BC_NUM_SIZE(places_rdx));
351 }
352
353 n->rdx += places_rdx;
354 n->scale += places;
355 n->len += places_rdx;
356
357 assert(n->rdx == BC_NUM_RDX(n->scale));
358 }
359
bc_num_retireMul(BcNum * restrict n,size_t scale,bool neg1,bool neg2)360 static void bc_num_retireMul(BcNum *restrict n, size_t scale,
361 bool neg1, bool neg2)
362 {
363 if (n->scale < scale) bc_num_extend(n, scale - n->scale);
364 else bc_num_truncate(n, n->scale - scale);
365
366 bc_num_clean(n);
367 if (BC_NUM_NONZERO(n)) n->neg = (!neg1 != !neg2);
368 }
369
bc_num_split(const BcNum * restrict n,size_t idx,BcNum * restrict a,BcNum * restrict b)370 static void bc_num_split(const BcNum *restrict n, size_t idx,
371 BcNum *restrict a, BcNum *restrict b)
372 {
373 assert(BC_NUM_ZERO(a));
374 assert(BC_NUM_ZERO(b));
375
376 if (idx < n->len) {
377
378 b->len = n->len - idx;
379 a->len = idx;
380 a->scale = a->rdx = b->scale = b->rdx = 0;
381
382 assert(a->cap >= a->len);
383 assert(b->cap >= b->len);
384
385 memcpy(b->num, n->num + idx, BC_NUM_SIZE(b->len));
386 memcpy(a->num, n->num, BC_NUM_SIZE(idx));
387
388 bc_num_clean(b);
389 }
390 else bc_num_copy(a, n);
391
392 bc_num_clean(a);
393 }
394
bc_num_shiftZero(BcNum * restrict n)395 static size_t bc_num_shiftZero(BcNum *restrict n) {
396
397 size_t i;
398
399 assert(!n->rdx || BC_NUM_ZERO(n));
400
401 for (i = 0; i < n->len && !n->num[i]; ++i);
402
403 n->len -= i;
404 n->num += i;
405
406 return i;
407 }
408
bc_num_unshiftZero(BcNum * restrict n,size_t places_rdx)409 static void bc_num_unshiftZero(BcNum *restrict n, size_t places_rdx) {
410 n->len += places_rdx;
411 n->num -= places_rdx;
412 }
413
bc_num_shift(BcNum * restrict n,BcBigDig dig)414 static BcStatus bc_num_shift(BcNum *restrict n, BcBigDig dig) {
415
416 size_t i, len = n->len;
417 BcBigDig carry = 0, pow;
418 BcDig *ptr = n->num;
419
420 assert(dig < BC_BASE_DIGS);
421
422 pow = bc_num_pow10[dig];
423 dig = bc_num_pow10[BC_BASE_DIGS - dig];
424
425 for (i = len - 1; BC_NO_SIG && i < len; --i) {
426 BcBigDig in, temp;
427 in = ((BcBigDig) ptr[i]);
428 temp = carry * dig;
429 carry = in % pow;
430 ptr[i] = ((BcDig) (in / pow)) + (BcDig) temp;
431 }
432
433 assert(!carry);
434
435 return BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
436 }
437
bc_num_shiftLeft(BcNum * restrict n,size_t places)438 static BcStatus bc_num_shiftLeft(BcNum *restrict n, size_t places) {
439
440 BcStatus s = BC_STATUS_SUCCESS;
441 BcBigDig dig;
442 size_t places_rdx;
443 bool shift;
444
445 if (!places) return s;
446 if (places > n->scale) {
447 size_t size = bc_vm_growSize(BC_NUM_RDX(places - n->scale), n->len);
448 if (size > SIZE_MAX - 1) return bc_vm_err(BC_ERROR_MATH_OVERFLOW);
449 }
450 if (BC_NUM_ZERO(n)) {
451 if (n->scale >= places) n->scale -= places;
452 else n->scale = 0;
453 return s;
454 }
455
456 dig = (BcBigDig) (places % BC_BASE_DIGS);
457 shift = (dig != 0);
458 places_rdx = BC_NUM_RDX(places);
459
460 if (n->scale) {
461
462 if (n->rdx >= places_rdx) {
463
464 size_t mod = n->scale % BC_BASE_DIGS, revdig;
465
466 mod = mod ? mod : BC_BASE_DIGS;
467 revdig = dig ? BC_BASE_DIGS - dig : 0;
468
469 if (mod + revdig > BC_BASE_DIGS) places_rdx = 1;
470 else places_rdx = 0;
471 }
472 else places_rdx -= n->rdx;
473 }
474
475 if (places_rdx) {
476 bc_num_expand(n, bc_vm_growSize(n->len, places_rdx));
477 memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len));
478 memset(n->num, 0, BC_NUM_SIZE(places_rdx));
479 n->len += places_rdx;
480 }
481
482 if (places > n->scale) n->scale = n->rdx = 0;
483 else {
484 n->scale -= places;
485 n->rdx = BC_NUM_RDX(n->scale);
486 }
487
488 if (shift) s = bc_num_shift(n, BC_BASE_DIGS - dig);
489
490 bc_num_clean(n);
491
492 return BC_SIG && !s ? BC_STATUS_SIGNAL : s;
493 }
494
bc_num_shiftRight(BcNum * restrict n,size_t places)495 static BcStatus bc_num_shiftRight(BcNum *restrict n, size_t places) {
496
497 BcStatus s = BC_STATUS_SUCCESS;
498 BcBigDig dig;
499 size_t places_rdx, scale, scale_mod, int_len, expand;
500 bool shift;
501
502 if (!places) return s;
503 if (BC_NUM_ZERO(n)) {
504 n->scale += places;
505 bc_num_expand(n, BC_NUM_RDX(n->scale));
506 return s;
507 }
508
509 dig = (BcBigDig) (places % BC_BASE_DIGS);
510 shift = (dig != 0);
511 scale = n->scale;
512 scale_mod = scale % BC_BASE_DIGS;
513 scale_mod = scale_mod ? scale_mod : BC_BASE_DIGS;
514 int_len = bc_num_int(n);
515 places_rdx = BC_NUM_RDX(places);
516
517 if (scale_mod + dig > BC_BASE_DIGS) {
518 expand = places_rdx - 1;
519 places_rdx = 1;
520 }
521 else {
522 expand = places_rdx;
523 places_rdx = 0;
524 }
525
526 if (expand > int_len) expand -= int_len;
527 else expand = 0;
528
529 bc_num_extend(n, places_rdx * BC_BASE_DIGS);
530 bc_num_expand(n, bc_vm_growSize(expand, n->len));
531 memset(n->num + n->len, 0, BC_NUM_SIZE(expand));
532 n->len += expand;
533 n->scale = n->rdx = 0;
534
535 if (shift) s = bc_num_shift(n, dig);
536
537 n->scale = scale + places;
538 n->rdx = BC_NUM_RDX(n->scale);
539
540 bc_num_clean(n);
541
542 assert(n->rdx <= n->len && n->len <= n->cap);
543 assert(n->rdx == BC_NUM_RDX(n->scale));
544
545 return BC_SIG && !s ? BC_STATUS_SIGNAL : s;
546 }
547
bc_num_inv(BcNum * a,BcNum * b,size_t scale)548 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale) {
549
550 BcNum one;
551 BcDig num[2];
552
553 assert(BC_NUM_NONZERO(a));
554
555 bc_num_setup(&one, num, sizeof(num) / sizeof(BcDig));
556 bc_num_one(&one);
557
558 return bc_num_div(&one, a, b, scale);
559 }
560
561 #if BC_ENABLE_EXTRA_MATH
bc_num_intop(const BcNum * a,const BcNum * b,BcNum * restrict c,BcBigDig * v)562 static BcStatus bc_num_intop(const BcNum *a, const BcNum *b, BcNum *restrict c,
563 BcBigDig *v)
564 {
565 if (BC_ERR(b->rdx)) return bc_vm_err(BC_ERROR_MATH_NON_INTEGER);
566 bc_num_copy(c, a);
567 return bc_num_bigdig(b, v);
568 }
569 #endif // BC_ENABLE_EXTRA_MATH
570
bc_num_as(BcNum * a,BcNum * b,BcNum * restrict c,size_t sub)571 static BcStatus bc_num_as(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) {
572
573 BcDig *ptr_c, *ptr_l, *ptr_r;
574 size_t i, min_rdx, max_rdx, diff, a_int, b_int, min_len, max_len, max_int;
575 size_t len_l, len_r;
576 bool b_neg, do_sub, do_rev_sub, carry;
577
578 // Because this function doesn't need to use scale (per the bc spec),
579 // I am hijacking it to say whether it's doing an add or a subtract.
580 // Convert substraction to addition of negative second operand.
581
582 if (BC_NUM_ZERO(b)) {
583 bc_num_copy(c, a);
584 return BC_STATUS_SUCCESS;
585 }
586 if (BC_NUM_ZERO(a)) {
587 bc_num_copy(c, b);
588 c->neg = (b->neg != sub);
589 return BC_STATUS_SUCCESS;
590 }
591
592 b_neg = (b->neg != sub);
593 do_sub = (a->neg != b_neg);
594
595 a_int = bc_num_int(a);
596 b_int = bc_num_int(b);
597 max_int = BC_MAX(a_int, b_int);
598
599 min_rdx = BC_MIN(a->rdx, b->rdx);
600 max_rdx = BC_MAX(a->rdx, b->rdx);
601 diff = max_rdx - min_rdx;
602
603 max_len = max_int + max_rdx;
604
605 if (do_sub) {
606 if (a_int != b_int) do_rev_sub = (a_int < b_int);
607 else if (a->rdx > b->rdx)
608 do_rev_sub = (bc_num_compare(a->num + diff, b->num, b->len) < 0);
609 else
610 do_rev_sub = (bc_num_compare(a->num, b->num + diff, a->len) <= 0);
611 }
612 else {
613 max_len += 1;
614 do_rev_sub = false;
615 }
616
617 assert(max_len <= c->cap);
618
619 if (do_rev_sub) {
620 ptr_l = b->num;
621 ptr_r = a->num;
622 len_l = b->len;
623 len_r = a->len;
624 }
625 else {
626 ptr_l = a->num;
627 ptr_r = b->num;
628 len_l = a->len;
629 len_r = b->len;
630 }
631
632 ptr_c = c->num;
633 carry = false;
634
635 if (diff) {
636
637 if ((a->rdx > b->rdx) != do_rev_sub) {
638 memcpy(ptr_c, ptr_l, BC_NUM_SIZE(diff));
639 ptr_l += diff;
640 len_l -= diff;
641 }
642 else {
643
644 if (do_sub) {
645
646 for (i = 0; BC_NO_SIG && i < diff; i++)
647 ptr_c[i] = bc_num_subDigits(0, ptr_r[i], &carry);
648
649 if (BC_SIG) return BC_STATUS_SIGNAL;
650 }
651 else memcpy(ptr_c, ptr_r, BC_NUM_SIZE(diff));
652
653 ptr_r += diff;
654 len_r -= diff;
655 }
656
657 ptr_c += diff;
658 }
659
660 min_len = BC_MIN(len_l, len_r);
661
662 if (do_sub) {
663 for (i = 0; BC_NO_SIG && i < min_len; ++i)
664 ptr_c[i] = bc_num_subDigits(ptr_l[i], ptr_r[i], &carry);
665 for (; BC_NO_SIG && i < len_l; ++i)
666 ptr_c[i] = bc_num_subDigits(ptr_l[i], 0, &carry);
667 for (; BC_NO_SIG && i < len_r; ++i)
668 ptr_c[i] = bc_num_subDigits(0, ptr_r[i], &carry);
669 for (; BC_NO_SIG && i < max_len - diff; ++i)
670 ptr_c[i] = bc_num_subDigits(0, 0, &carry);
671 }
672 else {
673 for (i = 0; BC_NO_SIG && i < min_len; ++i)
674 ptr_c[i] = bc_num_addDigits(ptr_l[i], ptr_r[i], &carry);
675 for (; BC_NO_SIG && i < len_l; ++i)
676 ptr_c[i] = bc_num_addDigits(ptr_l[i], 0, &carry);
677 for (; BC_NO_SIG && i < len_r; ++i)
678 ptr_c[i] = bc_num_addDigits(0, ptr_r[i], &carry);
679 for (; BC_NO_SIG && i < max_len - diff; ++i)
680 ptr_c[i] = bc_num_addDigits(0, 0, &carry);
681 }
682
683 if (BC_NO_SIG) {
684
685 assert(carry == false);
686
687 // The result has the same sign as a, unless the operation was a
688 // reverse subtraction (b - a).
689 c->neg = (a->neg != do_rev_sub);
690 c->len = max_len;
691 c->rdx = max_rdx;
692 c->scale = BC_MAX(a->scale, b->scale);
693
694 bc_num_clean(c);
695 }
696
697 return BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
698 }
699
bc_num_m_simp(const BcNum * a,const BcNum * b,BcNum * restrict c)700 static BcStatus bc_num_m_simp(const BcNum *a, const BcNum *b, BcNum *restrict c)
701 {
702 size_t i, alen = a->len, blen = b->len, clen;
703 BcDig *ptr_a = a->num, *ptr_b = b->num, *ptr_c;
704 BcBigDig sum = 0, carry = 0;
705
706 assert(sizeof(sum) >= sizeof(BcDig) * 2);
707 assert(!a->rdx && !b->rdx);
708
709 clen = bc_vm_growSize(alen, blen);
710 bc_num_expand(c, bc_vm_growSize(clen, 1));
711
712 ptr_c = c->num;
713 memset(ptr_c, 0, BC_NUM_SIZE(c->cap));
714
715 for (i = 0; BC_NO_SIG && i < clen; ++i) {
716
717 ssize_t sidx = (ssize_t) (i - blen + 1);
718 size_t j = (size_t) BC_MAX(0, sidx), k = BC_MIN(i, blen - 1);
719
720 for (; BC_NO_SIG && j < alen && k < blen; ++j, --k) {
721
722 sum += ((BcBigDig) ptr_a[j]) * ((BcBigDig) ptr_b[k]);
723
724 if (sum >= ((BcBigDig) BC_BASE_POW) * BC_BASE_POW) {
725 carry += sum / BC_BASE_POW;
726 sum %= BC_BASE_POW;
727 }
728 }
729
730 if (sum >= BC_BASE_POW) {
731 carry += sum / BC_BASE_POW;
732 sum %= BC_BASE_POW;
733 }
734
735 ptr_c[i] = (BcDig) sum;
736 assert(ptr_c[i] < BC_BASE_POW);
737 sum = carry;
738 carry = 0;
739 }
740
741 if (sum) {
742 assert(sum < BC_BASE_POW);
743 ptr_c[clen] = (BcDig) sum;
744 clen += 1;
745 }
746
747 c->len = clen;
748
749 return BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
750 }
751
bc_num_shiftAddSub(BcNum * restrict n,const BcNum * restrict a,size_t shift,BcNumShiftAddOp op)752 static BcStatus bc_num_shiftAddSub(BcNum *restrict n, const BcNum *restrict a,
753 size_t shift, BcNumShiftAddOp op)
754 {
755 assert(n->len >= shift + a->len);
756 assert(!n->rdx && !a->rdx);
757 return op(n->num + shift, a->num, a->len);
758 }
759
bc_num_k(BcNum * a,BcNum * b,BcNum * restrict c)760 static BcStatus bc_num_k(BcNum *a, BcNum *b, BcNum *restrict c) {
761
762 BcStatus s;
763 size_t max, max2, total;
764 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
765 BcDig *digs, *dig_ptr;
766 BcNumShiftAddOp op;
767 bool aone = BC_NUM_ONE(a);
768
769 assert(BC_NUM_ZERO(c));
770
771 // This is here because the function is recursive.
772 if (BC_SIG) return BC_STATUS_SIGNAL;
773 if (BC_NUM_ZERO(a) || BC_NUM_ZERO(b)) return BC_STATUS_SUCCESS;
774 if (aone || BC_NUM_ONE(b)) {
775 bc_num_copy(c, aone ? b : a);
776 if ((aone && a->neg) || b->neg) c->neg = !c->neg;
777 return BC_STATUS_SUCCESS;
778 }
779 if (a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
780 return bc_num_m_simp(a, b, c);
781
782 max = BC_MAX(a->len, b->len);
783 max = BC_MAX(max, BC_NUM_DEF_SIZE);
784 max2 = (max + 1) / 2;
785
786 total = bc_vm_arraySize(BC_NUM_KARATSUBA_ALLOCS, max);
787 digs = dig_ptr = bc_vm_malloc(BC_NUM_SIZE(total));
788
789 bc_num_setup(&l1, dig_ptr, max);
790 dig_ptr += max;
791 bc_num_setup(&h1, dig_ptr, max);
792 dig_ptr += max;
793 bc_num_setup(&l2, dig_ptr, max);
794 dig_ptr += max;
795 bc_num_setup(&h2, dig_ptr, max);
796 dig_ptr += max;
797 bc_num_setup(&m1, dig_ptr, max);
798 dig_ptr += max;
799 bc_num_setup(&m2, dig_ptr, max);
800 max = bc_vm_growSize(max, 1);
801 bc_num_init(&z0, max);
802 bc_num_init(&z1, max);
803 bc_num_init(&z2, max);
804 max = bc_vm_growSize(max, max) + 1;
805 bc_num_init(&temp, max);
806
807 bc_num_split(a, max2, &l1, &h1);
808 bc_num_split(b, max2, &l2, &h2);
809
810 bc_num_expand(c, max);
811 c->len = max;
812 memset(c->num, 0, BC_NUM_SIZE(c->len));
813
814 s = bc_num_sub(&h1, &l1, &m1, 0);
815 if (BC_ERR(s)) goto err;
816 s = bc_num_sub(&l2, &h2, &m2, 0);
817 if (BC_ERR(s)) goto err;
818
819 if (BC_NUM_NONZERO(&h1) && BC_NUM_NONZERO(&h2)) {
820
821 s = bc_num_m(&h1, &h2, &z2, 0);
822 if (BC_ERR(s)) goto err;
823 bc_num_clean(&z2);
824
825 s = bc_num_shiftAddSub(c, &z2, max2 * 2, bc_num_addArrays);
826 if (BC_ERR(s)) goto err;
827 s = bc_num_shiftAddSub(c, &z2, max2, bc_num_addArrays);
828 if (BC_ERR(s)) goto err;
829 }
830
831 if (BC_NUM_NONZERO(&l1) && BC_NUM_NONZERO(&l2)) {
832
833 s = bc_num_m(&l1, &l2, &z0, 0);
834 if (BC_ERR(s)) goto err;
835 bc_num_clean(&z0);
836
837 s = bc_num_shiftAddSub(c, &z0, max2, bc_num_addArrays);
838 if (BC_ERR(s)) goto err;
839 s = bc_num_shiftAddSub(c, &z0, 0, bc_num_addArrays);
840 if (BC_ERR(s)) goto err;
841 }
842
843 if (BC_NUM_NONZERO(&m1) && BC_NUM_NONZERO(&m2)) {
844
845 s = bc_num_m(&m1, &m2, &z1, 0);
846 if (BC_ERR(s)) goto err;
847 bc_num_clean(&z1);
848
849 op = (m1.neg != m2.neg) ? bc_num_subArrays : bc_num_addArrays;
850 s = bc_num_shiftAddSub(c, &z1, max2, op);
851 if (BC_ERR(s)) goto err;
852 }
853
854 err:
855 free(digs);
856 bc_num_free(&temp);
857 bc_num_free(&z2);
858 bc_num_free(&z1);
859 bc_num_free(&z0);
860 return s;
861 }
862
bc_num_m(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)863 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) {
864
865 BcStatus s;
866 BcNum cpa, cpb;
867 size_t ascale, bscale, ardx, brdx, azero = 0, bzero = 0, zero, len, rscale;
868
869 bc_num_zero(c);
870 ascale = a->scale;
871 bscale = b->scale;
872 scale = BC_MAX(scale, ascale);
873 scale = BC_MAX(scale, bscale);
874
875 rscale = ascale + bscale;
876 scale = BC_MIN(rscale, scale);
877
878 if ((a->len == 1 || b->len == 1) && !a->rdx && !b->rdx) {
879
880 BcNum *operand;
881 BcBigDig dig;
882
883 if (a->len == 1) {
884 dig = (BcBigDig) a->num[0];
885 operand = b;
886 }
887 else {
888 dig = (BcBigDig) b->num[0];
889 operand = a;
890 }
891
892 s = bc_num_mulArray(operand, dig, c);
893 if (BC_ERROR_SIGNAL_ONLY(s)) return s;
894
895 if (BC_NUM_NONZERO(c)) c->neg = (a->neg != b->neg);
896
897 return s;
898 }
899
900 bc_num_init(&cpa, a->len + a->rdx);
901 bc_num_init(&cpb, b->len + b->rdx);
902 bc_num_copy(&cpa, a);
903 bc_num_copy(&cpb, b);
904
905 cpa.neg = cpb.neg = false;
906
907 ardx = cpa.rdx * BC_BASE_DIGS;
908 s = bc_num_shiftLeft(&cpa, ardx);
909 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
910 bc_num_clean(&cpa);
911 azero = bc_num_shiftZero(&cpa);
912
913 brdx = cpb.rdx * BC_BASE_DIGS;
914 s = bc_num_shiftLeft(&cpb, brdx);
915 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
916 bzero = bc_num_shiftZero(&cpb);
917 bc_num_clean(&cpb);
918
919 s = bc_num_k(&cpa, &cpb, c);
920 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
921
922 zero = bc_vm_growSize(azero, bzero);
923 len = bc_vm_growSize(c->len, zero);
924
925 bc_num_expand(c, len);
926 s = bc_num_shiftLeft(c, (len - c->len) * BC_BASE_DIGS);
927 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
928 s = bc_num_shiftRight(c, ardx + brdx);
929 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
930
931 bc_num_retireMul(c, scale, a->neg, b->neg);
932
933 err:
934 bc_num_unshiftZero(&cpb, bzero);
935 bc_num_free(&cpb);
936 bc_num_unshiftZero(&cpa, azero);
937 bc_num_free(&cpa);
938 return s;
939 }
940
bc_num_nonZeroDig(BcDig * restrict a,size_t len)941 static bool bc_num_nonZeroDig(BcDig *restrict a, size_t len) {
942 size_t i;
943 bool nonzero = false;
944 for (i = len - 1; !nonzero && i < len; --i) nonzero = (a[i] != 0);
945 return nonzero;
946 }
947
bc_num_divCmp(const BcDig * a,const BcNum * b,size_t len)948 static ssize_t bc_num_divCmp(const BcDig *a, const BcNum *b, size_t len) {
949
950 ssize_t cmp;
951
952 if (b->len > len && a[len]) cmp = bc_num_compare(a, b->num, len + 1);
953 else if (b->len <= len) {
954 if (a[len]) cmp = 1;
955 else cmp = bc_num_compare(a, b->num, len);
956 }
957 else cmp = -1;
958
959 return cmp;
960 }
961
bc_num_divExtend(BcNum * restrict a,BcNum * restrict b,BcBigDig divisor)962 static BcStatus bc_num_divExtend(BcNum *restrict a, BcNum *restrict b,
963 BcBigDig divisor)
964 {
965 BcStatus s;
966 size_t pow;
967
968 pow = BC_BASE_DIGS - bc_num_log10((size_t) divisor);
969
970 s = bc_num_shiftLeft(a, pow);
971 if (BC_ERROR_SIGNAL_ONLY(s)) return s;
972
973 return bc_num_shiftLeft(b, pow);
974 }
975
bc_num_d_long(BcNum * restrict a,BcNum * restrict b,BcNum * restrict c,size_t scale)976 static BcStatus bc_num_d_long(BcNum *restrict a, BcNum *restrict b,
977 BcNum *restrict c, size_t scale)
978 {
979 BcStatus s = BC_STATUS_SUCCESS;
980 BcBigDig divisor;
981 size_t len, end, i, rdx;
982 BcNum cpb;
983 bool nonzero = false;
984
985 assert(b->len < a->len);
986 len = b->len;
987 end = a->len - len;
988 assert(len >= 1);
989
990 bc_num_expand(c, a->len);
991 memset(c->num, 0, c->cap * sizeof(BcDig));
992
993 c->rdx = a->rdx;
994 c->scale = a->scale;
995 c->len = a->len;
996
997 divisor = (BcBigDig) b->num[len - 1];
998
999 if (len > 1 && bc_num_nonZeroDig(b->num, len - 1)) {
1000
1001 nonzero = (divisor > 1 << ((10 * BC_BASE_DIGS) / 6 + 1));
1002
1003 if (!nonzero) {
1004
1005 s = bc_num_divExtend(a, b, divisor);
1006 if (BC_ERROR_SIGNAL_ONLY(s)) return s;
1007
1008 len = BC_MAX(a->len, b->len);
1009 bc_num_expand(a, len + 1);
1010
1011 if (len + 1 > a->len) a->len = len + 1;
1012
1013 len = b->len;
1014 end = a->len - len;
1015 divisor = (BcBigDig) b->num[len - 1];
1016
1017 nonzero = bc_num_nonZeroDig(b->num, len - 1);
1018 }
1019 }
1020
1021 divisor += nonzero;
1022
1023 bc_num_expand(c, a->len);
1024 memset(c->num, 0, BC_NUM_SIZE(c->cap));
1025
1026 assert(c->scale >= scale);
1027 rdx = c->rdx - BC_NUM_RDX(scale);
1028
1029 bc_num_init(&cpb, len + 1);
1030
1031 i = end - 1;
1032
1033 for (; BC_NO_SIG && i < end && i >= rdx && BC_NUM_NONZERO(a); --i) {
1034
1035 ssize_t cmp;
1036 BcDig *n;
1037 BcBigDig q, result;
1038
1039 n = a->num + i;
1040 assert(n >= a->num);
1041 result = q = 0;
1042
1043 cmp = bc_num_divCmp(n, b, len);
1044
1045 #if BC_ENABLE_SIGNALS
1046 if (BC_NUM_CMP_SIGNAL(cmp)) goto err;
1047 #endif // BC_ENABLE_SIGNALS
1048
1049 while (cmp >= 0) {
1050
1051 BcBigDig n1, dividend;
1052
1053 n1 = (BcBigDig) n[len];
1054 dividend = n1 * BC_BASE_POW + (BcBigDig) n[len - 1];
1055 q = (dividend / divisor);
1056
1057 if (q <= 1) {
1058 q = 1;
1059 s = bc_num_subArrays(n, b->num, len);
1060 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1061 }
1062 else {
1063
1064 assert(q <= BC_BASE_POW);
1065
1066 s = bc_num_mulArray(b, (BcBigDig) q, &cpb);
1067 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1068
1069 s = bc_num_subArrays(n, cpb.num, cpb.len);
1070 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1071 }
1072
1073 result += q;
1074 assert(result <= BC_BASE_POW);
1075
1076 if (nonzero) {
1077 cmp = bc_num_divCmp(n, b, len);
1078 #if BC_ENABLE_SIGNALS
1079 if (BC_NUM_CMP_SIGNAL(cmp)) goto err;
1080 #endif // BC_ENABLE_SIGNALS
1081 }
1082 else cmp = -1;
1083 }
1084
1085 assert(result < BC_BASE_POW);
1086
1087 c->num[i] = (BcDig) result;
1088 }
1089
1090 err:
1091 if (BC_NO_ERR(!s) && BC_SIG) s = BC_STATUS_SIGNAL;
1092 bc_num_free(&cpb);
1093 return s;
1094 }
1095
bc_num_d(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)1096 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) {
1097
1098 BcStatus s = BC_STATUS_SUCCESS;
1099 size_t len;
1100 BcNum cpa, cpb;
1101
1102 if (BC_NUM_ZERO(b)) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO);
1103 if (BC_NUM_ZERO(a)) {
1104 bc_num_setToZero(c, scale);
1105 return BC_STATUS_SUCCESS;
1106 }
1107 if (BC_NUM_ONE(b)) {
1108 bc_num_copy(c, a);
1109 bc_num_retireMul(c, scale, a->neg, b->neg);
1110 return BC_STATUS_SUCCESS;
1111 }
1112 if (!a->rdx && !b->rdx && b->len == 1 && !scale) {
1113 BcBigDig rem;
1114 s = bc_num_divArray(a, (BcBigDig) b->num[0], c, &rem);
1115 bc_num_retireMul(c, scale, a->neg, b->neg);
1116 return s;
1117 }
1118
1119 len = bc_num_mulReq(a, b, scale);
1120 bc_num_init(&cpa, len);
1121 bc_num_copy(&cpa, a);
1122 bc_num_createCopy(&cpb, b);
1123
1124 len = b->len;
1125
1126 if (len > cpa.len) {
1127 bc_num_expand(&cpa, bc_vm_growSize(len, 2));
1128 bc_num_extend(&cpa, (len - cpa.len) * BC_BASE_DIGS);
1129 }
1130
1131 cpa.scale = cpa.rdx * BC_BASE_DIGS;
1132
1133 bc_num_extend(&cpa, b->scale);
1134 cpa.rdx -= BC_NUM_RDX(b->scale);
1135 cpa.scale = cpa.rdx * BC_BASE_DIGS;
1136
1137 if (scale > cpa.scale) {
1138 bc_num_extend(&cpa, scale);
1139 cpa.scale = cpa.rdx * BC_BASE_DIGS;
1140 }
1141
1142 if (cpa.cap == cpa.len) bc_num_expand(&cpa, bc_vm_growSize(cpa.len, 1));
1143
1144 // We want an extra zero in front to make things simpler.
1145 cpa.num[cpa.len++] = 0;
1146
1147 if (cpa.rdx == cpa.len) cpa.len = bc_num_nonzeroLen(&cpa);
1148 if (cpb.rdx == cpb.len) cpb.len = bc_num_nonzeroLen(&cpb);
1149 cpb.scale = cpb.rdx = 0;
1150
1151 s = bc_num_d_long(&cpa, &cpb, c, scale);
1152
1153 if (BC_NO_ERR(!s)) {
1154 if (BC_SIG) s = BC_STATUS_SIGNAL;
1155 else bc_num_retireMul(c, scale, a->neg, b->neg);
1156 }
1157
1158 bc_num_free(&cpb);
1159 bc_num_free(&cpa);
1160
1161 return s;
1162 }
1163
bc_num_r(BcNum * a,BcNum * b,BcNum * restrict c,BcNum * restrict d,size_t scale,size_t ts)1164 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1165 BcNum *restrict d, size_t scale, size_t ts)
1166 {
1167 BcStatus s;
1168 BcNum temp;
1169 bool neg;
1170
1171 if (BC_NUM_ZERO(b)) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO);
1172 if (BC_NUM_ZERO(a)) {
1173 bc_num_setToZero(c, ts);
1174 bc_num_setToZero(d, ts);
1175 return BC_STATUS_SUCCESS;
1176 }
1177
1178 bc_num_init(&temp, d->cap);
1179 s = bc_num_d(a, b, c, scale);
1180 assert(!s || s == BC_STATUS_SIGNAL);
1181 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1182
1183 if (scale) scale = ts + 1;
1184
1185 s = bc_num_m(c, b, &temp, scale);
1186 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1187 s = bc_num_sub(a, &temp, d, scale);
1188 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1189
1190 if (ts > d->scale && BC_NUM_NONZERO(d)) bc_num_extend(d, ts - d->scale);
1191
1192 neg = d->neg;
1193 bc_num_retireMul(d, ts, a->neg, b->neg);
1194 d->neg = BC_NUM_NONZERO(d) ? neg : false;
1195
1196 err:
1197 bc_num_free(&temp);
1198 return s;
1199 }
1200
bc_num_rem(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)1201 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1202 {
1203 BcStatus s;
1204 BcNum c1;
1205 size_t ts;
1206
1207 ts = bc_vm_growSize(scale, b->scale);
1208 ts = BC_MAX(ts, a->scale);
1209
1210 bc_num_init(&c1, bc_num_mulReq(a, b, ts));
1211 s = bc_num_r(a, b, &c1, c, scale, ts);
1212 bc_num_free(&c1);
1213
1214 return s;
1215 }
1216
bc_num_p(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)1217 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) {
1218
1219 BcStatus s = BC_STATUS_SUCCESS;
1220 BcNum copy;
1221 BcBigDig pow = 0;
1222 size_t i, powrdx, resrdx;
1223 bool neg, zero;
1224
1225 if (BC_ERR(b->rdx)) return bc_vm_err(BC_ERROR_MATH_NON_INTEGER);
1226
1227 if (BC_NUM_ZERO(b)) {
1228 bc_num_one(c);
1229 return BC_STATUS_SUCCESS;
1230 }
1231 if (BC_NUM_ZERO(a)) {
1232 if (b->neg) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO);
1233 bc_num_setToZero(c, scale);
1234 return BC_STATUS_SUCCESS;
1235 }
1236 if (BC_NUM_ONE(b)) {
1237 if (!b->neg) bc_num_copy(c, a);
1238 else s = bc_num_inv(a, c, scale);
1239 return s;
1240 }
1241
1242 neg = b->neg;
1243 b->neg = false;
1244 s = bc_num_bigdig(b, &pow);
1245 b->neg = neg;
1246 if (s) return s;
1247
1248 bc_num_createCopy(©, a);
1249
1250 if (!neg) {
1251 size_t max = BC_MAX(scale, a->scale), scalepow = a->scale * pow;
1252 scale = BC_MIN(scalepow, max);
1253 }
1254
1255 for (powrdx = a->scale; BC_NO_SIG && !(pow & 1); pow >>= 1) {
1256 powrdx <<= 1;
1257 s = bc_num_mul(©, ©, ©, powrdx);
1258 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1259 }
1260
1261 if (BC_SIG) goto sig_err;
1262
1263 bc_num_copy(c, ©);
1264 resrdx = powrdx;
1265
1266 while (BC_NO_SIG && (pow >>= 1)) {
1267
1268 powrdx <<= 1;
1269 s = bc_num_mul(©, ©, ©, powrdx);
1270 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1271
1272 if (pow & 1) {
1273 resrdx += powrdx;
1274 s = bc_num_mul(c, ©, c, resrdx);
1275 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1276 }
1277 }
1278
1279 if (BC_SIG) goto sig_err;
1280 if (neg) {
1281 s = bc_num_inv(c, c, scale);
1282 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1283 }
1284
1285 if (c->scale > scale) bc_num_truncate(c, c->scale - scale);
1286
1287 // We can't use bc_num_clean() here.
1288 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1289 if (zero) bc_num_setToZero(c, scale);
1290
1291 sig_err:
1292 if (BC_NO_ERR(!s) && BC_SIG) s = BC_STATUS_SIGNAL;
1293 err:
1294 bc_num_free(©);
1295 return s;
1296 }
1297
1298 #if BC_ENABLE_EXTRA_MATH
bc_num_place(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)1299 static BcStatus bc_num_place(BcNum *a, BcNum *b, BcNum *restrict c,
1300 size_t scale)
1301 {
1302 BcStatus s = BC_STATUS_SUCCESS;
1303 BcBigDig val = 0;
1304
1305 BC_UNUSED(scale);
1306
1307 s = bc_num_intop(a, b, c, &val);
1308 if (BC_ERR(s)) return s;
1309
1310 if (val < c->scale) bc_num_truncate(c, c->scale - val);
1311 else if (val > c->scale) bc_num_extend(c, val - c->scale);
1312
1313 return s;
1314 }
1315
bc_num_left(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)1316 static BcStatus bc_num_left(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1317 {
1318 BcStatus s = BC_STATUS_SUCCESS;
1319 BcBigDig val = 0;
1320
1321 BC_UNUSED(scale);
1322
1323 s = bc_num_intop(a, b, c, &val);
1324 if (BC_ERR(s)) return s;
1325
1326 return bc_num_shiftLeft(c, (size_t) val);
1327 }
1328
bc_num_right(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)1329 static BcStatus bc_num_right(BcNum *a, BcNum *b, BcNum *restrict c,
1330 size_t scale)
1331 {
1332 BcStatus s = BC_STATUS_SUCCESS;
1333 BcBigDig val = 0;
1334
1335 BC_UNUSED(scale);
1336
1337 s = bc_num_intop(a, b, c, &val);
1338 if (BC_ERR(s)) return s;
1339
1340 if (BC_NUM_ZERO(c)) return s;
1341
1342 return bc_num_shiftRight(c, (size_t) val);
1343 }
1344 #endif // BC_ENABLE_EXTRA_MATH
1345
bc_num_binary(BcNum * a,BcNum * b,BcNum * c,size_t scale,BcNumBinaryOp op,size_t req)1346 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1347 BcNumBinaryOp op, size_t req)
1348 {
1349 BcStatus s;
1350 BcNum num2, *ptr_a, *ptr_b;
1351 bool init = false;
1352
1353 assert(a != NULL && b != NULL && c != NULL && op != NULL);
1354
1355 if (c == a) {
1356 ptr_a = &num2;
1357 memcpy(ptr_a, c, sizeof(BcNum));
1358 init = true;
1359 }
1360 else ptr_a = a;
1361
1362 if (c == b) {
1363 ptr_b = &num2;
1364 if (c != a) {
1365 memcpy(ptr_b, c, sizeof(BcNum));
1366 init = true;
1367 }
1368 }
1369 else ptr_b = b;
1370
1371 if (init) bc_num_init(c, req);
1372 else bc_num_expand(c, req);
1373
1374 s = op(ptr_a, ptr_b, c, scale);
1375
1376 assert(!c->neg || BC_NUM_NONZERO(c));
1377 assert(c->rdx <= c->len || !c->len || s);
1378 assert(!c->len || c->num[c->len - 1] || c->rdx == c->len);
1379
1380 if (init) bc_num_free(&num2);
1381
1382 return s;
1383 }
1384
1385 #ifndef NDEBUG
bc_num_strValid(const char * val)1386 static bool bc_num_strValid(const char *val) {
1387
1388 bool radix = false;
1389 size_t i, len = strlen(val);
1390
1391 if (!len) return true;
1392
1393 for (i = 0; i < len; ++i) {
1394
1395 BcDig c = val[i];
1396
1397 if (c == '.') {
1398
1399 if (radix) return false;
1400
1401 radix = true;
1402 continue;
1403 }
1404
1405 if (!(isdigit(c) || isupper(c))) return false;
1406 }
1407
1408 return true;
1409 }
1410 #endif // NDEBUG
1411
bc_num_parseChar(char c,size_t base_t)1412 static BcBigDig bc_num_parseChar(char c, size_t base_t) {
1413
1414 if (isupper(c)) {
1415 c = BC_NUM_NUM_LETTER(c);
1416 c = ((size_t) c) >= base_t ? (char) base_t - 1 : c;
1417 }
1418 else c -= '0';
1419
1420 return (BcBigDig) (uchar) c;
1421 }
1422
bc_num_parseDecimal(BcNum * restrict n,const char * restrict val)1423 static void bc_num_parseDecimal(BcNum *restrict n, const char *restrict val) {
1424
1425 size_t len, i, temp, mod;
1426 const char *ptr;
1427 bool zero = true, rdx;
1428
1429 for (i = 0; val[i] == '0'; ++i);
1430
1431 val += i;
1432 assert(!val[0] || isalnum(val[0]) || val[0] == '.');
1433
1434 // All 0's. We can just return, since this
1435 // procedure expects a virgin (already 0) BcNum.
1436 if (!val[0]) return;
1437
1438 len = strlen(val);
1439
1440 ptr = strchr(val, '.');
1441 rdx = (ptr != NULL);
1442
1443 for (i = 0; i < len && (zero = (val[i] == '0' || val[i] == '.')); ++i);
1444
1445 n->scale = (size_t) (rdx * ((val + len) - (ptr + 1)));
1446 n->rdx = BC_NUM_RDX(n->scale);
1447
1448 i = len - (ptr == val ? 0 : i) - rdx;
1449 temp = BC_NUM_ROUND_POW(i);
1450 mod = n->scale % BC_BASE_DIGS;
1451 i = mod ? BC_BASE_DIGS - mod : 0;
1452 n->len = ((temp + i) / BC_BASE_DIGS);
1453
1454 bc_num_expand(n, n->len);
1455 memset(n->num, 0, BC_NUM_SIZE(n->len));
1456
1457 if (zero) n->len = n->rdx = 0;
1458 else {
1459
1460 BcBigDig exp, pow;
1461
1462 assert(i <= BC_NUM_BIGDIG_MAX);
1463
1464 exp = (BcBigDig) i;
1465 pow = bc_num_pow10[exp];
1466
1467 for (i = len - 1; i < len; --i, ++exp) {
1468
1469 char c = val[i];
1470
1471 if (c == '.') exp -= 1;
1472 else {
1473
1474 size_t idx = exp / BC_BASE_DIGS;
1475
1476 if (isupper(c)) c = '9';
1477 n->num[idx] += (((BcBigDig) c) - '0') * pow;
1478
1479 if ((exp + 1) % BC_BASE_DIGS == 0) pow = 1;
1480 else pow *= BC_BASE;
1481 }
1482 }
1483 }
1484 }
1485
bc_num_parseBase(BcNum * restrict n,const char * restrict val,BcBigDig base)1486 static BcStatus bc_num_parseBase(BcNum *restrict n, const char *restrict val,
1487 BcBigDig base)
1488 {
1489 BcStatus s = BC_STATUS_SUCCESS;
1490 BcNum temp, mult1, mult2, result1, result2, *m1, *m2, *ptr;
1491 char c = 0;
1492 bool zero = true;
1493 BcBigDig v;
1494 size_t i, digs, len = strlen(val);
1495
1496 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
1497 if (zero) return BC_STATUS_SUCCESS;
1498
1499 bc_num_init(&temp, BC_NUM_BIGDIG_LOG10);
1500 bc_num_init(&mult1, BC_NUM_BIGDIG_LOG10);
1501
1502 for (i = 0; i < len && (c = val[i]) && c != '.'; ++i) {
1503
1504 v = bc_num_parseChar(c, base);
1505
1506 s = bc_num_mulArray(n, base, &mult1);
1507 if (BC_ERROR_SIGNAL_ONLY(s)) goto int_err;
1508 bc_num_bigdig2num(&temp, v);
1509 s = bc_num_add(&mult1, &temp, n, 0);
1510 if (BC_ERROR_SIGNAL_ONLY(s)) goto int_err;
1511 }
1512
1513 if (i == len && !(c = val[i])) goto int_err;
1514
1515 assert(c == '.');
1516 bc_num_init(&mult2, BC_NUM_BIGDIG_LOG10);
1517 bc_num_init(&result1, BC_NUM_DEF_SIZE);
1518 bc_num_init(&result2, BC_NUM_DEF_SIZE);
1519 bc_num_one(&mult1);
1520
1521 m1 = &mult1;
1522 m2 = &mult2;
1523
1524 for (i += 1, digs = 0; BC_NO_SIG && i < len && (c = val[i]); ++i, ++digs) {
1525
1526 v = bc_num_parseChar(c, base);
1527
1528 s = bc_num_mulArray(&result1, base, &result2);
1529 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1530
1531 bc_num_bigdig2num(&temp, v);
1532 s = bc_num_add(&result2, &temp, &result1, 0);
1533 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1534 s = bc_num_mulArray(m1, base, m2);
1535 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1536
1537 if (m2->len < m2->rdx) m2->len = m2->rdx;
1538
1539 ptr = m1;
1540 m1 = m2;
1541 m2 = ptr;
1542 }
1543
1544 if (BC_SIG) {
1545 s = BC_STATUS_SIGNAL;
1546 goto err;
1547 }
1548
1549 // This one cannot be a divide by 0 because mult starts out at 1, then is
1550 // multiplied by base, and base cannot be 0, so mult cannot be 0.
1551 s = bc_num_div(&result1, m1, &result2, digs * 2);
1552 assert(!s || s == BC_STATUS_SIGNAL);
1553 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1554 bc_num_truncate(&result2, digs);
1555 s = bc_num_add(n, &result2, n, digs);
1556 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1557
1558 if (BC_NUM_NONZERO(n)) {
1559 if (n->scale < digs) bc_num_extend(n, digs - n->scale);
1560 }
1561 else bc_num_zero(n);
1562
1563 err:
1564 bc_num_free(&result2);
1565 bc_num_free(&result1);
1566 bc_num_free(&mult2);
1567 int_err:
1568 bc_num_free(&mult1);
1569 bc_num_free(&temp);
1570 return s;
1571 }
1572
bc_num_printNewline(void)1573 static void bc_num_printNewline(void) {
1574 if (vm->nchars >= (size_t) (vm->line_len - 1)) {
1575 bc_vm_putchar('\\');
1576 bc_vm_putchar('\n');
1577 }
1578 }
1579
bc_num_putchar(int c)1580 static void bc_num_putchar(int c) {
1581 if (c != '\n') bc_num_printNewline();
1582 bc_vm_putchar(c);
1583 }
1584
1585 #if DC_ENABLED
bc_num_printChar(size_t n,size_t len,bool rdx)1586 static void bc_num_printChar(size_t n, size_t len, bool rdx) {
1587 BC_UNUSED(rdx);
1588 BC_UNUSED(len);
1589 assert(len == 1);
1590 bc_vm_putchar((uchar) n);
1591 }
1592 #endif // DC_ENABLED
1593
bc_num_printDigits(size_t n,size_t len,bool rdx)1594 static void bc_num_printDigits(size_t n, size_t len, bool rdx) {
1595
1596 size_t exp, pow;
1597
1598 bc_num_putchar(rdx ? '.' : ' ');
1599
1600 for (exp = 0, pow = 1; exp < len - 1; ++exp, pow *= BC_BASE);
1601
1602 for (exp = 0; exp < len; pow /= BC_BASE, ++exp) {
1603 size_t dig = n / pow;
1604 n -= dig * pow;
1605 bc_num_putchar(((uchar) dig) + '0');
1606 }
1607 }
1608
bc_num_printHex(size_t n,size_t len,bool rdx)1609 static void bc_num_printHex(size_t n, size_t len, bool rdx) {
1610
1611 BC_UNUSED(len);
1612
1613 assert(len == 1);
1614
1615 if (rdx) bc_num_putchar('.');
1616
1617 bc_num_putchar(bc_num_hex_digits[n]);
1618 }
1619
bc_num_printDecimal(const BcNum * restrict n)1620 static void bc_num_printDecimal(const BcNum *restrict n) {
1621
1622 size_t i, j, rdx = n->rdx;
1623 bool zero = true;
1624 size_t buffer[BC_BASE_DIGS];
1625
1626 if (n->neg) bc_num_putchar('-');
1627
1628 for (i = n->len - 1; i < n->len; --i) {
1629
1630 BcDig n9 = n->num[i];
1631 size_t temp;
1632 bool irdx = (i == rdx - 1);
1633
1634 zero = (zero & !irdx);
1635 temp = n->scale % BC_BASE_DIGS;
1636 temp = i || !temp ? 0 : BC_BASE_DIGS - temp;
1637
1638 memset(buffer, 0, BC_BASE_DIGS * sizeof(size_t));
1639
1640 for (j = 0; n9 && j < BC_BASE_DIGS; ++j) {
1641 buffer[j] = n9 % BC_BASE;
1642 n9 /= BC_BASE;
1643 }
1644
1645 for (j = BC_BASE_DIGS - 1; j < BC_BASE_DIGS && j >= temp; --j) {
1646 bool print_rdx = (irdx & (j == BC_BASE_DIGS - 1));
1647 zero = (zero && buffer[j] == 0);
1648 if (!zero) bc_num_printHex(buffer[j], 1, print_rdx);
1649 }
1650 }
1651 }
1652
1653 #if BC_ENABLE_EXTRA_MATH
bc_num_printExponent(const BcNum * restrict n,bool eng)1654 static BcStatus bc_num_printExponent(const BcNum *restrict n, bool eng) {
1655
1656 BcStatus s = BC_STATUS_SUCCESS;
1657 bool neg = (n->len <= n->rdx);
1658 BcNum temp, exp;
1659 size_t places, mod;
1660 BcDig digs[BC_NUM_BIGDIG_LOG10];
1661
1662 bc_num_createCopy(&temp, n);
1663
1664 if (neg) {
1665
1666 size_t i, idx = bc_num_nonzeroLen(n) - 1;
1667
1668 places = 1;
1669
1670 for (i = BC_BASE_DIGS - 1; i < BC_BASE_DIGS; --i) {
1671 if (bc_num_pow10[i] > (BcBigDig) n->num[idx]) places += 1;
1672 else break;
1673 }
1674
1675 places += (n->rdx - (idx + 1)) * BC_BASE_DIGS;
1676 mod = places % 3;
1677
1678 if (eng && mod != 0) places += 3 - mod;
1679 s = bc_num_shiftLeft(&temp, places);
1680 if (BC_ERROR_SIGNAL_ONLY(s)) goto exit;
1681 }
1682 else {
1683 places = bc_num_intDigits(n) - 1;
1684 mod = places % 3;
1685 if (eng && mod != 0) places -= 3 - (3 - mod);
1686 s = bc_num_shiftRight(&temp, places);
1687 if (BC_ERROR_SIGNAL_ONLY(s)) goto exit;
1688 }
1689
1690 bc_num_printDecimal(&temp);
1691 bc_num_putchar('e');
1692
1693 if (!places) {
1694 bc_num_printHex(0, 1, false);
1695 goto exit;
1696 }
1697
1698 if (neg) bc_num_putchar('-');
1699
1700 bc_num_setup(&exp, digs, BC_NUM_BIGDIG_LOG10);
1701 bc_num_bigdig2num(&exp, (BcBigDig) places);
1702
1703 bc_num_printDecimal(&exp);
1704
1705 exit:
1706 bc_num_free(&temp);
1707 return BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1708 }
1709 #endif // BC_ENABLE_EXTRA_MATH
1710
bc_num_printFixup(BcNum * restrict n,BcBigDig rem,BcBigDig pow,size_t idx)1711 static BcStatus bc_num_printFixup(BcNum *restrict n, BcBigDig rem,
1712 BcBigDig pow, size_t idx)
1713 {
1714 size_t i, len = n->len - idx;
1715 BcBigDig acc;
1716 BcDig *a = n->num + idx;
1717
1718 if (len < 2) return BC_STATUS_SUCCESS;
1719
1720 for (i = len - 1; BC_NO_SIG && i > 0; --i) {
1721
1722 acc = ((BcBigDig) a[i]) * rem + ((BcBigDig) a[i - 1]);
1723 a[i - 1] = (BcDig) (acc % pow);
1724 acc /= pow;
1725 acc += (BcBigDig) a[i];
1726
1727 if (acc >= BC_BASE_POW) {
1728
1729 if (i == len - 1) {
1730 len = bc_vm_growSize(len, 1);
1731 bc_num_expand(n, bc_vm_growSize(len, idx));
1732 a = n->num + idx;
1733 a[len - 1] = 0;
1734 }
1735
1736 a[i + 1] += acc / BC_BASE_POW;
1737 acc %= BC_BASE_POW;
1738 }
1739
1740 assert(acc < BC_BASE_POW);
1741 a[i] = (BcDig) acc;
1742 }
1743
1744 n->len = len + idx;
1745
1746 return BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1747 }
1748
bc_num_printPrepare(BcNum * restrict n,BcBigDig rem,BcBigDig pow)1749 static BcStatus bc_num_printPrepare(BcNum *restrict n, BcBigDig rem,
1750 BcBigDig pow)
1751 {
1752 BcStatus s = BC_STATUS_SUCCESS;
1753 size_t i;
1754
1755 for (i = 0; BC_NO_SIG && BC_NO_ERR(!s) && i < n->len; ++i)
1756 s = bc_num_printFixup(n, rem, pow, i);
1757
1758 if (BC_ERR(s)) return s;
1759
1760 for (i = 0; BC_NO_SIG && i < n->len; ++i) {
1761
1762 assert(pow == ((BcBigDig) ((BcDig) pow)));
1763
1764 if (n->num[i] >= (BcDig) pow) {
1765
1766 if (i + 1 == n->len) {
1767 n->len = bc_vm_growSize(n->len, 1);
1768 bc_num_expand(n, n->len);
1769 n->num[i + 1] = 0;
1770 }
1771
1772 assert(pow < BC_BASE_POW);
1773 n->num[i + 1] += n->num[i] / ((BcDig) pow);
1774 n->num[i] %= (BcDig) pow;
1775 }
1776 }
1777
1778 return BC_NO_ERR(!s) && BC_SIG ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1779 }
1780
bc_num_printNum(BcNum * restrict n,BcBigDig base,size_t len,BcNumDigitOp print)1781 static BcStatus bc_num_printNum(BcNum *restrict n, BcBigDig base,
1782 size_t len, BcNumDigitOp print)
1783 {
1784 BcStatus s;
1785 BcVec stack;
1786 BcNum intp, fracp1, fracp2, digit, flen1, flen2, *n1, *n2, *temp;
1787 BcBigDig dig = 0, *ptr, acc, exp;
1788 size_t i, j;
1789 bool radix;
1790 BcDig digit_digs[BC_NUM_BIGDIG_LOG10 + 1];
1791
1792 assert(base > 1);
1793
1794 if (BC_NUM_ZERO(n)) {
1795 print(0, len, false);
1796 return BC_STATUS_SUCCESS;
1797 }
1798
1799 // This function uses an algorithm that Stefan Esser <se@freebsd.org> came
1800 // up with to print the integer part of a number. What it does is convert
1801 // intp into a number of the specified base, but it does it directly,
1802 // instead of just doing a series of divisions and printing the remainders
1803 // in reverse order.
1804 //
1805 // Let me explain in a bit more detail:
1806 //
1807 // The algorithm takes the current least significant digit (after intp has
1808 // been converted to an integer) and the next to least significant digit,
1809 // and it converts the least significant digit into one of the specified
1810 // base, putting any overflow into the next to least significant digit. It
1811 // iterates through the whole number, from least significant to most
1812 // significant, doing this conversion. At the end of that iteration, the
1813 // least significant digit is converted, but the others are not, so it
1814 // iterates again, starting at the next to least significant digit. It keeps
1815 // doing that conversion, skipping one more digit than the last time, until
1816 // all digits have been converted. Then it prints them in reverse order.
1817 //
1818 // That is the gist of the algorithm. It leaves out several things, such as
1819 // the fact that digits are not always converted into the specified base,
1820 // but into something close, basically a power of the specified base. In
1821 // Stefan's words, "You could consider BcDigs to be of base 10^BC_BASE_DIGS
1822 // in the normal case and obase^N for the largest value of N that satisfies
1823 // obase^N <= 10^BC_BASE_DIGS. [This means that] the result is not in base
1824 // "obase", but in base "obase^N", which happens to be printable as a number
1825 // of base "obase" without consideration for neighbouring BcDigs." This fact
1826 // is what necessitates the existence of the loop later in this function.
1827 //
1828 // The conversion happens in bc_num_printPrepare() where the outer loop
1829 // happens and bc_num_printFixup() where the inner loop, or actual
1830 // conversion, happens.
1831
1832 bc_vec_init(&stack, sizeof(BcBigDig), NULL);
1833 bc_num_init(&fracp1, n->rdx);
1834
1835 bc_num_createCopy(&intp, n);
1836 bc_num_truncate(&intp, intp.scale);
1837
1838 s = bc_num_sub(n, &intp, &fracp1, 0);
1839 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1840
1841 if (base != vm->last_base) {
1842
1843 vm->last_pow = 1;
1844 vm->last_exp = 0;
1845
1846 while (vm->last_pow * base <= BC_BASE_POW) {
1847 vm->last_pow *= base;
1848 vm->last_exp += 1;
1849 }
1850
1851 vm->last_rem = BC_BASE_POW - vm->last_pow;
1852 vm->last_base = base;
1853 }
1854
1855 exp = vm->last_exp;
1856
1857 if (vm->last_rem != 0) {
1858 s = bc_num_printPrepare(&intp, vm->last_rem, vm->last_pow);
1859 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
1860 }
1861
1862 for (i = 0; BC_NO_SIG && i < intp.len; ++i) {
1863
1864 acc = (BcBigDig) intp.num[i];
1865
1866 for (j = 0; BC_NO_SIG && j < exp && (i < intp.len - 1 || acc != 0); ++j)
1867 {
1868 if (j != exp - 1) {
1869 dig = acc % base;
1870 acc /= base;
1871 }
1872 else {
1873 dig = acc;
1874 acc = 0;
1875 }
1876
1877 assert(dig < base);
1878
1879 bc_vec_push(&stack, &dig);
1880 }
1881
1882 assert(acc == 0 || BC_SIG);
1883 }
1884
1885 if (BC_SIG) goto sig_err;
1886
1887 for (i = 0; BC_NO_SIG && i < stack.len; ++i) {
1888 ptr = bc_vec_item_rev(&stack, i);
1889 assert(ptr != NULL);
1890 print(*ptr, len, false);
1891 }
1892
1893 if (BC_SIG) goto sig_err;
1894 if (!n->scale) goto err;
1895
1896 bc_num_init(&fracp2, n->rdx);
1897 bc_num_setup(&digit, digit_digs, sizeof(digit_digs) / sizeof(BcDig));
1898 bc_num_init(&flen1, BC_NUM_BIGDIG_LOG10 + 1);
1899 bc_num_init(&flen2, BC_NUM_BIGDIG_LOG10 + 1);
1900 bc_num_one(&flen1);
1901
1902 radix = true;
1903 n1 = &flen1;
1904 n2 = &flen2;
1905
1906 fracp2.scale = n->scale;
1907 fracp2.rdx = BC_NUM_RDX(fracp2.scale);
1908
1909 while (BC_NO_SIG && bc_num_intDigits(n1) < n->scale + 1) {
1910
1911 bc_num_expand(&fracp2, fracp1.len + 1);
1912 s = bc_num_mulArray(&fracp1, base, &fracp2);
1913 if (BC_ERROR_SIGNAL_ONLY(s)) goto frac_err;
1914 if (fracp2.len < fracp2.rdx) fracp2.len = fracp2.rdx;
1915
1916 // Will never fail (except for signals) because fracp is
1917 // guaranteed to be non-negative and small enough.
1918 s = bc_num_bigdig(&fracp2, &dig);
1919 if (BC_ERROR_SIGNAL_ONLY(s)) goto frac_err;
1920
1921 bc_num_bigdig2num(&digit, dig);
1922 s = bc_num_sub(&fracp2, &digit, &fracp1, 0);
1923 if (BC_ERROR_SIGNAL_ONLY(s)) goto frac_err;
1924
1925 print(dig, len, radix);
1926 s = bc_num_mulArray(n1, base, n2);
1927 if (BC_ERROR_SIGNAL_ONLY(s)) goto frac_err;
1928
1929 radix = false;
1930 temp = n1;
1931 n1 = n2;
1932 n2 = temp;
1933 }
1934
1935 frac_err:
1936 bc_num_free(&flen2);
1937 bc_num_free(&flen1);
1938 bc_num_free(&fracp2);
1939 sig_err:
1940 if (BC_NO_ERR(!s) && BC_SIG) s = BC_STATUS_SIGNAL;
1941 err:
1942 bc_num_free(&fracp1);
1943 bc_num_free(&intp);
1944 bc_vec_free(&stack);
1945 return s;
1946 }
1947
bc_num_printBase(BcNum * restrict n,BcBigDig base)1948 static BcStatus bc_num_printBase(BcNum *restrict n, BcBigDig base) {
1949
1950 BcStatus s;
1951 size_t width;
1952 BcNumDigitOp print;
1953 bool neg = n->neg;
1954
1955 if (neg) bc_num_putchar('-');
1956
1957 n->neg = false;
1958
1959 if (base <= BC_NUM_MAX_POSIX_IBASE) {
1960 width = 1;
1961 print = bc_num_printHex;
1962 }
1963 else {
1964 width = bc_num_log10(base - 1);
1965 print = bc_num_printDigits;
1966 }
1967
1968 s = bc_num_printNum(n, base, width, print);
1969 n->neg = neg;
1970
1971 return s;
1972 }
1973
1974 #if DC_ENABLED
bc_num_stream(BcNum * restrict n,BcBigDig base)1975 BcStatus bc_num_stream(BcNum *restrict n, BcBigDig base) {
1976 return bc_num_printNum(n, base, 1, bc_num_printChar);
1977 }
1978 #endif // DC_ENABLED
1979
bc_num_setup(BcNum * restrict n,BcDig * restrict num,size_t cap)1980 void bc_num_setup(BcNum *restrict n, BcDig *restrict num, size_t cap) {
1981 assert(n != NULL);
1982 n->num = num;
1983 n->cap = cap;
1984 bc_num_zero(n);
1985 }
1986
bc_num_init(BcNum * restrict n,size_t req)1987 void bc_num_init(BcNum *restrict n, size_t req) {
1988 assert(n != NULL);
1989 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
1990 bc_num_setup(n, bc_vm_malloc(BC_NUM_SIZE(req)), req);
1991 }
1992
bc_num_free(void * num)1993 void bc_num_free(void *num) {
1994 assert(num != NULL);
1995 free(((BcNum*) num)->num);
1996 }
1997
bc_num_copy(BcNum * d,const BcNum * s)1998 void bc_num_copy(BcNum *d, const BcNum *s) {
1999 assert(d != NULL && s != NULL);
2000 if (d == s) return;
2001 bc_num_expand(d, s->len);
2002 d->len = s->len;
2003 d->neg = s->neg;
2004 d->rdx = s->rdx;
2005 d->scale = s->scale;
2006 memcpy(d->num, s->num, BC_NUM_SIZE(d->len));
2007 }
2008
bc_num_createCopy(BcNum * d,const BcNum * s)2009 void bc_num_createCopy(BcNum *d, const BcNum *s) {
2010 bc_num_init(d, s->len);
2011 bc_num_copy(d, s);
2012 }
2013
bc_num_createFromBigdig(BcNum * n,BcBigDig val)2014 void bc_num_createFromBigdig(BcNum *n, BcBigDig val) {
2015 bc_num_init(n, (BC_NUM_BIGDIG_LOG10 - 1) / BC_BASE_DIGS + 1);
2016 bc_num_bigdig2num(n, val);
2017 }
2018
bc_num_scale(const BcNum * restrict n)2019 size_t bc_num_scale(const BcNum *restrict n) {
2020 return n->scale;
2021 }
2022
bc_num_len(const BcNum * restrict n)2023 size_t bc_num_len(const BcNum *restrict n) {
2024
2025 size_t len = n->len;
2026
2027 if (BC_NUM_ZERO(n)) return 0;
2028
2029 if (n->rdx == len) {
2030
2031 size_t zero, scale;
2032
2033 len = bc_num_nonzeroLen(n);
2034
2035 scale = n->scale % BC_BASE_DIGS;
2036 scale = scale ? scale : BC_BASE_DIGS;
2037
2038 zero = bc_num_zeroDigits(n->num + len - 1);
2039
2040 len = len * BC_BASE_DIGS - zero - (BC_BASE_DIGS - scale);
2041 }
2042 else len = bc_num_intDigits(n) + n->scale;
2043
2044 return len;
2045 }
2046
bc_num_parse(BcNum * restrict n,const char * restrict val,BcBigDig base,bool letter)2047 BcStatus bc_num_parse(BcNum *restrict n, const char *restrict val,
2048 BcBigDig base, bool letter)
2049 {
2050 BcStatus s = BC_STATUS_SUCCESS;
2051
2052 assert(n != NULL && val != NULL && base);
2053 assert(base >= BC_NUM_MIN_BASE && base <= vm->maxes[BC_PROG_GLOBALS_IBASE]);
2054 assert(bc_num_strValid(val));
2055
2056 if (letter) {
2057 BcBigDig dig = bc_num_parseChar(val[0], BC_NUM_MAX_LBASE);
2058 bc_num_bigdig2num(n, dig);
2059 }
2060 else if (base == BC_BASE) bc_num_parseDecimal(n, val);
2061 else s = bc_num_parseBase(n, val, base);
2062
2063 return s;
2064 }
2065
bc_num_print(BcNum * restrict n,BcBigDig base,bool newline)2066 BcStatus bc_num_print(BcNum *restrict n, BcBigDig base, bool newline) {
2067
2068 BcStatus s = BC_STATUS_SUCCESS;
2069
2070 assert(n != NULL);
2071 assert(BC_ENABLE_EXTRA_MATH || base >= BC_NUM_MIN_BASE);
2072
2073 bc_num_printNewline();
2074
2075 if (BC_NUM_ZERO(n)) bc_num_printHex(0, 1, false);
2076 else if (base == BC_BASE) bc_num_printDecimal(n);
2077 #if BC_ENABLE_EXTRA_MATH
2078 else if (base == 0 || base == 1)
2079 s = bc_num_printExponent(n, base != 0);
2080 #endif // BC_ENABLE_EXTRA_MATH
2081 else s = bc_num_printBase(n, base);
2082
2083 if (BC_NO_ERR(!s) && newline) bc_num_putchar('\n');
2084
2085 return s;
2086 }
2087
bc_num_bigdig(const BcNum * restrict n,BcBigDig * result)2088 BcStatus bc_num_bigdig(const BcNum *restrict n, BcBigDig *result) {
2089
2090 size_t i;
2091 BcBigDig r;
2092
2093 assert(n != NULL && result != NULL);
2094
2095 if (BC_ERR(n->neg)) return bc_vm_err(BC_ERROR_MATH_NEGATIVE);
2096
2097 for (r = 0, i = n->len; i > n->rdx;) {
2098
2099 BcBigDig prev = r * BC_BASE_POW;
2100
2101 if (BC_ERR(prev / BC_BASE_POW != r))
2102 return bc_vm_err(BC_ERROR_MATH_OVERFLOW);
2103
2104 r = prev + (BcBigDig) n->num[--i];
2105
2106 if (BC_ERR(r < prev)) return bc_vm_err(BC_ERROR_MATH_OVERFLOW);
2107 }
2108
2109 *result = r;
2110
2111 return BC_STATUS_SUCCESS;
2112 }
2113
bc_num_bigdig2num(BcNum * restrict n,BcBigDig val)2114 void bc_num_bigdig2num(BcNum *restrict n, BcBigDig val) {
2115
2116 BcDig *ptr;
2117 size_t i;
2118
2119 assert(n != NULL);
2120
2121 bc_num_zero(n);
2122
2123 if (!val) return;
2124
2125 bc_num_expand(n, BC_NUM_BIGDIG_LOG10);
2126
2127 for (ptr = n->num, i = 0; val; ++i, val /= BC_BASE_POW)
2128 ptr[i] = val % BC_BASE_POW;
2129
2130 n->len = i;
2131 }
2132
bc_num_addReq(const BcNum * a,const BcNum * b,size_t scale)2133 size_t bc_num_addReq(const BcNum *a, const BcNum *b, size_t scale) {
2134
2135 size_t aint, bint, ardx, brdx;
2136
2137 BC_UNUSED(scale);
2138
2139 ardx = a->rdx;
2140 aint = bc_num_int(a);
2141 assert(aint <= a->len && ardx <= a->len);
2142
2143 brdx = b->rdx;
2144 bint = bc_num_int(b);
2145 assert(bint <= b->len && brdx <= b->len);
2146
2147 ardx = BC_MAX(ardx, brdx);
2148 aint = BC_MAX(aint, bint);
2149
2150 return bc_vm_growSize(bc_vm_growSize(ardx, aint), 1);
2151 }
2152
bc_num_mulReq(const BcNum * a,const BcNum * b,size_t scale)2153 size_t bc_num_mulReq(const BcNum *a, const BcNum *b, size_t scale) {
2154 size_t max, rdx;
2155 rdx = bc_vm_growSize(a->rdx, b->rdx);
2156 max = BC_NUM_RDX(scale);
2157 max = bc_vm_growSize(BC_MAX(max, rdx), 1);
2158 rdx = bc_vm_growSize(bc_vm_growSize(bc_num_int(a), bc_num_int(b)), max);
2159 return rdx;
2160 }
2161
bc_num_powReq(const BcNum * a,const BcNum * b,size_t scale)2162 size_t bc_num_powReq(const BcNum *a, const BcNum *b, size_t scale) {
2163 BC_UNUSED(scale);
2164 return bc_vm_growSize(bc_vm_growSize(a->len, b->len), 1);
2165 }
2166
2167 #if BC_ENABLE_EXTRA_MATH
bc_num_placesReq(const BcNum * a,const BcNum * b,size_t scale)2168 size_t bc_num_placesReq(const BcNum *a, const BcNum *b, size_t scale) {
2169 BC_UNUSED(scale);
2170 return a->len + b->len - a->rdx - b->rdx;
2171 }
2172 #endif // BC_ENABLE_EXTRA_MATH
2173
bc_num_add(BcNum * a,BcNum * b,BcNum * c,size_t scale)2174 BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2175 return bc_num_binary(a, b, c, false, bc_num_as, bc_num_addReq(a, b, scale));
2176 }
2177
bc_num_sub(BcNum * a,BcNum * b,BcNum * c,size_t scale)2178 BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2179 return bc_num_binary(a, b, c, true, bc_num_as, bc_num_addReq(a, b, scale));
2180 }
2181
bc_num_mul(BcNum * a,BcNum * b,BcNum * c,size_t scale)2182 BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2183 return bc_num_binary(a, b, c, scale, bc_num_m, bc_num_mulReq(a, b, scale));
2184 }
2185
bc_num_div(BcNum * a,BcNum * b,BcNum * c,size_t scale)2186 BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2187 return bc_num_binary(a, b, c, scale, bc_num_d, bc_num_mulReq(a, b, scale));
2188 }
2189
bc_num_mod(BcNum * a,BcNum * b,BcNum * c,size_t scale)2190 BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2191 size_t req = bc_num_mulReq(a, b, scale);
2192 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2193 }
2194
bc_num_pow(BcNum * a,BcNum * b,BcNum * c,size_t scale)2195 BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2196 return bc_num_binary(a, b, c, scale, bc_num_p, bc_num_powReq(a, b, scale));
2197 }
2198
2199 #if BC_ENABLE_EXTRA_MATH
bc_num_places(BcNum * a,BcNum * b,BcNum * c,size_t scale)2200 BcStatus bc_num_places(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2201 size_t req = bc_num_placesReq(a, b, scale);
2202 return bc_num_binary(a, b, c, scale, bc_num_place, req);
2203 }
2204
bc_num_lshift(BcNum * a,BcNum * b,BcNum * c,size_t scale)2205 BcStatus bc_num_lshift(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2206 size_t req = bc_num_placesReq(a, b, scale);
2207 return bc_num_binary(a, b, c, scale, bc_num_left, req);
2208 }
2209
bc_num_rshift(BcNum * a,BcNum * b,BcNum * c,size_t scale)2210 BcStatus bc_num_rshift(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2211 size_t req = bc_num_placesReq(a, b, scale);
2212 return bc_num_binary(a, b, c, scale, bc_num_right, req);
2213 }
2214 #endif // BC_ENABLE_EXTRA_MATH
2215
bc_num_sqrt(BcNum * restrict a,BcNum * restrict b,size_t scale)2216 BcStatus bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) {
2217
2218 BcStatus s = BC_STATUS_SUCCESS;
2219 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2220 size_t pow, len, rdx, req, digs, digs1, digs2, resscale;
2221 BcDig half_digs[1];
2222
2223 assert(a != NULL && b != NULL && a != b);
2224
2225 if (BC_ERR(a->neg)) return bc_vm_err(BC_ERROR_MATH_NEGATIVE);
2226
2227 if (a->scale > scale) scale = a->scale;
2228 len = bc_vm_growSize(bc_num_intDigits(a), 1);
2229 rdx = BC_NUM_RDX(scale);
2230 req = bc_vm_growSize(BC_MAX(rdx, a->rdx), len >> 1);
2231 bc_num_init(b, bc_vm_growSize(req, 1));
2232
2233 if (BC_NUM_ZERO(a)) {
2234 bc_num_setToZero(b, scale);
2235 return BC_STATUS_SUCCESS;
2236 }
2237 if (BC_NUM_ONE(a)) {
2238 bc_num_one(b);
2239 bc_num_extend(b, scale);
2240 return BC_STATUS_SUCCESS;
2241 }
2242
2243 rdx = BC_NUM_RDX(scale);
2244 rdx = BC_MAX(rdx, a->rdx);
2245 len = bc_vm_growSize(a->len, rdx);
2246
2247 bc_num_init(&num1, len);
2248 bc_num_init(&num2, len);
2249 bc_num_setup(&half, half_digs, sizeof(half_digs) / sizeof(BcDig));
2250
2251 bc_num_one(&half);
2252 half.num[0] = BC_BASE_POW / 2;
2253 half.len = 1;
2254 half.rdx = 1;
2255 half.scale = 1;
2256
2257 bc_num_init(&f, len);
2258 bc_num_init(&fprime, len);
2259
2260 x0 = &num1;
2261 x1 = &num2;
2262
2263 bc_num_one(x0);
2264 pow = bc_num_intDigits(a);
2265
2266 if (pow) {
2267
2268 if (pow & 1) x0->num[0] = 2;
2269 else x0->num[0] = 6;
2270
2271 pow -= 2 - (pow & 1);
2272 s = bc_num_shiftLeft(x0, pow / 2);
2273 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
2274 }
2275
2276 x0->scale = x0->rdx = digs = digs1 = digs2 = 0;
2277 resscale = (scale + BC_BASE_DIGS) + 2;
2278
2279 while (BC_NO_SIG && bc_num_cmp(x1, x0)) {
2280
2281 assert(BC_NUM_NONZERO(x0));
2282
2283 s = bc_num_div(a, x0, &f, resscale);
2284 assert(!s || s == BC_STATUS_SIGNAL);
2285 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
2286 s = bc_num_add(x0, &f, &fprime, resscale);
2287 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
2288 s = bc_num_mul(&fprime, &half, x1, resscale);
2289 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
2290
2291 temp = x0;
2292 x0 = x1;
2293 x1 = temp;
2294 }
2295
2296 if (BC_SIG) {
2297 s = BC_STATUS_SIGNAL;
2298 goto err;
2299 }
2300
2301 bc_num_copy(b, x0);
2302 if (b->scale > scale) bc_num_truncate(b, b->scale - scale);
2303
2304 assert(!b->neg || BC_NUM_NONZERO(b));
2305 assert(b->rdx <= b->len || !b->len);
2306 assert(!b->len || b->num[b->len - 1] || b->rdx == b->len);
2307
2308 err:
2309 if (BC_ERR(s)) bc_num_free(b);
2310 bc_num_free(&fprime);
2311 bc_num_free(&f);
2312 bc_num_free(&num2);
2313 bc_num_free(&num1);
2314 return s;
2315 }
2316
bc_num_divmod(BcNum * a,BcNum * b,BcNum * c,BcNum * d,size_t scale)2317 BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) {
2318
2319 BcStatus s;
2320 BcNum num2, *ptr_a;
2321 bool init = false;
2322 size_t ts, len;
2323
2324 ts = BC_MAX(scale + b->scale, a->scale);
2325 len = bc_num_mulReq(a, b, ts);
2326
2327 assert(a != NULL && b != NULL && c != NULL && d != NULL);
2328 assert(c != d && a != d && b != d && b != c);
2329
2330 if (c == a) {
2331 memcpy(&num2, c, sizeof(BcNum));
2332 ptr_a = &num2;
2333 bc_num_init(c, len);
2334 init = true;
2335 }
2336 else {
2337 ptr_a = a;
2338 bc_num_expand(c, len);
2339 }
2340
2341 if (BC_NUM_NONZERO(a) && !a->rdx && !b->rdx && b->len == 1 && !scale) {
2342
2343 BcBigDig rem;
2344
2345 s = bc_num_divArray(ptr_a, (BcBigDig) b->num[0], c, &rem);
2346
2347 assert(rem < BC_BASE_POW);
2348
2349 d->num[0] = (BcDig) rem;
2350 d->len = (rem != 0);
2351 }
2352 else s = bc_num_r(ptr_a, b, c, d, scale, ts);
2353
2354 assert(!c->neg || BC_NUM_NONZERO(c));
2355 assert(c->rdx <= c->len || !c->len);
2356 assert(!c->len || c->num[c->len - 1] || c->rdx == c->len);
2357 assert(!d->neg || BC_NUM_NONZERO(d));
2358 assert(d->rdx <= d->len || !d->len);
2359 assert(!d->len || d->num[d->len - 1] || d->rdx == d->len);
2360
2361 if (init) bc_num_free(&num2);
2362
2363 return s;
2364 }
2365
2366 #if DC_ENABLED
bc_num_modexp(BcNum * a,BcNum * b,BcNum * c,BcNum * restrict d)2367 BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d) {
2368
2369 BcStatus s;
2370 BcNum base, exp, two, temp;
2371 BcDig two_digs[2];
2372
2373 assert(a != NULL && b != NULL && c != NULL && d != NULL);
2374 assert(a != d && b != d && c != d);
2375
2376 if (BC_ERR(BC_NUM_ZERO(c)))
2377 return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO);
2378 if (BC_ERR(b->neg)) return bc_vm_err(BC_ERROR_MATH_NEGATIVE);
2379 if (BC_ERR(a->rdx || b->rdx || c->rdx))
2380 return bc_vm_err(BC_ERROR_MATH_NON_INTEGER);
2381
2382 bc_num_expand(d, c->len);
2383 bc_num_init(&base, c->len);
2384 bc_num_setup(&two, two_digs, sizeof(two_digs) / sizeof(BcDig));
2385 bc_num_init(&temp, b->len + 1);
2386
2387 bc_num_one(&two);
2388 two.num[0] = 2;
2389 bc_num_one(d);
2390
2391 // We already checked for 0.
2392 s = bc_num_rem(a, c, &base, 0);
2393 assert(!s || s == BC_STATUS_SIGNAL);
2394 if (BC_ERROR_SIGNAL_ONLY(s)) goto rem_err;
2395 bc_num_createCopy(&exp, b);
2396
2397 while (BC_NO_SIG && BC_NUM_NONZERO(&exp)) {
2398
2399 // Num two cannot be 0, so no errors.
2400 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2401 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
2402
2403 if (BC_NUM_ONE(&temp) && !temp.neg) {
2404
2405 s = bc_num_mul(d, &base, &temp, 0);
2406 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
2407
2408 // We already checked for 0.
2409 s = bc_num_rem(&temp, c, d, 0);
2410 assert(!s || s == BC_STATUS_SIGNAL);
2411 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
2412 }
2413
2414 s = bc_num_mul(&base, &base, &temp, 0);
2415 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
2416
2417 // We already checked for 0.
2418 s = bc_num_rem(&temp, c, &base, 0);
2419 assert(!s || s == BC_STATUS_SIGNAL);
2420 if (BC_ERROR_SIGNAL_ONLY(s)) goto err;
2421 }
2422
2423 if (BC_NO_ERR(!s) && BC_SIG) s = BC_STATUS_SIGNAL;
2424
2425 err:
2426 bc_num_free(&exp);
2427 rem_err:
2428 bc_num_free(&temp);
2429 bc_num_free(&base);
2430 assert(!d->neg || d->len);
2431 assert(!d->len || d->num[d->len - 1] || d->rdx == d->len);
2432 return s;
2433 }
2434 #endif // DC_ENABLED
2435
2436 #if BC_DEBUG_CODE
bc_num_printDebug(const BcNum * n,const char * name,bool emptyline)2437 void bc_num_printDebug(const BcNum *n, const char *name, bool emptyline) {
2438 printf("%s: ", name);
2439 bc_num_printDecimal(n);
2440 printf("\n");
2441 if (emptyline) printf("\n");
2442 vm->nchars = 0;
2443 }
2444
bc_num_printDigs(const BcDig * n,size_t len,bool emptyline)2445 void bc_num_printDigs(const BcDig *n, size_t len, bool emptyline) {
2446
2447 size_t i;
2448
2449 for (i = len - 1; i < len; --i) printf(" %0*d", BC_BASE_DIGS, n[i]);
2450
2451 printf("\n");
2452 if (emptyline) printf("\n");
2453 vm->nchars = 0;
2454 }
2455
bc_num_printWithDigs(const BcNum * n,const char * name,bool emptyline)2456 void bc_num_printWithDigs(const BcNum *n, const char *name, bool emptyline) {
2457 printf("%s len: %zu, rdx: %zu, scale: %zu\n",
2458 name, n->len, n->rdx, n->scale);
2459 bc_num_printDigs(n->num, n->len, emptyline);
2460 }
2461
bc_num_dump(const char * varname,const BcNum * n)2462 void bc_num_dump(const char *varname, const BcNum *n) {
2463
2464 ulong i, scale = n->scale;
2465
2466 fprintf(stderr, "\n%s = %s", varname, n->len ? (n->neg ? "-" : "+") : "0 ");
2467
2468 for (i = n->len - 1; i < n->len; --i) {
2469
2470 if (i + 1 == n->rdx) fprintf(stderr, ". ");
2471
2472 if (scale / BC_BASE_DIGS != n->rdx - i - 1)
2473 fprintf(stderr, "%0*d ", BC_BASE_DIGS, n->num[i]);
2474 else {
2475
2476 int mod = scale % BC_BASE_DIGS;
2477 int d = BC_BASE_DIGS - mod;
2478 BcDig div;
2479
2480 if (mod != 0) {
2481 div = n->num[i] / ((BcDig) bc_num_pow10[(ulong) d]);
2482 fprintf(stderr, "%0*d", (int) mod, div);
2483 }
2484
2485 div = n->num[i] % ((BcDig) bc_num_pow10[(ulong) d]);
2486 fprintf(stderr, " ' %0*d ", d, div);
2487 }
2488 }
2489
2490 fprintf(stderr, "(%zu | %zu.%zu / %zu) %p\n",
2491 n->scale, n->len, n->rdx, n->cap, (void*) n->num);
2492 }
2493 #endif // BC_DEBUG_CODE
2494