// ("always returning zero") prefix, i.e. zbc_foo or zdc_foo.
//
#if ENABLE_FEATURE_BC_SIGNALS || ENABLE_FEATURE_CLEAN_UP
+# define ERRORS_ARE_FATAL 0
# define ERRORFUNC /*nothing*/
# define ERROR_RETURN(a) a
-# define ERRORS_ARE_FATAL 0
# define BC_STATUS BcStatus
# define RETURN_STATUS(v) return (v)
#else
+# define ERRORS_ARE_FATAL 1
# define ERRORFUNC NORETURN
# define ERROR_RETURN(a) /*nothing*/
-# define ERRORS_ARE_FATAL 1
# define BC_STATUS void
# define RETURN_STATUS(v) do { ((void)(v)); return; } while (0)
#endif
+#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
+#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
+#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
+//#define BC_NUM_AREQ(a, b) (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
+static /*ALWAYS_INLINE*/ size_t BC_NUM_AREQ(BcNum *a, BcNum *b)
+{
+ return BC_MAX(a->rdx, b->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1;
+}
+//#define BC_NUM_MREQ(a, b, scale) (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
+static /*ALWAYS_INLINE*/ size_t BC_NUM_MREQ(BcNum *a, BcNum *b, size_t scale)
+{
+ return BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX(scale, a->rdx + b->rdx) + 1;
+}
+
typedef void (*BcNumDigitOp)(size_t, size_t, bool) FAST_FUNC;
-typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t) FAST_FUNC;
+typedef BC_STATUS (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t) FAST_FUNC;
-static BcStatus zbc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) FAST_FUNC;
-static BcStatus zbc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale) FAST_FUNC;
-static BcStatus zbc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale) FAST_FUNC;
-static BcStatus zbc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale) FAST_FUNC;
-static BcStatus zbc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) FAST_FUNC;
-static BcStatus zbc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale) FAST_FUNC;
-static BcStatus zbc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
- size_t scale);
+static BC_STATUS zbc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
+ BcNumBinaryOp op, size_t req);
+static FAST_FUNC BC_STATUS zbc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
+static FAST_FUNC BC_STATUS zbc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
+static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
+static FAST_FUNC BC_STATUS zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
+static FAST_FUNC BC_STATUS zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
+static FAST_FUNC BC_STATUS zbc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
+
+static FAST_FUNC BC_STATUS zbc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
+{
+ BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_a : zbc_num_s;
+ (void) scale;
+ RETURN_STATUS(zbc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b)));
+}
+
+static FAST_FUNC BC_STATUS zbc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
+{
+ BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_s : zbc_num_a;
+ (void) scale;
+ RETURN_STATUS(zbc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b)));
+}
+
+static FAST_FUNC BC_STATUS zbc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
+{
+ size_t req = BC_NUM_MREQ(a, b, scale);
+ RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_m, req));
+}
+
+static FAST_FUNC BC_STATUS zbc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
+{
+ size_t req = BC_NUM_MREQ(a, b, scale);
+ RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_d, req));
+}
+
+static FAST_FUNC BC_STATUS zbc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
+{
+ size_t req = BC_NUM_MREQ(a, b, scale);
+ RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_rem, req));
+}
+
+static FAST_FUNC BC_STATUS zbc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
+{
+ RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_p, a->len * b->len + 1));
+}
static const BcNumBinaryOp zbc_program_ops[] = {
zbc_num_pow, zbc_num_mul, zbc_num_div, zbc_num_mod, zbc_num_add, zbc_num_sub,
};
+#if ERRORS_ARE_FATAL
+# define zbc_num_add(...) (zbc_num_add(__VA_ARGS__), BC_STATUS_SUCCESS)
+# define zbc_num_sub(...) (zbc_num_sub(__VA_ARGS__), BC_STATUS_SUCCESS)
+# define zbc_num_mul(...) (zbc_num_mul(__VA_ARGS__), BC_STATUS_SUCCESS)
+# define zbc_num_div(...) (zbc_num_div(__VA_ARGS__), BC_STATUS_SUCCESS)
+# define zbc_num_mod(...) (zbc_num_mod(__VA_ARGS__), BC_STATUS_SUCCESS)
+# define zbc_num_pow(...) (zbc_num_pow(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
static void fflush_and_check(void)
{
}
}
-#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
-#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
-#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
-//#define BC_NUM_AREQ(a, b) (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
-static /*ALWAYS_INLINE*/ size_t BC_NUM_AREQ(BcNum *a, BcNum *b)
-{
- return BC_MAX(a->rdx, b->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1;
-}
-//#define BC_NUM_MREQ(a, b, scale) (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
-static /*ALWAYS_INLINE*/ size_t BC_NUM_MREQ(BcNum *a, BcNum *b, size_t scale)
-{
- return BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX(scale, a->rdx + b->rdx) + 1;
-}
-
static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
{
size_t i;
# define zbc_num_shift(...) (zbc_num_shift(__VA_ARGS__), BC_STATUS_SUCCESS)
#endif
-static BcStatus zbc_num_inv(BcNum *a, BcNum *b, size_t scale)
+static BC_STATUS zbc_num_inv(BcNum *a, BcNum *b, size_t scale)
{
BcNum one;
BcDig num[2];
one.num = num;
bc_num_one(&one);
- return zbc_num_div(&one, a, b, scale);
+ RETURN_STATUS(zbc_num_div(&one, a, b, scale));
}
+#if ERRORS_ARE_FATAL
+# define zbc_num_inv(...) (zbc_num_inv(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
-static FAST_FUNC BcStatus zbc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
+static FAST_FUNC BC_STATUS zbc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
{
BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
size_t i, max, min_rdx, min_int, diff, a_int, b_int;
if (a->len == 0) {
bc_num_copy(c, b);
if (sub && c->len) c->neg = !c->neg;
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
- else if (b->len == 0) {
+ if (b->len == 0) {
bc_num_copy(c, a);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
c->neg = a->neg;
if (carry != 0) c->num[c->len++] = (BcDig) carry;
- return BC_STATUS_SUCCESS; // can't make void, see zbc_num_binary()
+ RETURN_STATUS(BC_STATUS_SUCCESS); // can't make void, see zbc_num_binary()
}
-static FAST_FUNC BcStatus zbc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
+static FAST_FUNC BC_STATUS zbc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
{
ssize_t cmp;
BcNum *minuend, *subtrahend;
if (a->len == 0) {
bc_num_copy(c, b);
if (sub && c->len) c->neg = !c->neg;
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
- else if (b->len == 0) {
+ if (b->len == 0) {
bc_num_copy(c, a);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
aneg = a->neg;
if (cmp == 0) {
bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
- else if (cmp > 0) {
+ if (cmp > 0) {
neg = a->neg;
minuend = a;
subtrahend = b;
bc_num_clean(c);
- return BC_STATUS_SUCCESS; // can't make void, see zbc_num_binary()
+ RETURN_STATUS(BC_STATUS_SUCCESS); // can't make void, see zbc_num_binary()
}
-static FAST_FUNC BcStatus zbc_num_k(BcNum *restrict a, BcNum *restrict b,
+static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
BcNum *restrict c)
+#if ERRORS_ARE_FATAL
+# define zbc_num_k(...) (zbc_num_k(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
{
BcStatus s;
size_t max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
if (a->len == 0 || b->len == 0) {
bc_num_zero(c);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
aone = BC_NUM_ONE(a);
if (aone || BC_NUM_ONE(b)) {
bc_num_copy(c, aone ? b : a);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
c->num[i + j] += (BcDig) carry;
len = BC_MAX(len, i + j + !!carry);
+#if ENABLE_FEATURE_BC_SIGNALS
// a=2^1000000
// a*a <- without check below, this will not be interruptible
if (G_interrupt) return BC_STATUS_FAILURE;
+#endif
}
c->len = len;
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
bc_num_init(&l1, max);
bc_num_free(&l2);
bc_num_free(&h1);
bc_num_free(&l1);
- return s;
+ RETURN_STATUS(s);
}
-static FAST_FUNC BcStatus zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
+static FAST_FUNC BC_STATUS zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
{
BcStatus s;
BcNum cpa, cpb;
err:
bc_num_free(&cpb);
bc_num_free(&cpa);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_num_m(...) (zbc_num_m(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
-static FAST_FUNC BcStatus zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
+static FAST_FUNC BC_STATUS zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
{
BcStatus s = BC_STATUS_SUCCESS;
BcDig *n, *p, q;
bool zero = true;
if (b->len == 0)
- return bc_error("divide by zero");
- else if (a->len == 0) {
+ RETURN_STATUS(bc_error("divide by zero"));
+ if (a->len == 0) {
bc_num_setToZero(c, scale);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
- else if (BC_NUM_ONE(b)) {
+ if (BC_NUM_ONE(b)) {
bc_num_copy(c, a);
bc_num_retireMul(c, scale, a->neg, b->neg);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
bc_num_subArrays(n, p, len);
c->num[i] = q;
+#if ENABLE_FEATURE_BC_SIGNALS
// a=2^100000
// scale=40000
// 1/a <- without check below, this will not be interruptible
s = BC_STATUS_FAILURE;
break;
}
+#endif
}
bc_num_retireMul(c, scale, a->neg, b->neg);
bc_num_free(&cp);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_num_d(...) (zbc_num_d(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
-static FAST_FUNC BcStatus zbc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
+static FAST_FUNC BC_STATUS zbc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
BcNum *restrict d, size_t scale, size_t ts)
{
BcStatus s;
bool neg;
if (b->len == 0)
- return bc_error("divide by zero");
+ RETURN_STATUS(bc_error("divide by zero"));
if (a->len == 0) {
bc_num_setToZero(d, ts);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
bc_num_init(&temp, d->cap);
err:
bc_num_free(&temp);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_num_r(...) (zbc_num_r(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
-static FAST_FUNC BcStatus zbc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
+static FAST_FUNC BC_STATUS zbc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
{
BcStatus s;
BcNum c1;
s = zbc_num_r(a, b, &c1, c, scale, ts);
bc_num_free(&c1);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_num_rem(...) (zbc_num_rem(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
-static FAST_FUNC BcStatus zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
+static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
{
BcStatus s = BC_STATUS_SUCCESS;
BcNum copy;
size_t i, powrdx, resrdx;
bool neg, zero;
- if (b->rdx) return bc_error("non integer number");
+ if (b->rdx) RETURN_STATUS(bc_error("non integer number"));
if (b->len == 0) {
bc_num_one(c);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
- else if (a->len == 0) {
+ if (a->len == 0) {
bc_num_setToZero(c, scale);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
- else if (BC_NUM_ONE(b)) {
+ if (BC_NUM_ONE(b)) {
if (!b->neg)
bc_num_copy(c, a);
else
s = zbc_num_inv(a, c, scale);
- return s;
+ RETURN_STATUS(s);
}
neg = b->neg;
b->neg = false;
s = zbc_num_ulong(b, &pow);
- if (s) return s;
+ if (s) RETURN_STATUS(s);
bc_num_init(©, a->len);
bc_num_copy(©, a);
err:
bc_num_free(©);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_num_p(...) (zbc_num_p(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
-static BcStatus zbc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
+static BC_STATUS zbc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
BcNumBinaryOp op, size_t req)
{
BcStatus s;
else
bc_num_expand(c, req);
+#if !ERRORS_ARE_FATAL
s = op(ptr_a, ptr_b, c, scale);
-
- if (init) bc_num_free(&num2);
-
- return s;
-}
-
-static void bc_num_printNewline(void)
-{
- if (G.prog.nchars == G.prog.len - 1) {
- bb_putchar('\\');
- bb_putchar('\n');
- G.prog.nchars = 0;
- }
-}
-
-#if ENABLE_DC
-static FAST_FUNC void bc_num_printChar(size_t num, size_t width, bool radix)
-{
- (void) radix;
- bb_putchar((char) num);
- G.prog.nchars += width;
-}
-#endif
-
-static FAST_FUNC void bc_num_printDigits(size_t num, size_t width, bool radix)
-{
- size_t exp, pow;
-
- bc_num_printNewline();
- bb_putchar(radix ? '.' : ' ');
- ++G.prog.nchars;
-
- bc_num_printNewline();
- for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
- continue;
-
- for (exp = 0; exp < width; pow /= 10, ++G.prog.nchars, ++exp) {
- size_t dig;
- bc_num_printNewline();
- dig = num / pow;
- num -= dig * pow;
- bb_putchar(((char) dig) + '0');
- }
-}
-
-static FAST_FUNC void bc_num_printHex(size_t num, size_t width, bool radix)
-{
- if (radix) {
- bc_num_printNewline();
- bb_putchar('.');
- G.prog.nchars += 1;
- }
-
- bc_num_printNewline();
- bb_putchar(bb_hexdigits_upcase[num]);
- G.prog.nchars += width;
-}
-
-static void bc_num_printDecimal(BcNum *n)
-{
- size_t i, rdx = n->rdx - 1;
-
- if (n->neg) bb_putchar('-');
- G.prog.nchars += n->neg;
-
- for (i = n->len - 1; i < n->len; --i)
- bc_num_printHex((size_t) n->num[i], 1, i == rdx);
-}
-
-static BC_STATUS zbc_num_printNum(BcNum *n, BcNum *base, size_t width, BcNumDigitOp print)
-{
- BcStatus s;
- BcVec stack;
- BcNum intp, fracp, digit, frac_len;
- unsigned long dig, *ptr;
- size_t i;
- bool radix;
-
- if (n->len == 0) {
- print(0, width, false);
- RETURN_STATUS(BC_STATUS_SUCCESS);
- }
-
- bc_vec_init(&stack, sizeof(long), NULL);
- bc_num_init(&intp, n->len);
- bc_num_init(&fracp, n->rdx);
- bc_num_init(&digit, width);
- bc_num_init(&frac_len, BC_NUM_INT(n));
- bc_num_copy(&intp, n);
- bc_num_one(&frac_len);
-
- bc_num_truncate(&intp, intp.rdx);
- s = zbc_num_sub(n, &intp, &fracp, 0);
- if (s) goto err;
-
- while (intp.len != 0) {
- s = zbc_num_divmod(&intp, base, &intp, &digit, 0);
- if (s) goto err;
- s = zbc_num_ulong(&digit, &dig);
- if (s) goto err;
- bc_vec_push(&stack, &dig);
- }
-
- for (i = 0; i < stack.len; ++i) {
- ptr = bc_vec_item_rev(&stack, i);
- print(*ptr, width, false);
- }
-
- if (!n->rdx) goto err;
-
- for (radix = true; frac_len.len <= n->rdx; radix = false) {
- s = zbc_num_mul(&fracp, base, &fracp, n->rdx);
- if (s) goto err;
- s = zbc_num_ulong(&fracp, &dig);
- if (s) goto err;
- bc_num_ulong2num(&intp, dig);
- s = zbc_num_sub(&fracp, &intp, &fracp, 0);
- if (s) goto err;
- print(dig, width, radix);
- s = zbc_num_mul(&frac_len, base, &frac_len, 0);
- if (s) goto err;
- }
-
-err:
- bc_num_free(&frac_len);
- bc_num_free(&digit);
- bc_num_free(&fracp);
- bc_num_free(&intp);
- bc_vec_free(&stack);
- RETURN_STATUS(s);
-}
-#if ERRORS_ARE_FATAL
-# define zbc_num_printNum(...) (zbc_num_printNum(__VA_ARGS__), BC_STATUS_SUCCESS)
+#else
+ op(ptr_a, ptr_b, c, scale);
+ s = BC_STATUS_SUCCESS;
#endif
-static BC_STATUS zbc_num_printBase(BcNum *n)
-{
- BcStatus s;
- size_t width, i;
- BcNumDigitOp print;
- bool neg = n->neg;
-
- if (neg) {
- bb_putchar('-');
- G.prog.nchars++;
- }
-
- n->neg = false;
-
- if (G.prog.ob_t <= BC_NUM_MAX_IBASE) {
- width = 1;
- print = bc_num_printHex;
- }
- else {
- for (i = G.prog.ob_t - 1, width = 0; i != 0; i /= 10, ++width)
- continue;
- print = bc_num_printDigits;
- }
-
- s = zbc_num_printNum(n, &G.prog.ob, width, print);
- n->neg = neg;
+ if (init) bc_num_free(&num2);
RETURN_STATUS(s);
}
#if ERRORS_ARE_FATAL
-# define zbc_num_printBase(...) (zbc_num_printBase(__VA_ARGS__), BC_STATUS_SUCCESS)
-#endif
-
-#if ENABLE_DC
-static BC_STATUS zbc_num_stream(BcNum *n, BcNum *base)
-{
- RETURN_STATUS(zbc_num_printNum(n, base, 1, bc_num_printChar));
-}
-#if ERRORS_ARE_FATAL
-# define zbc_num_stream(...) (zbc_num_stream(__VA_ARGS__), BC_STATUS_SUCCESS)
-#endif
+# define zbc_num_binary(...) (zbc_num_binary(__VA_ARGS__), BC_STATUS_SUCCESS)
#endif
static bool bc_num_strValid(const char *val, size_t base)
# define zbc_num_parse(...) (zbc_num_parse(__VA_ARGS__), BC_STATUS_SUCCESS)
#endif
-static BC_STATUS zbc_num_print(BcNum *n, bool newline)
-{
- BcStatus s = BC_STATUS_SUCCESS;
-
- bc_num_printNewline();
-
- if (n->len == 0) {
- bb_putchar('0');
- ++G.prog.nchars;
- }
- else if (G.prog.ob_t == 10)
- bc_num_printDecimal(n);
- else
- s = zbc_num_printBase(n);
-
- if (newline) {
- bb_putchar('\n');
- G.prog.nchars = 0;
- }
-
- RETURN_STATUS(s);
-}
-#if ERRORS_ARE_FATAL
-# define zbc_num_print(...) (zbc_num_print(__VA_ARGS__), BC_STATUS_SUCCESS)
-#endif
-
-static FAST_FUNC BcStatus zbc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
-{
- BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_a : zbc_num_s;
- (void) scale;
- return zbc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
-}
-
-static FAST_FUNC BcStatus zbc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
-{
- BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_s : zbc_num_a;
- (void) scale;
- return zbc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
-}
-
-static FAST_FUNC BcStatus zbc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
-{
- size_t req = BC_NUM_MREQ(a, b, scale);
- return zbc_num_binary(a, b, c, scale, zbc_num_m, req);
-}
-
-static FAST_FUNC BcStatus zbc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
-{
- size_t req = BC_NUM_MREQ(a, b, scale);
- return zbc_num_binary(a, b, c, scale, zbc_num_d, req);
-}
-
-static FAST_FUNC BcStatus zbc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
-{
- size_t req = BC_NUM_MREQ(a, b, scale);
- return zbc_num_binary(a, b, c, scale, zbc_num_rem, req);
-}
-
-static FAST_FUNC BcStatus zbc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
-{
- return zbc_num_binary(a, b, c, scale, zbc_num_p, a->len * b->len + 1);
-}
-
-static BcStatus zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
+static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
{
BcStatus s;
BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
if (a->len == 0) {
bc_num_setToZero(b, scale);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
else if (a->neg)
- return bc_error("negative number");
+ RETURN_STATUS(bc_error("negative number"));
else if (BC_NUM_ONE(a)) {
bc_num_one(b);
bc_num_extend(b, scale);
- return BC_STATUS_SUCCESS;
+ RETURN_STATUS(BC_STATUS_SUCCESS);
}
scale = BC_MAX(scale, a->rdx) + 1;
bc_num_free(&half);
bc_num_free(&num2);
bc_num_free(&num1);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_num_sqrt(...) (zbc_num_sqrt(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
-static BcStatus zbc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
+static BC_STATUS zbc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
size_t scale)
{
BcStatus s;
if (init) bc_num_free(&num2);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_num_divmod(...) (zbc_num_divmod(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
#if ENABLE_DC
-static BcStatus zbc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
+static BC_STATUS zbc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
{
BcStatus s;
BcNum base, exp, two, temp;
if (c->len == 0)
- return bc_error("divide by zero");
+ RETURN_STATUS(bc_error("divide by zero"));
if (a->rdx || b->rdx || c->rdx)
- return bc_error("non integer number");
+ RETURN_STATUS(bc_error("non integer number"));
if (b->neg)
- return bc_error("negative number");
+ RETURN_STATUS(bc_error("negative number"));
bc_num_expand(d, c->len);
bc_num_init(&base, c->len);
bc_num_free(&two);
bc_num_free(&exp);
bc_num_free(&base);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_num_modexp(...) (zbc_num_modexp(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
#endif // ENABLE_DC
#if ENABLE_BC
if (s) return s;
bc_num_init_DEF_SIZE(&res.d.n);
- s = zbc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
+ s = BC_STATUS_SUCCESS;
+#if !ERRORS_ARE_FATAL
+ s =
+#endif
+ zbc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
if (s) goto err;
bc_program_binOpRetire(&res);
}
}
+static void bc_num_printNewline(void)
+{
+ if (G.prog.nchars == G.prog.len - 1) {
+ bb_putchar('\\');
+ bb_putchar('\n');
+ G.prog.nchars = 0;
+ }
+}
+
+#if ENABLE_DC
+static FAST_FUNC void bc_num_printChar(size_t num, size_t width, bool radix)
+{
+ (void) radix;
+ bb_putchar((char) num);
+ G.prog.nchars += width;
+}
+#endif
+
+static FAST_FUNC void bc_num_printDigits(size_t num, size_t width, bool radix)
+{
+ size_t exp, pow;
+
+ bc_num_printNewline();
+ bb_putchar(radix ? '.' : ' ');
+ ++G.prog.nchars;
+
+ bc_num_printNewline();
+ for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
+ continue;
+
+ for (exp = 0; exp < width; pow /= 10, ++G.prog.nchars, ++exp) {
+ size_t dig;
+ bc_num_printNewline();
+ dig = num / pow;
+ num -= dig * pow;
+ bb_putchar(((char) dig) + '0');
+ }
+}
+
+static FAST_FUNC void bc_num_printHex(size_t num, size_t width, bool radix)
+{
+ if (radix) {
+ bc_num_printNewline();
+ bb_putchar('.');
+ G.prog.nchars += 1;
+ }
+
+ bc_num_printNewline();
+ bb_putchar(bb_hexdigits_upcase[num]);
+ G.prog.nchars += width;
+}
+
+static void bc_num_printDecimal(BcNum *n)
+{
+ size_t i, rdx = n->rdx - 1;
+
+ if (n->neg) bb_putchar('-');
+ G.prog.nchars += n->neg;
+
+ for (i = n->len - 1; i < n->len; --i)
+ bc_num_printHex((size_t) n->num[i], 1, i == rdx);
+}
+
+static BC_STATUS zbc_num_printNum(BcNum *n, BcNum *base, size_t width, BcNumDigitOp print)
+{
+ BcStatus s;
+ BcVec stack;
+ BcNum intp, fracp, digit, frac_len;
+ unsigned long dig, *ptr;
+ size_t i;
+ bool radix;
+
+ if (n->len == 0) {
+ print(0, width, false);
+ RETURN_STATUS(BC_STATUS_SUCCESS);
+ }
+
+ bc_vec_init(&stack, sizeof(long), NULL);
+ bc_num_init(&intp, n->len);
+ bc_num_init(&fracp, n->rdx);
+ bc_num_init(&digit, width);
+ bc_num_init(&frac_len, BC_NUM_INT(n));
+ bc_num_copy(&intp, n);
+ bc_num_one(&frac_len);
+
+ bc_num_truncate(&intp, intp.rdx);
+ s = zbc_num_sub(n, &intp, &fracp, 0);
+ if (s) goto err;
+
+ while (intp.len != 0) {
+ s = zbc_num_divmod(&intp, base, &intp, &digit, 0);
+ if (s) goto err;
+ s = zbc_num_ulong(&digit, &dig);
+ if (s) goto err;
+ bc_vec_push(&stack, &dig);
+ }
+
+ for (i = 0; i < stack.len; ++i) {
+ ptr = bc_vec_item_rev(&stack, i);
+ print(*ptr, width, false);
+ }
+
+ if (!n->rdx) goto err;
+
+ for (radix = true; frac_len.len <= n->rdx; radix = false) {
+ s = zbc_num_mul(&fracp, base, &fracp, n->rdx);
+ if (s) goto err;
+ s = zbc_num_ulong(&fracp, &dig);
+ if (s) goto err;
+ bc_num_ulong2num(&intp, dig);
+ s = zbc_num_sub(&fracp, &intp, &fracp, 0);
+ if (s) goto err;
+ print(dig, width, radix);
+ s = zbc_num_mul(&frac_len, base, &frac_len, 0);
+ if (s) goto err;
+ }
+
+err:
+ bc_num_free(&frac_len);
+ bc_num_free(&digit);
+ bc_num_free(&fracp);
+ bc_num_free(&intp);
+ bc_vec_free(&stack);
+ RETURN_STATUS(s);
+}
+#if ERRORS_ARE_FATAL
+# define zbc_num_printNum(...) (zbc_num_printNum(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
+
+static BC_STATUS zbc_num_printBase(BcNum *n)
+{
+ BcStatus s;
+ size_t width, i;
+ BcNumDigitOp print;
+ bool neg = n->neg;
+
+ if (neg) {
+ bb_putchar('-');
+ G.prog.nchars++;
+ }
+
+ n->neg = false;
+
+ if (G.prog.ob_t <= BC_NUM_MAX_IBASE) {
+ width = 1;
+ print = bc_num_printHex;
+ }
+ else {
+ for (i = G.prog.ob_t - 1, width = 0; i != 0; i /= 10, ++width)
+ continue;
+ print = bc_num_printDigits;
+ }
+
+ s = zbc_num_printNum(n, &G.prog.ob, width, print);
+ n->neg = neg;
+
+ RETURN_STATUS(s);
+}
+#if ERRORS_ARE_FATAL
+# define zbc_num_printBase(...) (zbc_num_printBase(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
+
+#if ENABLE_DC
+static BC_STATUS zbc_num_stream(BcNum *n, BcNum *base)
+{
+ RETURN_STATUS(zbc_num_printNum(n, base, 1, bc_num_printChar));
+}
+#if ERRORS_ARE_FATAL
+# define zbc_num_stream(...) (zbc_num_stream(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
+#endif
+
+static BC_STATUS zbc_num_print(BcNum *n, bool newline)
+{
+ BcStatus s = BC_STATUS_SUCCESS;
+
+ bc_num_printNewline();
+
+ if (n->len == 0) {
+ bb_putchar('0');
+ ++G.prog.nchars;
+ }
+ else if (G.prog.ob_t == 10)
+ bc_num_printDecimal(n);
+ else
+ s = zbc_num_printBase(n);
+
+ if (newline) {
+ bb_putchar('\n');
+ G.prog.nchars = 0;
+ }
+
+ RETURN_STATUS(s);
+}
+#if ERRORS_ARE_FATAL
+# define zbc_num_print(...) (zbc_num_print(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
+
static BC_STATUS zbc_program_print(char inst, size_t idx)
{
BcStatus s;
# define zbc_program_copyToVar(...) (zbc_program_copyToVar(__VA_ARGS__), BC_STATUS_SUCCESS)
#endif
-static BcStatus bc_program_assign(char inst)
+static BC_STATUS zbc_program_assign(char inst)
{
BcStatus s;
BcResult *left, *right, res;
bool assign = inst == BC_INST_ASSIGN, ib, sc;
s = zbc_program_binOpPrep(&left, &l, &right, &r, assign);
- if (s) return s;
+ if (s) RETURN_STATUS(s);
ib = left->t == BC_RESULT_IBASE;
sc = left->t == BC_RESULT_SCALE;
BcVec *v;
if (left->t != BC_RESULT_VAR)
- return bc_error_variable_is_wrong_type();
+ RETURN_STATUS(bc_error_variable_is_wrong_type());
v = bc_program_search(left->d.id.name, true);
- return zbc_program_assignStr(right, v, false);
+ RETURN_STATUS(zbc_program_assignStr(right, v, false));
}
#endif
if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
- return bc_error("bad assignment:"
+ RETURN_STATUS(("bad assignment:"
" left side must be scale,"
" ibase, obase, last, var,"
" or array element"
- );
+ ));
#if ENABLE_BC
if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
- return bc_error("divide by zero");
+ RETURN_STATUS(bc_error("divide by zero"));
if (assign)
bc_num_copy(l, r);
- else
- s = zbc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
-
- if (s) return s;
+ else {
+ s = BC_STATUS_SUCCESS;
+#if !ERRORS_ARE_FATAL
+ s =
+#endif
+ zbc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
+ }
+ if (s) RETURN_STATUS(s);
#else
bc_num_copy(l, r);
#endif
unsigned long val, max;
s = zbc_num_ulong(l, &val);
- if (s)
- return s;
+ if (s) RETURN_STATUS(s);
s = left->t - BC_RESULT_IBASE;
if (sc) {
max = BC_MAX_SCALE;
}
else {
if (val < BC_NUM_MIN_BASE)
- return bc_error(msg[s]);
+ RETURN_STATUS(bc_error(msg[s]));
max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
}
if (val > max)
- return bc_error(msg[s]);
+ RETURN_STATUS(bc_error(msg[s]));
if (!sc)
bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
bc_num_copy(&res.d.n, l);
bc_program_binOpRetire(&res);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_program_assign(...) (zbc_program_assign(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
#if !ENABLE_DC
#define bc_program_pushVar(code, bgn, pop, copy) \
BC_INST_ASSIGN_MINUS;
bc_vec_push(&G.prog.results, &res);
- bc_program_assign(inst);
+ s = zbc_program_assign(inst);
+ if (s) RETURN_STATUS(s);
if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
bc_vec_pop(&G.prog.results);
return len;
}
-static BcStatus bc_program_builtin(char inst)
+static BC_STATUS zbc_program_builtin(char inst)
{
BcStatus s;
BcResult *opnd;
bool len = inst == BC_INST_LENGTH;
if (!BC_PROG_STACK(&G.prog.results, 1))
- return bc_error_stack_has_too_few_elements();
+ RETURN_STATUS(bc_error_stack_has_too_few_elements());
opnd = bc_vec_top(&G.prog.results);
s = zbc_program_num(opnd, &num, false);
- if (s) return s;
+ if (s) RETURN_STATUS(s);
#if ENABLE_DC
if (!BC_PROG_NUM(opnd, num) && !len)
- return bc_error_variable_is_wrong_type();
+ RETURN_STATUS(bc_error_variable_is_wrong_type());
#endif
bc_num_init_DEF_SIZE(&res.d.n);
#endif
#if ENABLE_DC
else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
-
char **str;
size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
bc_program_retire(&res, BC_RESULT_TEMP);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_program_builtin(...) (zbc_program_builtin(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
#if ENABLE_DC
-static BcStatus bc_program_divmod(void)
+static BC_STATUS zbc_program_divmod(void)
{
BcStatus s;
BcResult *opd1, *opd2, res, res2;
BcNum *n1, *n2 = NULL;
s = zbc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
- if (s) return s;
+ if (s) RETURN_STATUS(s);
bc_num_init_DEF_SIZE(&res.d.n);
bc_num_init(&res2.d.n, n2->len);
res.t = BC_RESULT_TEMP;
bc_vec_push(&G.prog.results, &res);
- return s;
+ RETURN_STATUS(s);
err:
bc_num_free(&res2.d.n);
bc_num_free(&res.d.n);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_program_divmod(...) (zbc_program_divmod(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
-static BcStatus bc_program_modexp(void)
+static BC_STATUS zbc_program_modexp(void)
{
BcStatus s;
BcResult *r1, *r2, *r3, res;
BcNum *n1, *n2, *n3;
if (!BC_PROG_STACK(&G.prog.results, 3))
- return bc_error_stack_has_too_few_elements();
+ RETURN_STATUS(bc_error_stack_has_too_few_elements());
s = zbc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
- if (s) return s;
+ if (s) RETURN_STATUS(s);
r1 = bc_vec_item_rev(&G.prog.results, 2);
s = zbc_program_num(r1, &n1, false);
- if (s) return s;
+ if (s) RETURN_STATUS(s);
if (!BC_PROG_NUM(r1, n1))
- return bc_error_variable_is_wrong_type();
+ RETURN_STATUS(bc_error_variable_is_wrong_type());
// Make sure that the values have their pointers updated, if necessary.
if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
if (r1->t == r2->t) {
s = zbc_program_num(r2, &n2, false);
- if (s) return s;
+ if (s) RETURN_STATUS(s);
}
if (r1->t == r3->t) {
s = zbc_program_num(r3, &n3, false);
- if (s) return s;
+ if (s) RETURN_STATUS(s);
}
}
bc_vec_pop(&G.prog.results);
bc_program_binOpRetire(&res);
- return s;
+ RETURN_STATUS(s);
err:
bc_num_free(&res.d.n);
- return s;
+ RETURN_STATUS(s);
}
+#if ERRORS_ARE_FATAL
+# define zbc_program_modexp(...) (zbc_program_modexp(__VA_ARGS__), BC_STATUS_SUCCESS)
+#endif
static void bc_program_stackLen(void)
{
case BC_INST_SCALE_FUNC:
case BC_INST_LENGTH:
case BC_INST_SQRT:
- s = bc_program_builtin(inst);
+ s = zbc_program_builtin(inst);
break;
case BC_INST_NUM:
r.t = BC_RESULT_CONSTANT;
case BC_INST_ASSIGN_MINUS:
#endif
case BC_INST_ASSIGN:
- s = bc_program_assign(inst);
+ s = zbc_program_assign(inst);
break;
#if ENABLE_DC
case BC_INST_MODEXP:
- s = bc_program_modexp();
+ s = zbc_program_modexp();
break;
case BC_INST_DIVMOD:
- s = bc_program_divmod();
+ s = zbc_program_divmod();
break;
case BC_INST_EXECUTE:
case BC_INST_EXEC_COND: