diff options
Diffstat (limited to 'contrib/bc/src/num.c')
-rw-r--r-- | contrib/bc/src/num.c | 1793 |
1 files changed, 1170 insertions, 623 deletions
diff --git a/contrib/bc/src/num.c b/contrib/bc/src/num.c index dc3f63ab076e..ac0f828008f8 100644 --- a/contrib/bc/src/num.c +++ b/contrib/bc/src/num.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2018-2021 Gavin D. Howard and contributors. + * Copyright (c) 2018-2023 Gavin D. Howard and contributors. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,11 +44,15 @@ #include <num.h> #include <rand.h> #include <vm.h> +#if BC_ENABLE_LIBRARY +#include <library.h> +#endif // BC_ENABLE_LIBRARY // Before you try to understand this code, see the development manual // (manuals/development.md#numbers). -static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale); +static void +bc_num_m(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale); /** * Multiply two numbers and throw a math error if they overflow. @@ -56,7 +60,9 @@ static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale); * @param b The second operand. * @return The product of the two operands. */ -static inline size_t bc_num_mulOverflow(size_t a, size_t b) { +static inline size_t +bc_num_mulOverflow(size_t a, size_t b) +{ size_t res = a * b; if (BC_ERR(BC_VM_MUL_OVERFLOW(a, b, res))) bc_err(BC_ERR_MATH_OVERFLOW); return res; @@ -68,7 +74,9 @@ static inline size_t bc_num_mulOverflow(size_t a, size_t b) { * @param n The value to turn into a signed value and negate. * @param neg The condition to negate or not. */ -static inline ssize_t bc_num_neg(size_t n, bool neg) { +static inline ssize_t +bc_num_neg(size_t n, bool neg) +{ return (((ssize_t) n) ^ -((ssize_t) neg)) + neg; } @@ -77,7 +85,9 @@ static inline ssize_t bc_num_neg(size_t n, bool neg) { * @param n The number to compare. * @return -1 if the number is less than 0, 1 if greater, and 0 if equal. */ -ssize_t bc_num_cmpZero(const BcNum *n) { +ssize_t +bc_num_cmpZero(const BcNum* n) +{ return bc_num_neg((n)->len != 0, BC_NUM_NEG(n)); } @@ -86,7 +96,9 @@ ssize_t bc_num_cmpZero(const BcNum *n) { * @param n The number to return the amount of integer limbs for. * @return The amount of integer limbs in @a n. */ -static inline size_t bc_num_int(const BcNum *n) { +static inline size_t +bc_num_int(const BcNum* n) +{ return n->len ? n->len - BC_NUM_RDX_VAL(n) : 0; } @@ -95,14 +107,15 @@ static inline size_t bc_num_int(const BcNum *n) { * @param n The number to expand. * @param req The number limbs to expand the allocation capacity to. */ -static void bc_num_expand(BcNum *restrict n, size_t req) { - +static void +bc_num_expand(BcNum* restrict n, size_t req) +{ assert(n != NULL); req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; - if (req > n->cap) { - + if (req > n->cap) + { BC_SIG_LOCK; n->num = bc_vm_realloc(n->num, BC_NUM_SIZE(req)); @@ -117,17 +130,23 @@ static void bc_num_expand(BcNum *restrict n, size_t req) { * @param n The number to set to zero. * @param scale The scale to set the number to. */ -static void bc_num_setToZero(BcNum *restrict n, size_t scale) { +static inline void +bc_num_setToZero(BcNum* restrict n, size_t scale) +{ assert(n != NULL); n->scale = scale; n->len = n->rdx = 0; } -void bc_num_zero(BcNum *restrict n) { +void +bc_num_zero(BcNum* restrict n) +{ bc_num_setToZero(n, 0); } -void bc_num_one(BcNum *restrict n) { +void +bc_num_one(BcNum* restrict n) +{ bc_num_zero(n); n->len = 1; n->num[0] = 1; @@ -138,15 +157,19 @@ void bc_num_one(BcNum *restrict n) { * limbs are zero. * @param n The number to clean. */ -static void bc_num_clean(BcNum *restrict n) { - +static void +bc_num_clean(BcNum* restrict n) +{ // Reduce the length. - while (BC_NUM_NONZERO(n) && !n->num[n->len - 1]) n->len -= 1; + while (BC_NUM_NONZERO(n) && !n->num[n->len - 1]) + { + n->len -= 1; + } // Special cases. if (BC_NUM_ZERO(n)) n->rdx = 0; - else { - + else + { // len must be at least as much as rdx. size_t rdx = BC_NUM_RDX_VAL(n); if (n->len < rdx) n->len = rdx; @@ -161,10 +184,18 @@ static void bc_num_clean(BcNum *restrict n) { * @param i The number to return the log base 10 of. * @return The log base 10 of @a i. */ -static size_t bc_num_log10(size_t i) { +static size_t +bc_num_log10(size_t i) +{ size_t len; - for (len = 1; i; i /= BC_BASE, ++len); + + for (len = 1; i; i /= BC_BASE, ++len) + { + continue; + } + assert(len - 1 <= BC_BASE_DIGS + 1); + return len - 1; } @@ -175,7 +206,9 @@ static size_t bc_num_log10(size_t i) { * @return The number of decimal digits that are 0 starting at the most * significant digits. */ -static inline size_t bc_num_zeroDigits(const BcDig *n) { +static inline size_t +bc_num_zeroDigits(const BcDig* n) +{ assert(*n >= 0); assert(((size_t) *n) < BC_BASE_POW); return BC_BASE_DIGS - bc_num_log10((size_t) *n); @@ -187,7 +220,9 @@ static inline size_t bc_num_zeroDigits(const BcDig *n) { * @param n The number. * @return The number of integer digits in @a n. */ -static size_t bc_num_intDigits(const BcNum *n) { +static size_t +bc_num_intDigits(const BcNum* n) +{ size_t digits = bc_num_int(n) * BC_BASE_DIGS; if (digits > 0) digits -= bc_num_zeroDigits(n->num + n->len - 1); return digits; @@ -202,11 +237,20 @@ static size_t bc_num_intDigits(const BcNum *n) { * @param n The number. * @return The number of non-zero limbs after the decimal point. */ -static size_t bc_num_nonZeroLen(const BcNum *restrict n) { +static size_t +bc_num_nonZeroLen(const BcNum* restrict n) +{ size_t i, len = n->len; + assert(len == BC_NUM_RDX_VAL(n)); - for (i = len - 1; i < len && !n->num[i]; --i); + + for (i = len - 1; i < len && !n->num[i]; --i) + { + continue; + } + assert(i + 1 > 0); + return i + 1; } @@ -218,11 +262,12 @@ static size_t bc_num_nonZeroLen(const BcNum *restrict n) { * carry out from this add. * @return The resulting limb sum. */ -static BcDig bc_num_addDigits(BcDig a, BcDig b, bool *carry) { - +static BcDig +bc_num_addDigits(BcDig a, BcDig b, bool* carry) +{ assert(((BcBigDig) BC_BASE_POW) * 2 == ((BcDig) BC_BASE_POW) * 2); - assert(a < BC_BASE_POW); - assert(b < BC_BASE_POW); + assert(a < BC_BASE_POW && a >= 0); + assert(b < BC_BASE_POW && b >= 0); a += b + *carry; *carry = (a >= BC_BASE_POW); @@ -242,10 +287,11 @@ static BcDig bc_num_addDigits(BcDig a, BcDig b, bool *carry) { * and the carry out from this subtract. * @return The resulting limb difference. */ -static BcDig bc_num_subDigits(BcDig a, BcDig b, bool *carry) { - - assert(a < BC_BASE_POW); - assert(b < BC_BASE_POW); +static BcDig +bc_num_subDigits(BcDig a, BcDig b, bool* carry) +{ + assert(a < BC_BASE_POW && a >= 0); + assert(b < BC_BASE_POW && b >= 0); b += *carry; *carry = (a < b); @@ -263,16 +309,22 @@ static BcDig bc_num_subDigits(BcDig a, BcDig b, bool *carry) { * @param b The second operand. * @param len The length of @a b. */ -static void bc_num_addArrays(BcDig *restrict a, const BcDig *restrict b, - size_t len) +static void +bc_num_addArrays(BcDig* restrict a, const BcDig* restrict b, size_t len) { size_t i; bool carry = false; - for (i = 0; i < len; ++i) a[i] = bc_num_addDigits(a[i], b[i], &carry); + for (i = 0; i < len; ++i) + { + a[i] = bc_num_addDigits(a[i], b[i], &carry); + } // Take care of the extra limbs in the bigger array. - for (; carry; ++i) a[i] = bc_num_addDigits(a[i], 0, &carry); + for (; carry; ++i) + { + a[i] = bc_num_addDigits(a[i], 0, &carry); + } } /** @@ -281,16 +333,22 @@ static void bc_num_addArrays(BcDig *restrict a, const BcDig *restrict b, * @param b The second operand. * @param len The length of @a b. */ -static void bc_num_subArrays(BcDig *restrict a, const BcDig *restrict b, - size_t len) +static void +bc_num_subArrays(BcDig* restrict a, const BcDig* restrict b, size_t len) { size_t i; bool carry = false; - for (i = 0; i < len; ++i) a[i] = bc_num_subDigits(a[i], b[i], &carry); + for (i = 0; i < len; ++i) + { + a[i] = bc_num_subDigits(a[i], b[i], &carry); + } // Take care of the extra limbs in the bigger array. - for (; carry; ++i) a[i] = bc_num_subDigits(a[i], 0, &carry); + for (; carry; ++i) + { + a[i] = bc_num_subDigits(a[i], 0, &carry); + } } /** @@ -300,8 +358,8 @@ static void bc_num_subArrays(BcDig *restrict a, const BcDig *restrict b, * @param b The one limb of the one-limb number. * @param c The return parameter. */ -static void bc_num_mulArray(const BcNum *restrict a, BcBigDig b, - BcNum *restrict c) +static void +bc_num_mulArray(const BcNum* restrict a, BcBigDig b, BcNum* restrict c) { size_t i; BcBigDig carry = 0; @@ -312,10 +370,12 @@ static void bc_num_mulArray(const BcNum *restrict a, BcBigDig b, if (a->len + 1 > c->cap) bc_num_expand(c, a->len + 1); // We want the entire return parameter to be zero for cleaning later. + // NOLINTNEXTLINE memset(c->num, 0, BC_NUM_SIZE(c->cap)); // Actual multiplication loop. - for (i = 0; i < a->len; ++i) { + for (i = 0; i < a->len; ++i) + { BcBigDig in = ((BcBigDig) a->num[i]) * b + carry; c->num[i] = in % BC_BASE_POW; carry = in / BC_BASE_POW; @@ -325,6 +385,7 @@ static void bc_num_mulArray(const BcNum *restrict a, BcBigDig b, // Finishing touches. c->num[i] = (BcDig) carry; + assert(c->num[i] >= 0 && c->num[i] < BC_BASE_POW); c->len = a->len; c->len += (carry != 0); @@ -344,8 +405,9 @@ static void bc_num_mulArray(const BcNum *restrict a, BcBigDig b, * @param c The return parameter for the quotient. * @param rem The return parameter for the remainder. */ -static void bc_num_divArray(const BcNum *restrict a, BcBigDig b, - BcNum *restrict c, BcBigDig *rem) +static void +bc_num_divArray(const BcNum* restrict a, BcBigDig b, BcNum* restrict c, + BcBigDig* rem) { size_t i; BcBigDig carry = 0; @@ -353,10 +415,12 @@ static void bc_num_divArray(const BcNum *restrict a, BcBigDig b, assert(c->cap >= a->len); // Actual division loop. - for (i = a->len - 1; i < a->len; --i) { + for (i = a->len - 1; i < a->len; --i) + { BcBigDig in = ((BcBigDig) a->num[i]) + carry * BC_BASE_POW; assert(in / b < BC_BASE_POW); c->num[i] = (BcDig) (in / b); + assert(c->num[i] >= 0 && c->num[i] < BC_BASE_POW); carry = in % b; } @@ -378,19 +442,24 @@ static void bc_num_divArray(const BcNum *restrict a, BcBigDig b, * @param b The second array. * @param len The minimum length of the arrays. */ -static ssize_t bc_num_compare(const BcDig *restrict a, const BcDig *restrict b, - size_t len) +static ssize_t +bc_num_compare(const BcDig* restrict a, const BcDig* restrict b, size_t len) { size_t i; BcDig c = 0; - for (i = len - 1; i < len && !(c = a[i] - b[i]); --i); + for (i = len - 1; i < len && !(c = a[i] - b[i]); --i) + { + continue; + } return bc_num_neg(i + 1, c < 0); } -ssize_t bc_num_cmp(const BcNum *a, const BcNum *b) { - +ssize_t +bc_num_cmp(const BcNum* a, const BcNum* b) +{ size_t i, min, a_int, b_int, diff, ardx, brdx; - BcDig *max_num, *min_num; + BcDig* max_num; + BcDig* min_num; bool a_max, neg = false; ssize_t cmp; @@ -402,7 +471,8 @@ ssize_t bc_num_cmp(const BcNum *a, const BcNum *b) { // Easy cases. if (BC_NUM_ZERO(a)) return bc_num_neg(b->len != 0, !BC_NUM_NEG(b)); if (BC_NUM_ZERO(b)) return bc_num_cmpZero(a); - if (BC_NUM_NEG(a)) { + if (BC_NUM_NEG(a)) + { if (BC_NUM_NEG(b)) neg = true; else return -1; } @@ -422,13 +492,15 @@ ssize_t bc_num_cmp(const BcNum *a, const BcNum *b) { a_max = (ardx > brdx); // Set variables based on the above. - if (a_max) { + if (a_max) + { min = brdx; diff = ardx - brdx; max_num = a->num + diff; min_num = b->num; } - else { + else + { min = ardx; diff = brdx - ardx; max_num = b->num + diff; @@ -443,15 +515,17 @@ ssize_t bc_num_cmp(const BcNum *a, const BcNum *b) { // If there was no difference, then the final step is to check which number // has greater or lesser limbs beyond the other's. - for (max_num -= diff, i = diff - 1; i < diff; --i) { + for (max_num -= diff, i = diff - 1; i < diff; --i) + { if (max_num[i]) return bc_num_neg(1, !a_max == !neg); } return 0; } -void bc_num_truncate(BcNum *restrict n, size_t places) { - +void +bc_num_truncate(BcNum* restrict n, size_t places) +{ size_t nrdx, places_rdx; if (!places) return; @@ -468,8 +542,8 @@ void bc_num_truncate(BcNum *restrict n, size_t places) { BC_NUM_RDX_SET(n, nrdx - places_rdx); // Only when the number is nonzero do we need to do the hard stuff. - if (BC_NUM_NONZERO(n)) { - + if (BC_NUM_NONZERO(n)) + { size_t pow; // This calculates how many decimal digits are in the least significant @@ -482,6 +556,7 @@ void bc_num_truncate(BcNum *restrict n, size_t places) { // We have to move limbs to maintain invariants. The limbs must begin at // the beginning of the BcNum array. + // NOLINTNEXTLINE memmove(n->num, n->num + places_rdx, BC_NUM_SIZE(n->len)); // Clear the lower part of the last digit. @@ -491,14 +566,16 @@ void bc_num_truncate(BcNum *restrict n, size_t places) { } } -void bc_num_extend(BcNum *restrict n, size_t places) { - +void +bc_num_extend(BcNum* restrict n, size_t places) +{ size_t nrdx, places_rdx; if (!places) return; // Easy case with zero; set the scale. - if (BC_NUM_ZERO(n)) { + if (BC_NUM_ZERO(n)) + { n->scale += places; return; } @@ -510,9 +587,12 @@ void bc_num_extend(BcNum *restrict n, size_t places) { // This is the hard case. We need to expand the number, move the limbs, and // set the limbs that were just cleared. - if (places_rdx) { + if (places_rdx) + { bc_num_expand(n, bc_vm_growSize(n->len, places_rdx)); + // NOLINTNEXTLINE memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len)); + // NOLINTNEXTLINE memset(n->num, 0, BC_NUM_SIZE(places_rdx)); } @@ -527,8 +607,8 @@ void bc_num_extend(BcNum *restrict n, size_t places) { /** * Retires (finishes) a multiplication or division operation. */ -static void bc_num_retireMul(BcNum *restrict n, size_t scale, - bool neg1, bool neg2) +static void +bc_num_retireMul(BcNum* restrict n, size_t scale, bool neg1, bool neg2) { // Make sure scale is correct. if (n->scale < scale) bc_num_extend(n, scale - n->scale); @@ -547,16 +627,17 @@ static void bc_num_retireMul(BcNum *restrict n, size_t scale, * @param a An out parameter; the low part of @a n. * @param b An out parameter; the high part of @a n. */ -static void bc_num_split(const BcNum *restrict n, size_t idx, - BcNum *restrict a, BcNum *restrict b) +static void +bc_num_split(const BcNum* restrict n, size_t idx, BcNum* restrict a, + BcNum* restrict b) { // We want a and b to be clear. assert(BC_NUM_ZERO(a)); assert(BC_NUM_ZERO(b)); // The usual case. - if (idx < n->len) { - + if (idx < n->len) + { // Set the fields first. b->len = n->len - idx; a->len = idx; @@ -569,7 +650,9 @@ static void bc_num_split(const BcNum *restrict n, size_t idx, // Copy the arrays. This is not necessary for safety, but it is faster, // for some reason. + // NOLINTNEXTLINE memcpy(b->num, n->num + idx, BC_NUM_SIZE(b->len)); + // NOLINTNEXTLINE memcpy(a->num, n->num, BC_NUM_SIZE(idx)); bc_num_clean(b); @@ -586,8 +669,9 @@ static void bc_num_split(const BcNum *restrict n, size_t idx, * @param n The number to copy. * @param r The result number with a shifted rdx, len, and num. */ -static void bc_num_shiftRdx(const BcNum *restrict n, BcNum *restrict r) { - +static void +bc_num_shiftRdx(const BcNum* restrict n, BcNum* restrict r) +{ size_t rdx = BC_NUM_RDX_VAL(n); r->len = n->len - rdx; @@ -603,15 +687,20 @@ static void bc_num_shiftRdx(const BcNum *restrict n, BcNum *restrict r) { * skipped. This must be undone by bc_num_unshiftZero(). * @param n The number to shift. */ -static size_t bc_num_shiftZero(BcNum *restrict n) { - - size_t i; +static size_t +bc_num_shiftZero(BcNum* restrict n) +{ + // This is volatile to quiet a GCC warning about longjmp() clobbering. + volatile size_t i; // If we don't have an integer, that is a problem, but it's also a bug // because the caller should have set everything up right. assert(!BC_NUM_RDX_VAL(n) || BC_NUM_ZERO(n)); - for (i = 0; i < n->len && !n->num[i]; ++i); + for (i = 0; i < n->len && !n->num[i]; ++i) + { + continue; + } n->len -= i; n->num += i; @@ -625,7 +714,9 @@ static size_t bc_num_shiftZero(BcNum *restrict n) { * @param n The number to unshift. * @param places_rdx The amount the number was originally shift. */ -static void bc_num_unshiftZero(BcNum *restrict n, size_t places_rdx) { +static void +bc_num_unshiftZero(BcNum* restrict n, size_t places_rdx) +{ n->len += places_rdx; n->num -= places_rdx; } @@ -638,11 +729,12 @@ static void bc_num_unshiftZero(BcNum *restrict n, size_t places_rdx) { * @param n The number to shift digits in. * @param dig The number of places to shift right. */ -static void bc_num_shift(BcNum *restrict n, BcBigDig dig) { - +static void +bc_num_shift(BcNum* restrict n, BcBigDig dig) +{ size_t i, len = n->len; BcBigDig carry = 0, pow; - BcDig *ptr = n->num; + BcDig* ptr = n->num; assert(dig < BC_BASE_DIGS); @@ -652,12 +744,14 @@ static void bc_num_shift(BcNum *restrict n, BcBigDig dig) { // Run a series of divisions and mods with carries across the entire number // array. This effectively shifts everything over. - for (i = len - 1; i < len; --i) { + for (i = len - 1; i < len; --i) + { BcBigDig in, temp; in = ((BcBigDig) ptr[i]); temp = carry * dig; carry = in % pow; ptr[i] = ((BcDig) (in / pow)) + (BcDig) temp; + assert(ptr[i] >= 0 && ptr[i] < BC_BASE_POW); } assert(!carry); @@ -669,8 +763,9 @@ static void bc_num_shift(BcNum *restrict n, BcBigDig dig) { * @param n The number to shift left. * @param places The amount of places to shift @a n left by. */ -static void bc_num_shiftLeft(BcNum *restrict n, size_t places) { - +static void +bc_num_shiftLeft(BcNum* restrict n, size_t places) +{ BcBigDig dig; size_t places_rdx; bool shift; @@ -678,13 +773,15 @@ static void bc_num_shiftLeft(BcNum *restrict n, size_t places) { if (!places) return; // Make sure to grow the number if necessary. - if (places > n->scale) { + if (places > n->scale) + { size_t size = bc_vm_growSize(BC_NUM_RDX(places - n->scale), n->len); if (size > SIZE_MAX - 1) bc_err(BC_ERR_MATH_OVERFLOW); } // If zero, we can just set the scale and bail. - if (BC_NUM_ZERO(n)) { + if (BC_NUM_ZERO(n)) + { if (n->scale >= places) n->scale -= places; else n->scale = 0; return; @@ -705,13 +802,13 @@ static void bc_num_shiftLeft(BcNum *restrict n, size_t places) { // integer doesn't is because left shift would only extend the integer, // whereas a non-integer might have its fractional part eliminated or only // partially eliminated. - if (n->scale) { - + if (n->scale) + { size_t nrdx = BC_NUM_RDX_VAL(n); // If the number's rdx is bigger, that's the hard case. - if (nrdx >= places_rdx) { - + if (nrdx >= places_rdx) + { size_t mod = n->scale % BC_BASE_DIGS, revdig; // We want mod to be in the range [1, BC_BASE_DIGS], not @@ -729,19 +826,24 @@ static void bc_num_shiftLeft(BcNum *restrict n, size_t places) { } // If this is non-zero, we need an extra place, so expand, move, and set. - if (places_rdx) { + if (places_rdx) + { bc_num_expand(n, bc_vm_growSize(n->len, places_rdx)); + // NOLINTNEXTLINE memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len)); + // NOLINTNEXTLINE memset(n->num, 0, BC_NUM_SIZE(places_rdx)); n->len += places_rdx; } // Set the scale appropriately. - if (places > n->scale) { + if (places > n->scale) + { n->scale = 0; BC_NUM_RDX_SET(n, 0); } - else { + else + { n->scale -= places; BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale)); } @@ -752,8 +854,9 @@ static void bc_num_shiftLeft(BcNum *restrict n, size_t places) { bc_num_clean(n); } -void bc_num_shiftRight(BcNum *restrict n, size_t places) { - +void +bc_num_shiftRight(BcNum* restrict n, size_t places) +{ BcBigDig dig; size_t places_rdx, scale, scale_mod, int_len, expand; bool shift; @@ -761,7 +864,8 @@ void bc_num_shiftRight(BcNum *restrict n, size_t places) { if (!places) return; // If zero, we can just set the scale and bail. - if (BC_NUM_ZERO(n)) { + if (BC_NUM_ZERO(n)) + { n->scale += places; bc_num_expand(n, BC_NUM_RDX(n->scale)); return; @@ -782,11 +886,13 @@ void bc_num_shiftRight(BcNum *restrict n, size_t places) { places_rdx = BC_NUM_RDX(places); // If we are going to shift past a limb boundary or not, set accordingly. - if (scale_mod + dig > BC_BASE_DIGS) { + if (scale_mod + dig > BC_BASE_DIGS) + { expand = places_rdx - 1; places_rdx = 1; } - else { + else + { expand = places_rdx; places_rdx = 0; } @@ -798,6 +904,7 @@ void bc_num_shiftRight(BcNum *restrict n, size_t places) { // Extend, expand, and zero. bc_num_extend(n, places_rdx * BC_BASE_DIGS); bc_num_expand(n, bc_vm_growSize(expand, n->len)); + // NOLINTNEXTLINE memset(n->num + n->len, 0, BC_NUM_SIZE(expand)); // Set the fields. @@ -818,17 +925,6 @@ void bc_num_shiftRight(BcNum *restrict n, size_t places) { } /** - * Invert @a into @a b at the current scale. - * @param a The number to invert. - * @param b The return parameter. This must be preallocated. - * @param scale The current scale. - */ -static inline void bc_num_inv(BcNum *a, BcNum *b, size_t scale) { - assert(BC_NUM_NONZERO(a)); - bc_num_div(&vm.one, a, b, scale); -} - -/** * Tests if a number is a integer with scale or not. Returns true if the number * is not an integer. If it is, its integer shifted form is copied into the * result parameter for use where only integers are allowed. @@ -837,19 +933,25 @@ static inline void bc_num_inv(BcNum *a, BcNum *b, size_t scale) { * *not* be allocated. * @return True if the number is a non-integer, false otherwise. */ -static bool bc_num_nonInt(const BcNum *restrict n, BcNum *restrict r) { - +static bool +bc_num_nonInt(const BcNum* restrict n, BcNum* restrict r) +{ bool zero; size_t i, rdx = BC_NUM_RDX_VAL(n); - if (!rdx) { + if (!rdx) + { + // NOLINTNEXTLINE memcpy(r, n, sizeof(BcNum)); return false; } zero = true; - for (i = 0; zero && i < rdx; ++i) zero = (n->num[i] == 0); + for (i = 0; zero && i < rdx; ++i) + { + zero = (n->num[i] == 0); + } if (BC_ERR(!zero)) return true; @@ -868,10 +970,17 @@ static bool bc_num_nonInt(const BcNum *restrict n, BcNum *restrict r) { * @param c The result operand. * @return The second operand as a hardware integer. */ -static BcBigDig bc_num_intop(const BcNum *a, const BcNum *b, BcNum *restrict c) +static BcBigDig +bc_num_intop(const BcNum* a, const BcNum* b, BcNum* restrict c) { BcNum temp; +#if BC_GCC + temp.len = 0; + temp.rdx = 0; + temp.num = NULL; +#endif // BC_GCC + if (BC_ERR(bc_num_nonInt(b, &temp))) bc_err(BC_ERR_MATH_NON_INTEGER); bc_num_copy(c, a); @@ -890,19 +999,24 @@ static BcBigDig bc_num_intop(const BcNum *a, const BcNum *b, BcNum *restrict c) * @param c The return parameter. * @param sub Non-zero for a subtract, zero for an add. */ -static void bc_num_as(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) { - - BcDig *ptr_c, *ptr_l, *ptr_r; +static void +bc_num_as(BcNum* a, BcNum* b, BcNum* restrict c, size_t sub) +{ + BcDig* ptr_c; + BcDig* ptr_l; + BcDig* ptr_r; size_t i, min_rdx, max_rdx, diff, a_int, b_int, min_len, max_len, max_int; size_t len_l, len_r, ardx, brdx; bool b_neg, do_sub, do_rev_sub, carry, c_neg; - if (BC_NUM_ZERO(b)) { + if (BC_NUM_ZERO(b)) + { bc_num_copy(c, a); return; } - if (BC_NUM_ZERO(a)) { + if (BC_NUM_ZERO(a)) + { bc_num_copy(c, b); c->rdx = BC_NUM_NEG_VAL(c, BC_NUM_NEG(b) != sub); return; @@ -930,17 +1044,18 @@ static void bc_num_as(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) { max_len = max_int + max_rdx; - if (do_sub) { - + if (do_sub) + { // Check whether b has to be subtracted from a or a from b. if (a_int != b_int) do_rev_sub = (a_int < b_int); else if (ardx > brdx) + { do_rev_sub = (bc_num_compare(a->num + diff, b->num, b->len) < 0); - else - do_rev_sub = (bc_num_compare(a->num, b->num + diff, a->len) <= 0); + } + else do_rev_sub = (bc_num_compare(a->num, b->num + diff, a->len) <= 0); } - else { - + else + { // The result array of the addition might come out one element // longer than the bigger of the operand arrays. max_len += 1; @@ -950,13 +1065,15 @@ static void bc_num_as(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) { assert(max_len <= c->cap); // Cache values for simple code later. - if (do_rev_sub) { + if (do_rev_sub) + { ptr_l = b->num; ptr_r = a->num; len_l = b->len; len_r = a->len; } - else { + else + { ptr_l = a->num; ptr_r = b->num; len_l = a->len; @@ -968,34 +1085,38 @@ static void bc_num_as(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) { // This is true if the numbers have a different number of limbs after the // decimal point. - if (diff) { - + if (diff) + { // If the rdx values of the operands do not match, the result will // have low end elements that are the positive or negative trailing // elements of the operand with higher rdx value. - if ((ardx > brdx) != do_rev_sub) { - + if ((ardx > brdx) != do_rev_sub) + { // !do_rev_sub && ardx > brdx || do_rev_sub && brdx > ardx // The left operand has BcDig values that need to be copied, // either from a or from b (in case of a reversed subtraction). + // NOLINTNEXTLINE memcpy(ptr_c, ptr_l, BC_NUM_SIZE(diff)); ptr_l += diff; len_l -= diff; } - else { - + else + { // The right operand has BcDig values that need to be copied // or subtracted from zero (in case of a subtraction). - if (do_sub) { - + if (do_sub) + { // do_sub (do_rev_sub && ardx > brdx || // !do_rev_sub && brdx > ardx) for (i = 0; i < diff; i++) + { ptr_c[i] = bc_num_subDigits(0, ptr_r[i], &carry); + } } - else { - + else + { // !do_sub && brdx > ardx + // NOLINTNEXTLINE memcpy(ptr_c, ptr_r, BC_NUM_SIZE(diff)); } @@ -1018,23 +1139,33 @@ static void bc_num_as(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) { // Inlining takes care of eliminating constant zero arguments to // addDigit/subDigit (checked in disassembly of resulting bc binary // compiled with gcc and clang). - if (do_sub) { - + if (do_sub) + { // Actual subtraction. for (i = 0; i < min_len; ++i) + { ptr_c[i] = bc_num_subDigits(ptr_l[i], ptr_r[i], &carry); + } // Finishing the limbs beyond the direct subtraction. - for (; i < len_l; ++i) ptr_c[i] = bc_num_subDigits(ptr_l[i], 0, &carry); + for (; i < len_l; ++i) + { + ptr_c[i] = bc_num_subDigits(ptr_l[i], 0, &carry); + } } - else { - + else + { // Actual addition. for (i = 0; i < min_len; ++i) + { ptr_c[i] = bc_num_addDigits(ptr_l[i], ptr_r[i], &carry); + } // Finishing the limbs beyond the direct addition. - for (; i < len_l; ++i) ptr_c[i] = bc_num_addDigits(ptr_l[i], 0, &carry); + for (; i < len_l; ++i) + { + ptr_c[i] = bc_num_addDigits(ptr_l[i], 0, &carry); + } // Addition can create an extra limb. We take care of that here. ptr_c[i] = bc_num_addDigits(0, 0, &carry); @@ -1060,10 +1191,13 @@ static void bc_num_as(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) { * @param b The second operand. * @param c The return parameter. */ -static void bc_num_m_simp(const BcNum *a, const BcNum *b, BcNum *restrict c) { - +static void +bc_num_m_simp(const BcNum* a, const BcNum* b, BcNum* restrict c) +{ size_t i, alen = a->len, blen = b->len, clen; - BcDig *ptr_a = a->num, *ptr_b = b->num, *ptr_c; + BcDig* ptr_a = a->num; + BcDig* ptr_b = b->num; + BcDig* ptr_c; BcBigDig sum = 0, carry = 0; assert(sizeof(sum) >= sizeof(BcDig) * 2); @@ -1075,14 +1209,15 @@ static void bc_num_m_simp(const BcNum *a, const BcNum *b, BcNum *restrict c) { // If we don't memset, then we might have uninitialized data use later. ptr_c = c->num; + // NOLINTNEXTLINE memset(ptr_c, 0, BC_NUM_SIZE(c->cap)); // This is the actual multiplication loop. It uses the lattice form of long // multiplication (see the explanation on the web page at // https://knilt.arcc.albany.edu/What_is_Lattice_Multiplication or the // explanation at Wikipedia). - for (i = 0; i < clen; ++i) { - + for (i = 0; i < clen; ++i) + { ssize_t sidx = (ssize_t) (i - blen + 1); size_t j, k; @@ -1092,18 +1227,20 @@ static void bc_num_m_simp(const BcNum *a, const BcNum *b, BcNum *restrict c) { // On every iteration of this loop, a multiplication happens, then the // sum is automatically calculated. - for (; j < alen && k < blen; ++j, --k) { - + for (; j < alen && k < blen; ++j, --k) + { sum += ((BcBigDig) ptr_a[j]) * ((BcBigDig) ptr_b[k]); - if (sum >= ((BcBigDig) BC_BASE_POW) * BC_BASE_POW) { + if (sum >= ((BcBigDig) BC_BASE_POW) * BC_BASE_POW) + { carry += sum / BC_BASE_POW; sum %= BC_BASE_POW; } } // Calculate the carry. - if (sum >= BC_BASE_POW) { + if (sum >= BC_BASE_POW) + { carry += sum / BC_BASE_POW; sum %= BC_BASE_POW; } @@ -1131,8 +1268,9 @@ static void bc_num_m_simp(const BcNum *a, const BcNum *b, BcNum *restrict c) { * @param op The function to call, either bc_num_addArrays() or * bc_num_subArrays(). */ -static void bc_num_shiftAddSub(BcNum *restrict n, const BcNum *restrict a, - size_t shift, BcNumShiftAddOp op) +static void +bc_num_shiftAddSub(BcNum* restrict n, const BcNum* restrict a, size_t shift, + BcNumShiftAddOp op) { assert(n->len >= shift + a->len); assert(!BC_NUM_RDX_VAL(n) && !BC_NUM_RDX_VAL(a)); @@ -1142,26 +1280,33 @@ static void bc_num_shiftAddSub(BcNum *restrict n, const BcNum *restrict a, /** * Implements the Karatsuba algorithm. */ -static void bc_num_k(const BcNum *a, const BcNum *b, BcNum *restrict c) { - +static void +bc_num_k(const BcNum* a, const BcNum* b, BcNum* restrict c) +{ size_t max, max2, total; BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp; - BcDig *digs, *dig_ptr; + BcDig* digs; + BcDig* dig_ptr; BcNumShiftAddOp op; bool aone = BC_NUM_ONE(a); +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY assert(BC_NUM_ZERO(c)); if (BC_NUM_ZERO(a) || BC_NUM_ZERO(b)) return; - if (aone || BC_NUM_ONE(b)) { + if (aone || BC_NUM_ONE(b)) + { bc_num_copy(c, aone ? b : a); if ((aone && BC_NUM_NEG(a)) || BC_NUM_NEG(b)) BC_NUM_NEG_TGL(c); return; } // Shell out to the simple algorithm with certain conditions. - if (a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN) { + if (a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN) + { bc_num_m_simp(a, b, c); return; } @@ -1203,13 +1348,14 @@ static void bc_num_k(const BcNum *a, const BcNum *b, BcNum *restrict c) { max = bc_vm_growSize(max, max) + 1; bc_num_init(&temp, max); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; // First, set up c. bc_num_expand(c, max); c->len = max; + // NOLINTNEXTLINE memset(c->num, 0, BC_NUM_SIZE(c->len)); // Split the parameters. @@ -1225,8 +1371,8 @@ static void bc_num_k(const BcNum *a, const BcNum *b, BcNum *restrict c) { // the ollocations and splits are done, the algorithm is pretty // straightforward. - if (BC_NUM_NONZERO(&h1) && BC_NUM_NONZERO(&h2)) { - + if (BC_NUM_NONZERO(&h1) && BC_NUM_NONZERO(&h2)) + { assert(BC_NUM_RDX_VALID_NP(h1)); assert(BC_NUM_RDX_VALID_NP(h2)); @@ -1237,8 +1383,8 @@ static void bc_num_k(const BcNum *a, const BcNum *b, BcNum *restrict c) { bc_num_shiftAddSub(c, &z2, max2, bc_num_addArrays); } - if (BC_NUM_NONZERO(&l1) && BC_NUM_NONZERO(&l2)) { - + if (BC_NUM_NONZERO(&l1) && BC_NUM_NONZERO(&l2)) + { assert(BC_NUM_RDX_VALID_NP(l1)); assert(BC_NUM_RDX_VALID_NP(l2)); @@ -1249,8 +1395,8 @@ static void bc_num_k(const BcNum *a, const BcNum *b, BcNum *restrict c) { bc_num_shiftAddSub(c, &z0, 0, bc_num_addArrays); } - if (BC_NUM_NONZERO(&m1) && BC_NUM_NONZERO(&m2)) { - + if (BC_NUM_NONZERO(&m1) && BC_NUM_NONZERO(&m2)) + { assert(BC_NUM_RDX_VALID_NP(m1)); assert(BC_NUM_RDX_VALID_NP(m1)); @@ -1258,7 +1404,8 @@ static void bc_num_k(const BcNum *a, const BcNum *b, BcNum *restrict c) { bc_num_clean(&z1); op = (BC_NUM_NEG_NP(m1) != BC_NUM_NEG_NP(m2)) ? - bc_num_subArrays : bc_num_addArrays; + bc_num_subArrays : + bc_num_addArrays; bc_num_shiftAddSub(c, &z1, max2, op); } @@ -1269,7 +1416,7 @@ err: bc_num_free(&z2); bc_num_free(&z1); bc_num_free(&z0); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } /** @@ -1281,10 +1428,21 @@ err: * @param c The return parameter. * @param scale The current scale. */ -static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - +static void +bc_num_m(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale) +{ BcNum cpa, cpb; - size_t ascale, bscale, ardx, brdx, azero = 0, bzero = 0, zero, len, rscale; + size_t ascale, bscale, ardx, brdx, zero, len, rscale; + // These are meant to quiet warnings on GCC about longjmp() clobbering. + // The problem is real here. + size_t scale1, scale2, realscale; + // These are meant to quiet the GCC longjmp() clobbering, even though it + // does not apply here. + volatile size_t azero; + volatile size_t bzero; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); @@ -1295,24 +1453,26 @@ static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { bscale = b->scale; // This sets the final scale according to the bc spec. - scale = BC_MAX(scale, ascale); - scale = BC_MAX(scale, bscale); + scale1 = BC_MAX(scale, ascale); + scale2 = BC_MAX(scale1, bscale); rscale = ascale + bscale; - scale = BC_MIN(rscale, scale); + realscale = BC_MIN(rscale, scale2); // If this condition is true, we can use bc_num_mulArray(), which would be // much faster. - if ((a->len == 1 || b->len == 1) && !a->rdx && !b->rdx) { - - BcNum *operand; + if ((a->len == 1 || b->len == 1) && !a->rdx && !b->rdx) + { + BcNum* operand; BcBigDig dig; // Set the correct operands. - if (a->len == 1) { + if (a->len == 1) + { dig = (BcBigDig) a->num[0]; operand = b; } - else { + else + { dig = (BcBigDig) b->num[0]; operand = a; } @@ -1321,7 +1481,9 @@ static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { // Need to make sure the sign is correct. if (BC_NUM_NONZERO(c)) + { c->rdx = BC_NUM_NEG_VAL(c, BC_NUM_NEG(a) != BC_NUM_NEG(b)); + } return; } @@ -1336,7 +1498,7 @@ static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { bc_num_init(&cpa, a->len + BC_NUM_RDX_VAL(a)); bc_num_init(&cpb, b->len + BC_NUM_RDX_VAL(b)); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, init_err); BC_SIG_UNLOCK; @@ -1364,13 +1526,13 @@ static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { // jump. BC_SIG_LOCK; - BC_UNSETJMP; + BC_UNSETJMP(vm); // We want to ignore zero limbs. azero = bc_num_shiftZero(&cpa); bzero = bc_num_shiftZero(&cpb); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; @@ -1391,15 +1553,17 @@ static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { bc_num_shiftLeft(c, (len - c->len) * BC_BASE_DIGS); bc_num_shiftRight(c, ardx + brdx); - bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b)); + bc_num_retireMul(c, realscale, BC_NUM_NEG(a), BC_NUM_NEG(b)); err: BC_SIG_MAYLOCK; bc_num_unshiftZero(&cpb, bzero); - bc_num_free(&cpb); bc_num_unshiftZero(&cpa, azero); +init_err: + BC_SIG_MAYLOCK; + bc_num_free(&cpb); bc_num_free(&cpa); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } /** @@ -1408,11 +1572,17 @@ err: * @param len The length of the array. * @return True if @a has any non-zero limbs, false otherwise. */ -static bool bc_num_nonZeroDig(BcDig *restrict a, size_t len) { +static bool +bc_num_nonZeroDig(BcDig* restrict a, size_t len) +{ size_t i; - bool nonzero = false; - for (i = len - 1; !nonzero && i < len; --i) nonzero = (a[i] != 0); - return nonzero; + + for (i = len - 1; i < len; --i) + { + if (a[i] != 0) return true; + } + + return false; } /** @@ -1424,12 +1594,14 @@ static bool bc_num_nonZeroDig(BcDig *restrict a, size_t len) { * @param len The length to assume the arrays are. This is always less than the * actual length because of how this is implemented. */ -static ssize_t bc_num_divCmp(const BcDig *a, const BcNum *b, size_t len) { - +static ssize_t +bc_num_divCmp(const BcDig* a, const BcNum* b, size_t len) +{ ssize_t cmp; if (b->len > len && a[len]) cmp = bc_num_compare(a, b->num, len + 1); - else if (b->len <= len) { + else if (b->len <= len) + { if (a[len]) cmp = 1; else cmp = bc_num_compare(a, b->num, len); } @@ -1446,8 +1618,8 @@ static ssize_t bc_num_divCmp(const BcDig *a, const BcNum *b, size_t len) { * @param b The second operand. * @param divisor The divisor estimate. */ -static void bc_num_divExtend(BcNum *restrict a, BcNum *restrict b, - BcBigDig divisor) +static void +bc_num_divExtend(BcNum* restrict a, BcNum* restrict b, BcBigDig divisor) { size_t pow; @@ -1467,13 +1639,28 @@ static void bc_num_divExtend(BcNum *restrict a, BcNum *restrict b, * @param c The return parameter. * @param scale The current scale. */ -static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, - BcNum *restrict c, size_t scale) +static void +bc_num_d_long(BcNum* restrict a, BcNum* restrict b, BcNum* restrict c, + size_t scale) { BcBigDig divisor; - size_t len, end, i, rdx; + size_t i, rdx; + // This is volatile and len 2 and reallen exist to quiet the GCC warning + // about clobbering on longjmp(). This one is possible, I think. + volatile size_t len; + size_t len2, reallen; + // This is volatile and realend exists to quiet the GCC warning about + // clobbering on longjmp(). This one is possible, I think. + volatile size_t end; + size_t realend; BcNum cpb; - bool nonzero = false; + // This is volatile and realnonzero exists to quiet the GCC warning about + // clobbering on longjmp(). This one is possible, I think. + volatile bool nonzero; + bool realnonzero; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY assert(b->len < a->len); @@ -1485,6 +1672,7 @@ static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, // This is a final time to make sure c is big enough and that its array is // properly zeroed. bc_num_expand(c, a->len); + // NOLINTNEXTLINE memset(c->num, 0, c->cap * sizeof(BcDig)); // Setup. @@ -1498,8 +1686,8 @@ static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, // The entire bit of code in this if statement is to tighten the estimate of // the divisor. The condition asks if b has any other non-zero limbs. - if (len > 1 && bc_num_nonZeroDig(b->num, len - 1)) { - + if (len > 1 && bc_num_nonZeroDig(b->num, len - 1)) + { // This takes a little bit of understanding. The "10*BC_BASE_DIGS/6+1" // results in either 16 for 64-bit 9-digit limbs or 7 for 32-bit 4-digit // limbs. Then it shifts a 1 by that many, which in both cases, puts the @@ -1509,36 +1697,47 @@ static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, nonzero = (divisor > 1 << ((10 * BC_BASE_DIGS) / 6 + 1)); // If the divisor is *not* greater than half the limb... - if (!nonzero) { - + if (!nonzero) + { // Extend the parameters by the number of missing digits in the // divisor. bc_num_divExtend(a, b, divisor); // Check bc_num_d(). In there, we grow a again and again. We do it // again here; we *always* want to be sure it is big enough. - len = BC_MAX(a->len, b->len); - bc_num_expand(a, len + 1); + len2 = BC_MAX(a->len, b->len); + bc_num_expand(a, len2 + 1); // Make a have a zero most significant limb to match the len. - if (len + 1 > a->len) a->len = len + 1; + if (len2 + 1 > a->len) a->len = len2 + 1; // Grab the new divisor estimate, new because the shift has made it // different. - len = b->len; - end = a->len - len; - divisor = (BcBigDig) b->num[len - 1]; + reallen = b->len; + realend = a->len - reallen; + divisor = (BcBigDig) b->num[reallen - 1]; - nonzero = bc_num_nonZeroDig(b->num, len - 1); + realnonzero = bc_num_nonZeroDig(b->num, reallen - 1); + } + else + { + realend = end; + realnonzero = nonzero; } } + else + { + realend = end; + realnonzero = false; + } // If b has other nonzero limbs, we want the divisor to be one higher, so // that it is an upper bound. - divisor += nonzero; + divisor += realnonzero; // Make sure c can fit the new length. bc_num_expand(c, a->len); + // NOLINTNEXTLINE memset(c->num, 0, BC_NUM_SIZE(c->cap)); assert(c->scale >= scale); @@ -1548,15 +1747,15 @@ static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, bc_num_init(&cpb, len + 1); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; // This is the actual division loop. - for (i = end - 1; i < end && i >= rdx && BC_NUM_NONZERO(a); --i) { - + for (i = realend - 1; i < realend && i >= rdx && BC_NUM_NONZERO(a); --i) + { ssize_t cmp; - BcDig *n; + BcDig* n; BcBigDig result; n = a->num + i; @@ -1568,8 +1767,8 @@ static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, // This is true if n is greater than b, which means that division can // proceed, so this inner loop is the part that implements one instance // of the division. - while (cmp >= 0) { - + while (cmp >= 0) + { BcBigDig n1, dividend, quotient; // These should be named obviously enough. Just imagine that it's a @@ -1581,12 +1780,13 @@ static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, // If this is true, then we can just subtract. Remember: setting // quotient to 1 is not bad because we already know that n is // greater than b. - if (quotient <= 1) { + if (quotient <= 1) + { quotient = 1; bc_num_subArrays(n, b->num, len); } - else { - + else + { assert(quotient <= BC_BASE_POW); // We need to multiply and subtract for a quotient above 1. @@ -1602,7 +1802,7 @@ static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, // And here's why it might take multiple trips: n might *still* be // greater than b. So we have to loop again. That's what this is // setting up for: the condition of the while loop. - if (nonzero) cmp = bc_num_divCmp(n, b, len); + if (realnonzero) cmp = bc_num_divCmp(n, b, len); else cmp = -1; } @@ -1615,7 +1815,7 @@ static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, err: BC_SIG_MAYLOCK; bc_num_free(&cpb); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } /** @@ -1625,26 +1825,33 @@ err: * @param c The return parameter. * @param scale The current scale. */ -static void bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - +static void +bc_num_d(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale) +{ size_t len, cpardx; BcNum cpa, cpb; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); - if (BC_NUM_ZERO(a)) { + if (BC_NUM_ZERO(a)) + { bc_num_setToZero(c, scale); return; } - if (BC_NUM_ONE(b)) { + if (BC_NUM_ONE(b)) + { bc_num_copy(c, a); bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b)); return; } // If this is true, we can use bc_num_divArray(), which would be faster. - if (!BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b) && b->len == 1 && !scale) { + if (!BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b) && b->len == 1 && !scale) + { BcBigDig rem; bc_num_divArray(a, (BcBigDig) b->num[0], c, &rem); bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b)); @@ -1662,7 +1869,7 @@ static void bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { bc_num_copy(&cpa, a); bc_num_createCopy(&cpb, b); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; @@ -1670,7 +1877,8 @@ static void bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { // Like the above comment, we want the copy of the first parameter to be // larger than the second parameter. - if (len > cpa.len) { + if (len > cpa.len) + { bc_num_expand(&cpa, bc_vm_growSize(len, 2)); bc_num_extend(&cpa, (len - cpa.len) * BC_BASE_DIGS); } @@ -1685,7 +1893,8 @@ static void bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { cpa.scale = cpardx * BC_BASE_DIGS; // Once again, just setting things up, this time to match scale. - if (scale > cpa.scale) { + if (scale > cpa.scale) + { bc_num_extend(&cpa, scale); cpardx = BC_NUM_RDX_VAL_NP(cpa); cpa.scale = cpardx * BC_BASE_DIGS; @@ -1715,7 +1924,7 @@ err: BC_SIG_MAYLOCK; bc_num_free(&cpb); bc_num_free(&cpa); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } /** @@ -1730,15 +1939,23 @@ err: * @param ts The scale that the operation should be done to. Yes, it's not * necessarily the same as scale, per the bc spec. */ -static void bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c, - BcNum *restrict d, size_t scale, size_t ts) +static void +bc_num_r(BcNum* a, BcNum* b, BcNum* restrict c, BcNum* restrict d, size_t scale, + size_t ts) { BcNum temp; + // realscale is meant to quiet a warning on GCC about longjmp() clobbering. + // This one is real. + size_t realscale; bool neg; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); - if (BC_NUM_ZERO(a)) { + if (BC_NUM_ZERO(a)) + { bc_num_setToZero(c, ts); bc_num_setToZero(d, ts); return; @@ -1748,7 +1965,7 @@ static void bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c, bc_num_init(&temp, d->cap); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; @@ -1756,14 +1973,15 @@ static void bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c, bc_num_d(a, b, c, scale); // We want an extra digit so we can safely truncate. - if (scale) scale = ts + 1; + if (scale) realscale = ts + 1; + else realscale = scale; assert(BC_NUM_RDX_VALID(c)); assert(BC_NUM_RDX_VALID(b)); // Implement the rest of the (a - (a / b) * b) formula. - bc_num_m(c, b, &temp, scale); - bc_num_sub(a, &temp, d, scale); + bc_num_m(c, b, &temp, realscale); + bc_num_sub(a, &temp, d, realscale); // Extend if necessary. if (ts > d->scale && BC_NUM_NONZERO(d)) bc_num_extend(d, ts - d->scale); @@ -1775,7 +1993,7 @@ static void bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c, err: BC_SIG_MAYLOCK; bc_num_free(&temp); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } /** @@ -1786,10 +2004,14 @@ err: * @param c The return parameter. * @param scale The current scale. */ -static void bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - +static void +bc_num_rem(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale) +{ BcNum c1; size_t ts; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY ts = bc_vm_growSize(scale, b->scale); ts = BC_MAX(ts, a->scale); @@ -1799,7 +2021,7 @@ static void bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { // Need a temp for the quotient. bc_num_init(&c1, bc_num_mulReq(a, b, ts)); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; @@ -1808,7 +2030,7 @@ static void bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { err: BC_SIG_MAYLOCK; bc_num_free(&c1); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } /** @@ -1818,27 +2040,45 @@ err: * @param c The return parameter. * @param scale The current scale. */ -static void bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - +static void +bc_num_p(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale) +{ BcNum copy, btemp; BcBigDig exp; - size_t powrdx, resrdx; + // realscale is meant to quiet a warning on GCC about longjmp() clobbering. + // This one is real. + size_t powrdx, resrdx, realscale; bool neg; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY + + // This is here to silence a warning from GCC. +#if BC_GCC + btemp.len = 0; + btemp.rdx = 0; + btemp.num = NULL; +#endif // BC_GCC if (BC_ERR(bc_num_nonInt(b, &btemp))) bc_err(BC_ERR_MATH_NON_INTEGER); - if (BC_NUM_ZERO(&btemp)) { + assert(btemp.len == 0 || btemp.num != NULL); + + if (BC_NUM_ZERO(&btemp)) + { bc_num_one(c); return; } - if (BC_NUM_ZERO(a)) { + if (BC_NUM_ZERO(a)) + { if (BC_NUM_NEG_NP(btemp)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); bc_num_setToZero(c, scale); return; } - if (BC_NUM_ONE(&btemp)) { + if (BC_NUM_ONE(&btemp)) + { if (!BC_NUM_NEG_NP(btemp)) bc_num_copy(c, a); else bc_num_inv(a, c, scale); return; @@ -1853,21 +2093,24 @@ static void bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { bc_num_createCopy(©, a); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; // If this is true, then we do not have to do a division, and we need to // set scale accordingly. - if (!neg) { + if (!neg) + { size_t max = BC_MAX(scale, a->scale), scalepow; scalepow = bc_num_mulOverflow(a->scale, exp); - scale = BC_MIN(scalepow, max); + realscale = BC_MIN(scalepow, max); } + else realscale = scale; // This is only implementing the first exponentiation by squaring, until it // reaches the first time where the square is actually used. - for (powrdx = a->scale; !(exp & 1); exp >>= 1) { + for (powrdx = a->scale; !(exp & 1); exp >>= 1) + { powrdx <<= 1; assert(BC_NUM_RDX_VALID_NP(copy)); bc_num_mul(©, ©, ©, powrdx); @@ -1880,15 +2123,16 @@ static void bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { // Now finish the exponentiation by squaring, this time saving the squares // as necessary. - while (exp >>= 1) { - + while (exp >>= 1) + { powrdx <<= 1; assert(BC_NUM_RDX_VALID_NP(copy)); bc_num_mul(©, ©, ©, powrdx); // If this is true, we want to save that particular square. This does // that by multiplying c with copy. - if (exp & 1) { + if (exp & 1) + { resrdx += powrdx; assert(BC_NUM_RDX_VALID(c)); assert(BC_NUM_RDX_VALID_NP(copy)); @@ -1897,17 +2141,17 @@ static void bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { } // Invert if necessary. - if (neg) bc_num_inv(c, c, scale); + if (neg) bc_num_inv(c, c, realscale); // Truncate if necessary. - if (c->scale > scale) bc_num_truncate(c, c->scale - scale); + if (c->scale > realscale) bc_num_truncate(c, c->scale - realscale); bc_num_clean(c); err: BC_SIG_MAYLOCK; bc_num_free(©); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } #if BC_ENABLE_EXTRA_MATH @@ -1918,8 +2162,9 @@ err: * @param c The return parameter. * @param scale The current scale. */ -static void bc_num_place(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - +static void +bc_num_place(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale) +{ BcBigDig val; BC_UNUSED(scale); @@ -1934,8 +2179,9 @@ static void bc_num_place(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { /** * Implements the left shift operator. This is a BcNumBinOp function. */ -static void bc_num_left(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - +static void +bc_num_left(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale) +{ BcBigDig val; BC_UNUSED(scale); @@ -1948,8 +2194,9 @@ static void bc_num_left(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { /** * Implements the right shift operator. This is a BcNumBinOp function. */ -static void bc_num_right(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - +static void +bc_num_right(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale) +{ BcBigDig val; BC_UNUSED(scale); @@ -1980,11 +2227,16 @@ static void bc_num_right(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { * @param scale The current scale. * @param req The number of limbs needed to fit the result. */ -static void bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale, - BcNumBinOp op, size_t req) +static void +bc_num_binary(BcNum* a, BcNum* b, BcNum* c, size_t scale, BcNumBinOp op, + size_t req) { - BcNum *ptr_a, *ptr_b, num2; - bool init = false; + BcNum* ptr_a; + BcNum* ptr_b; + BcNum num2; +#if BC_ENABLE_LIBRARY + BcVm* vm = NULL; +#endif // BC_ENABLE_LIBRARY assert(a != NULL && b != NULL && c != NULL && op != NULL); @@ -1993,44 +2245,29 @@ static void bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale, BC_SIG_LOCK; - // Reallocate if c == a. - if (c == a) { - - ptr_a = &num2; - - memcpy(ptr_a, c, sizeof(BcNum)); - init = true; - } - else { - ptr_a = a; - } - - // Also reallocate if c == b. - if (c == b) { - - ptr_b = &num2; - - if (c != a) { - memcpy(ptr_b, c, sizeof(BcNum)); - init = true; - } - } - else { - ptr_b = b; - } + ptr_a = c == a ? &num2 : a; + ptr_b = c == b ? &num2 : b; // Actually reallocate. If we don't reallocate, we want to expand at the // very least. - if (init) { + if (c == a || c == b) + { +#if BC_ENABLE_LIBRARY + vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY + + // NOLINTNEXTLINE + memcpy(&num2, c, sizeof(BcNum)); bc_num_init(c, req); // Must prepare for cleanup. We want this here so that locals that got // set stay set since a longjmp() is not guaranteed to preserve locals. - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; } - else { + else + { BC_SIG_UNLOCK; bc_num_expand(c, req); } @@ -2049,15 +2286,14 @@ static void bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale, err: // Cleanup only needed if we initialized c to a new number. - if (init) { + if (c == a || c == b) + { BC_SIG_MAYLOCK; bc_num_free(&num2); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } } -#if !defined(NDEBUG) || BC_ENABLE_LIBRARY - /** * Tests a number string for validity. This function has a history; I originally * wrote it because I did not trust my parser. Over time, however, I came to @@ -2067,8 +2303,9 @@ err: * @param val The string to check to see if it's a valid number string. * @return True if the string is a valid number string, false otherwise. */ -bool bc_num_strValid(const char *restrict val) { - +bool +bc_num_strValid(const char* restrict val) +{ bool radix = false; size_t i, len = strlen(val); @@ -2080,13 +2317,13 @@ bool bc_num_strValid(const char *restrict val) { if (!len) return true; // Loop through the characters. - for (i = 0; i < len; ++i) { - + for (i = 0; i < len; ++i) + { BcDig c = val[i]; // If we have found a radix point... - if (c == '.') { - + if (c == '.') + { // We don't allow two radices. if (radix) return false; @@ -2100,7 +2337,6 @@ bool bc_num_strValid(const char *restrict val) { return true; } -#endif // !defined(NDEBUG) || BC_ENABLE_LIBRARY /** * Parses one character and returns the digit that corresponds to that @@ -2109,18 +2345,26 @@ bool bc_num_strValid(const char *restrict val) { * @param base The base. * @return The character as a digit. */ -static BcBigDig bc_num_parseChar(char c, size_t base) { - +static BcBigDig +bc_num_parseChar(char c, size_t base) +{ assert(isupper(c) || isdigit(c)); // If a letter... - if (isupper(c)) { + if (isupper(c)) + { +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY // This returns the digit that directly corresponds with the letter. c = BC_NUM_NUM_LETTER(c); // If the digit is greater than the base, we clamp. - c = ((size_t) c) >= base ? (char) base - 1 : c; + if (BC_DIGIT_CLAMP) + { + c = ((size_t) c) >= base ? (char) base - 1 : c; + } } // Straight convert the digit to a number. else c -= '0'; @@ -2134,14 +2378,21 @@ static BcBigDig bc_num_parseChar(char c, size_t base) { * @param n The number to parse into and return. Must be preallocated. * @param val The string to parse. */ -static void bc_num_parseDecimal(BcNum *restrict n, const char *restrict val) { - +static void +bc_num_parseDecimal(BcNum* restrict n, const char* restrict val) +{ size_t len, i, temp, mod; - const char *ptr; + const char* ptr; bool zero = true, rdx; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY // Eat leading zeroes. - for (i = 0; val[i] == '0'; ++i); + for (i = 0; val[i] == '0'; ++i) + { + continue; + } val += i; assert(!val[0] || isalnum(val[0]) || val[0] == '.'); @@ -2161,13 +2412,16 @@ static void bc_num_parseDecimal(BcNum *restrict n, const char *restrict val) { // We eat leading zeroes again. These leading zeroes are different because // they will come after the decimal point if they exist, and since that's // the case, they must be preserved. - for (i = 0; i < len && (zero = (val[i] == '0' || val[i] == '.')); ++i); + for (i = 0; i < len && (zero = (val[i] == '0' || val[i] == '.')); ++i) + { + continue; + } // Set the scale of the number based on the location of the decimal point. // The casts to uintptr_t is to ensure that bc does not hit undefined // behavior when doing math on the values. - n->scale = (size_t) (rdx * (((uintptr_t) (val + len)) - - (((uintptr_t) ptr) + 1))); + n->scale = (size_t) (rdx * + (((uintptr_t) (val + len)) - (((uintptr_t) ptr) + 1))); // Set rdx. BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale)); @@ -2180,17 +2434,20 @@ static void bc_num_parseDecimal(BcNum *restrict n, const char *restrict val) { i = mod ? BC_BASE_DIGS - mod : 0; n->len = ((temp + i) / BC_BASE_DIGS); - // Expand and zero. - bc_num_expand(n, n->len); - memset(n->num, 0, BC_NUM_SIZE(n->len)); + // Expand and zero. The plus extra is in case the lack of clamping causes + // the number to overflow the original bounds. + bc_num_expand(n, n->len + !BC_DIGIT_CLAMP); + // NOLINTNEXTLINE + memset(n->num, 0, BC_NUM_SIZE(n->len + !BC_DIGIT_CLAMP)); - if (zero) { + if (zero) + { // I think I can set rdx directly to zero here because n should be a // new number with sign set to false. n->len = n->rdx = 0; } - else { - + else + { // There is actually stuff to parse if we make it here. Yay... BcBigDig exp, pow; @@ -2202,22 +2459,45 @@ static void bc_num_parseDecimal(BcNum *restrict n, const char *restrict val) { // Parse loop. We parse backwards because numbers are stored little // endian. - for (i = len - 1; i < len; --i, ++exp) { - + for (i = len - 1; i < len; --i, ++exp) + { char c = val[i]; // Skip the decimal point. if (c == '.') exp -= 1; - else { - + else + { // The index of the limb. size_t idx = exp / BC_BASE_DIGS; - - // Clamp for the base. - if (isupper(c)) c = '9'; - - // Add the digit to the limb. - n->num[idx] += (((BcBigDig) c) - '0') * pow; + BcBigDig dig; + + if (isupper(c)) + { + // Clamp for the base. + if (!BC_DIGIT_CLAMP) c = BC_NUM_NUM_LETTER(c); + else c = 9; + } + else c -= '0'; + + // Add the digit to the limb. This takes care of overflow from + // lack of clamping. + dig = ((BcBigDig) n->num[idx]) + ((BcBigDig) c) * pow; + if (dig >= BC_BASE_POW) + { + // We cannot go over BC_BASE_POW with clamping. + assert(!BC_DIGIT_CLAMP); + + n->num[idx + 1] = (BcDig) (dig / BC_BASE_POW); + n->num[idx] = (BcDig) (dig % BC_BASE_POW); + assert(n->num[idx] >= 0 && n->num[idx] < BC_BASE_POW); + assert(n->num[idx + 1] >= 0 && + n->num[idx + 1] < BC_BASE_POW); + } + else + { + n->num[idx] = (BcDig) dig; + assert(n->num[idx] >= 0 && n->num[idx] < BC_BASE_POW); + } // Adjust the power and exponent. if ((exp + 1) % BC_BASE_DIGS == 0) pow = 1; @@ -2225,6 +2505,9 @@ static void bc_num_parseDecimal(BcNum *restrict n, const char *restrict val) { } } } + + // Make sure to add one to the length if needed from lack of clamping. + n->len += (!BC_DIGIT_CLAMP && n->num[n->len] != 0); } /** @@ -2233,17 +2516,28 @@ static void bc_num_parseDecimal(BcNum *restrict n, const char *restrict val) { * @param val The string to parse. * @param base The base to parse as. */ -static void bc_num_parseBase(BcNum *restrict n, const char *restrict val, - BcBigDig base) +static void +bc_num_parseBase(BcNum* restrict n, const char* restrict val, BcBigDig base) { - BcNum temp, mult1, mult2, result1, result2, *m1, *m2, *ptr; + BcNum temp, mult1, mult2, result1, result2; + BcNum* m1; + BcNum* m2; + BcNum* ptr; char c = 0; bool zero = true; BcBigDig v; - size_t i, digs, len = strlen(val); + size_t digs, len = strlen(val); + // This is volatile to quiet a warning on GCC about longjmp() clobbering. + volatile size_t i; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY // If zero, just return because the number should be virgin (already 0). - for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0'); + for (i = 0; zero && i < len; ++i) + { + zero = (val[i] == '.' || val[i] == '0'); + } if (zero) return; BC_SIG_LOCK; @@ -2251,7 +2545,7 @@ static void bc_num_parseBase(BcNum *restrict n, const char *restrict val, bc_num_init(&temp, BC_NUM_BIGDIG_LOG10); bc_num_init(&mult1, BC_NUM_BIGDIG_LOG10); - BC_SETJMP_LOCKED(int_err); + BC_SETJMP_LOCKED(vm, int_err); BC_SIG_UNLOCK; @@ -2260,8 +2554,8 @@ static void bc_num_parseBase(BcNum *restrict n, const char *restrict val, // Parse the integer part. This is the easy part because we just multiply // the number by the base, then add the digit. - for (i = 0; i < len && (c = val[i]) && c != '.'; ++i) { - + for (i = 0; i < len && (c = val[i]) && c != '.'; ++i) + { // Convert the character to a digit. v = bc_num_parseChar(c, base); @@ -2283,14 +2577,14 @@ static void bc_num_parseBase(BcNum *restrict n, const char *restrict val, BC_SIG_LOCK; // Unset the jump to reset in for these new initializations. - BC_UNSETJMP; + BC_UNSETJMP(vm); bc_num_init(&mult2, BC_NUM_BIGDIG_LOG10); bc_num_init(&result1, BC_NUM_DEF_SIZE); bc_num_init(&result2, BC_NUM_DEF_SIZE); bc_num_one(&mult1); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; @@ -2299,8 +2593,8 @@ static void bc_num_parseBase(BcNum *restrict n, const char *restrict val, m2 = &mult2; // Parse the fractional part. This is the hard part. - for (i += 1, digs = 0; i < len && (c = val[i]); ++i, ++digs) { - + for (i += 1, digs = 0; i < len && (c = val[i]); ++i, ++digs) + { size_t rdx; // Convert the character to a digit. @@ -2343,7 +2637,8 @@ static void bc_num_parseBase(BcNum *restrict n, const char *restrict val, bc_num_add(n, &result2, n, digs); // Basic cleanup. - if (BC_NUM_NONZERO(n)) { + if (BC_NUM_NONZERO(n)) + { if (n->scale < digs) bc_num_extend(n, digs - n->scale); } else bc_num_zero(n); @@ -2357,16 +2652,19 @@ int_err: BC_SIG_MAYLOCK; bc_num_free(&mult1); bc_num_free(&temp); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } /** * Prints a backslash+newline combo if the number of characters needs it. This * is really a convenience function. */ -static inline void bc_num_printNewline(void) { +static inline void +bc_num_printNewline(void) +{ #if !BC_ENABLE_LIBRARY - if (vm.nchars >= vm.line_len - 1 && vm.line_len) { + if (vm->nchars >= vm->line_len - 1 && vm->line_len) + { bc_vm_putchar('\\', bc_flush_none); bc_vm_putchar('\n', bc_flush_err); } @@ -2378,7 +2676,9 @@ static inline void bc_num_printNewline(void) { * @param c The character to print. * @param bslash Whether to print a backslash+newline. */ -static void bc_num_putchar(int c, bool bslash) { +static void +bc_num_putchar(int c, bool bslash) +{ if (c != '\n' && bslash) bc_num_printNewline(); bc_vm_putchar(c, bc_flush_save); } @@ -2396,7 +2696,9 @@ static void bc_num_putchar(int c, bool bslash) { * @param bslash True if a backslash+newline should be printed if the character * limit for the line is reached, false otherwise. */ -static void bc_num_printChar(size_t n, size_t len, bool rdx, bool bslash) { +static void +bc_num_printChar(size_t n, size_t len, bool rdx, bool bslash) +{ BC_UNUSED(rdx); BC_UNUSED(len); BC_UNUSED(bslash); @@ -2416,19 +2718,23 @@ static void bc_num_printChar(size_t n, size_t len, bool rdx, bool bslash) { * @param bslash True if a backslash+newline should be printed if the character * limit for the line is reached, false otherwise. */ -static void bc_num_printDigits(size_t n, size_t len, bool rdx, bool bslash) { - +static void +bc_num_printDigits(size_t n, size_t len, bool rdx, bool bslash) +{ size_t exp, pow; // If needed, print the radix; otherwise, print a space to separate digits. bc_num_putchar(rdx ? '.' : ' ', true); // Calculate the exponent and power. - for (exp = 0, pow = 1; exp < len - 1; ++exp, pow *= BC_BASE); + for (exp = 0, pow = 1; exp < len - 1; ++exp, pow *= BC_BASE) + { + continue; + } // Print each character individually. - for (exp = 0; exp < len; pow /= BC_BASE, ++exp) { - + for (exp = 0; exp < len; pow /= BC_BASE, ++exp) + { // The individual subdigit. size_t dig = n / pow; @@ -2451,8 +2757,9 @@ static void bc_num_printDigits(size_t n, size_t len, bool rdx, bool bslash) { * @param bslash True if a backslash+newline should be printed if the character * limit for the line is reached, false otherwise. */ -static void bc_num_printHex(size_t n, size_t len, bool rdx, bool bslash) { - +static void +bc_num_printHex(size_t n, size_t len, bool rdx, bool bslash) +{ BC_UNUSED(len); BC_UNUSED(bslash); @@ -2469,15 +2776,16 @@ static void bc_num_printHex(size_t n, size_t len, bool rdx, bool bslash) { * @param n The number to print. * @param newline Whether to print backslash+newlines on long enough lines. */ -static void bc_num_printDecimal(const BcNum *restrict n, bool newline) { - +static void +bc_num_printDecimal(const BcNum* restrict n, bool newline) +{ size_t i, j, rdx = BC_NUM_RDX_VAL(n); bool zero = true; size_t buffer[BC_BASE_DIGS]; // Print loop. - for (i = n->len - 1; i < n->len; --i) { - + for (i = n->len - 1; i < n->len; --i) + { BcDig n9 = n->num[i]; size_t temp; bool irdx = (i == rdx - 1); @@ -2487,25 +2795,27 @@ static void bc_num_printDecimal(const BcNum *restrict n, bool newline) { temp = n->scale % BC_BASE_DIGS; temp = i || !temp ? 0 : BC_BASE_DIGS - temp; + // NOLINTNEXTLINE memset(buffer, 0, BC_BASE_DIGS * sizeof(size_t)); // Fill the buffer with individual digits. - for (j = 0; n9 && j < BC_BASE_DIGS; ++j) { + for (j = 0; n9 && j < BC_BASE_DIGS; ++j) + { buffer[j] = ((size_t) n9) % BC_BASE; n9 /= BC_BASE; } // Print the digits in the buffer. - for (j = BC_BASE_DIGS - 1; j < BC_BASE_DIGS && j >= temp; --j) { - + for (j = BC_BASE_DIGS - 1; j < BC_BASE_DIGS && j >= temp; --j) + { // Figure out whether to print the decimal point. bool print_rdx = (irdx & (j == BC_BASE_DIGS - 1)); // The zero variable helps us skip leading zero digits in the limb. zero = (zero && buffer[j] == 0); - if (!zero) { - + if (!zero) + { // While the first three arguments should be self-explanatory, // the last needs explaining. I don't want to print a newline // when the last digit to be printed could take the place of the @@ -2527,33 +2837,37 @@ static void bc_num_printDecimal(const BcNum *restrict n, bool newline) { * @param eng True if we are in engineering mode. * @param newline Whether to print backslash+newlines on long enough lines. */ -static void bc_num_printExponent(const BcNum *restrict n, - bool eng, bool newline) +static void +bc_num_printExponent(const BcNum* restrict n, bool eng, bool newline) { size_t places, mod, nrdx = BC_NUM_RDX_VAL(n); bool neg = (n->len <= nrdx); BcNum temp, exp; BcDig digs[BC_NUM_BIGDIG_LOG10]; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY BC_SIG_LOCK; bc_num_createCopy(&temp, n); - BC_SETJMP_LOCKED(exit); + BC_SETJMP_LOCKED(vm, exit); BC_SIG_UNLOCK; // We need to calculate the exponents, and they change based on whether the // number is all fractional or not, obviously. - if (neg) { - + if (neg) + { // Figure out how many limbs after the decimal point is zero. size_t i, idx = bc_num_nonZeroLen(n) - 1; places = 1; // Figure out how much in the last limb is zero. - for (i = BC_BASE_DIGS - 1; i < BC_BASE_DIGS; --i) { + for (i = BC_BASE_DIGS - 1; i < BC_BASE_DIGS; --i) + { if (bc_num_pow10[i] > (BcBigDig) n->num[idx]) places += 1; else break; } @@ -2569,8 +2883,8 @@ static void bc_num_printExponent(const BcNum *restrict n, // Shift the temp to the right place. bc_num_shiftLeft(&temp, places); } - else { - + else + { // This is the number of digits that we are supposed to put behind the // decimal point. places = bc_num_intDigits(n) - 1; @@ -2591,7 +2905,8 @@ static void bc_num_printExponent(const BcNum *restrict n, bc_num_putchar('e', !newline); // Need to explicitly print a zero exponent. - if (!places) { + if (!places) + { bc_num_printHex(0, 1, false, !newline); goto exit; } @@ -2609,26 +2924,26 @@ static void bc_num_printExponent(const BcNum *restrict n, exit: BC_SIG_MAYLOCK; bc_num_free(&temp); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } #endif // BC_ENABLE_EXTRA_MATH /** - * Converts a number from limbs with base BC_BASE_POW to base @a pow, where - * @a pow is obase^N. + * Takes a number with limbs with base BC_BASE_POW and converts the limb at the + * given index to base @a pow, where @a pow is obase^N. * @param n The number to convert. * @param rem BC_BASE_POW - @a pow. * @param pow The power of obase we will convert the number to. * @param idx The index of the number to start converting at. Doing the * conversion is O(n^2); we have to sweep through starting at the - * least significant limb + * least significant limb. */ -static void bc_num_printFixup(BcNum *restrict n, BcBigDig rem, - BcBigDig pow, size_t idx) +static void +bc_num_printFixup(BcNum* restrict n, BcBigDig rem, BcBigDig pow, size_t idx) { size_t i, len = n->len - idx; BcBigDig acc; - BcDig *a = n->num + idx; + BcDig* a = n->num + idx; // Ignore if there's just one limb left. This is the part that requires the // extra loop after the one calling this function in bc_num_printPrepare(). @@ -2636,8 +2951,8 @@ static void bc_num_printFixup(BcNum *restrict n, BcBigDig rem, // Loop through the remaining limbs and convert. We start at the second limb // because we pull the value from the previous one as well. - for (i = len - 1; i > 0; --i) { - + for (i = len - 1; i > 0; --i) + { // Get the limb and add it to the previous, along with multiplying by // the remainder because that's the proper overflow. "acc" means // "accumulator," by the way. @@ -2651,11 +2966,11 @@ static void bc_num_printFixup(BcNum *restrict n, BcBigDig rem, acc += (BcBigDig) a[i]; // If the accumulator is greater than the base... - if (acc >= BC_BASE_POW) { - + if (acc >= BC_BASE_POW) + { // Do we need to grow? - if (i == len - 1) { - + if (i == len - 1) + { // Grow. len = bc_vm_growSize(len, 1); bc_num_expand(n, bc_vm_growSize(len, idx)); @@ -2683,34 +2998,38 @@ static void bc_num_printFixup(BcNum *restrict n, BcBigDig rem, } /** - * Prepares a number for printing in a base that is not a divisor of - * BC_BASE_POW. This basically converts the number from having limbs of base + * Prepares a number for printing in a base that does not have BC_BASE_POW as a + * power. This basically converts the number from having limbs of base * BC_BASE_POW to limbs of pow, where pow is obase^N. * @param n The number to prepare for printing. * @param rem The remainder of BC_BASE_POW when divided by a power of the base. * @param pow The power of the base. */ -static void bc_num_printPrepare(BcNum *restrict n, BcBigDig rem, BcBigDig pow) { - +static void +bc_num_printPrepare(BcNum* restrict n, BcBigDig rem, BcBigDig pow) +{ size_t i; // Loop from the least significant limb to the most significant limb and // convert limbs in each pass. - for (i = 0; i < n->len; ++i) bc_num_printFixup(n, rem, pow, i); + for (i = 0; i < n->len; ++i) + { + bc_num_printFixup(n, rem, pow, i); + } // bc_num_printFixup() does not do everything it is supposed to, so we do // the last bit of cleanup here. That cleanup is to ensure that each limb // is less than pow and to expand the number to fit new limbs as necessary. - for (i = 0; i < n->len; ++i) { - + for (i = 0; i < n->len; ++i) + { assert(pow == ((BcBigDig) ((BcDig) pow))); // If the limb needs fixing... - if (n->num[i] >= (BcDig) pow) { - + if (n->num[i] >= (BcDig) pow) + { // Do we need to grow? - if (i + 1 == n->len) { - + if (i + 1 == n->len) + { // Grow the number. n->len = bc_vm_growSize(n->len, 1); bc_num_expand(n, n->len); @@ -2728,20 +3047,29 @@ static void bc_num_printPrepare(BcNum *restrict n, BcBigDig rem, BcBigDig pow) { } } -static void bc_num_printNum(BcNum *restrict n, BcBigDig base, size_t len, - BcNumDigitOp print, bool newline) +static void +bc_num_printNum(BcNum* restrict n, BcBigDig base, size_t len, + BcNumDigitOp print, bool newline) { BcVec stack; - BcNum intp, fracp1, fracp2, digit, flen1, flen2, *n1, *n2, *temp; - BcBigDig dig = 0, *ptr, acc, exp; + BcNum intp, fracp1, fracp2, digit, flen1, flen2; + BcNum* n1; + BcNum* n2; + BcNum* temp; + BcBigDig dig = 0, acc, exp; + BcBigDig* ptr; size_t i, j, nrdx, idigits; bool radix; BcDig digit_digs[BC_NUM_BIGDIG_LOG10 + 1]; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY assert(base > 1); // Easy case. Even with scale, we just print this. - if (BC_NUM_ZERO(n)) { + if (BC_NUM_ZERO(n)) + { print(0, len, false, !newline); return; } @@ -2795,7 +3123,7 @@ static void bc_num_printNum(BcNum *restrict n, BcBigDig base, size_t len, // intp will be the "integer part" of the number, so copy it. bc_num_createCopy(&intp, n); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; @@ -2810,36 +3138,40 @@ static void bc_num_printNum(BcNum *restrict n, BcBigDig base, size_t len, // exponent and power. That is to prevent us from calculating them every // time because printing will probably happen multiple times on the same // base. - if (base != vm.last_base) { - - vm.last_pow = 1; - vm.last_exp = 0; + if (base != vm->last_base) + { + vm->last_pow = 1; + vm->last_exp = 0; // Calculate the exponent and power. - while (vm.last_pow * base <= BC_BASE_POW) { - vm.last_pow *= base; - vm.last_exp += 1; + while (vm->last_pow * base <= BC_BASE_POW) + { + vm->last_pow *= base; + vm->last_exp += 1; } // Also, the remainder and base itself. - vm.last_rem = BC_BASE_POW - vm.last_pow; - vm.last_base = base; + vm->last_rem = BC_BASE_POW - vm->last_pow; + vm->last_base = base; } - exp = vm.last_exp; + exp = vm->last_exp; - // If vm.last_rem is 0, then the base we are printing in is a divisor of + // If vm->last_rem is 0, then the base we are printing in is a divisor of // BC_BASE_POW, which is the easy case because it means that BC_BASE_POW is // a power of obase, and no conversion is needed. If it *is* 0, then we have // the hard case, and we have to prepare the number for the base. - if (vm.last_rem != 0) bc_num_printPrepare(&intp, vm.last_rem, vm.last_pow); + if (vm->last_rem != 0) + { + bc_num_printPrepare(&intp, vm->last_rem, vm->last_pow); + } // After the conversion comes the surprisingly easy part. From here on out, // this is basically naive code that I wrote, adjusted for the larger bases. // Fill the stack of digits for the integer part. - for (i = 0; i < intp.len; ++i) { - + for (i = 0; i < intp.len; ++i) + { // Get the limb. acc = (BcBigDig) intp.num[i]; @@ -2847,11 +3179,13 @@ static void bc_num_printNum(BcNum *restrict n, BcBigDig base, size_t len, for (j = 0; j < exp && (i < intp.len - 1 || acc != 0); ++j) { // This condition is true if we are not at the last digit. - if (j != exp - 1) { + if (j != exp - 1) + { dig = acc % base; acc /= base; } - else { + else + { dig = acc; acc = 0; } @@ -2866,19 +3200,37 @@ static void bc_num_printNum(BcNum *restrict n, BcBigDig base, size_t len, } // Go through the stack backwards and print each digit. - for (i = 0; i < stack.len; ++i) { - + for (i = 0; i < stack.len; ++i) + { ptr = bc_vec_item_rev(&stack, i); assert(ptr != NULL); // While the first three arguments should be self-explanatory, the last - // needs explaining. I don't want to print a newline when the last digit - // to be printed could take the place of the backslash rather than being - // pushed, as a single character, to the next line. That's what that - // last argument does for bc. - print(*ptr, len, false, !newline || - (n->scale != 0 || i == stack.len - 1)); + // needs explaining. I don't want to print a backslash+newline when the + // last digit to be printed could take the place of the backslash rather + // than being pushed, as a single character, to the next line. That's + // what that last argument does for bc. + // + // First, it needs to check if newlines are completely disabled. If they + // are not disabled, it needs to check the next part. + // + // If the number has a scale, then because we are printing just the + // integer part, there will be at least two more characters (a radix + // point plus at least one digit). So if there is a scale, a backslash + // is necessary. + // + // Finally, the last condition checks to see if we are at the end of the + // stack. If we are *not* (i.e., the index is not one less than the + // stack length), then a backslash is necessary because there is at + // least one more character for at least one more digit). Otherwise, if + // the index is equal to one less than the stack length, we want to + // disable backslash printing. + // + // The function that prints bases 17 and above will take care of not + // printing a backslash in the right case. + print(*ptr, len, false, + !newline || (n->scale != 0 || i < stack.len - 1)); } // We are done if there is no fractional part. @@ -2887,14 +3239,14 @@ static void bc_num_printNum(BcNum *restrict n, BcBigDig base, size_t len, BC_SIG_LOCK; // Reset the jump because some locals are changing. - BC_UNSETJMP; + BC_UNSETJMP(vm); bc_num_init(&fracp2, nrdx); bc_num_setup(&digit, digit_digs, sizeof(digit_digs) / sizeof(BcDig)); bc_num_init(&flen1, BC_NUM_BIGDIG_LOG10); bc_num_init(&flen2, BC_NUM_BIGDIG_LOG10); - BC_SETJMP_LOCKED(frac_err); + BC_SETJMP_LOCKED(vm, frac_err); BC_SIG_UNLOCK; @@ -2910,8 +3262,8 @@ static void bc_num_printNum(BcNum *restrict n, BcBigDig base, size_t len, BC_NUM_RDX_SET_NP(fracp2, BC_NUM_RDX(fracp2.scale)); // As long as we have not reached the scale of the number, keep printing. - while ((idigits = bc_num_intDigits(n1)) <= n->scale) { - + while ((idigits = bc_num_intDigits(n1)) <= n->scale) + { // These numbers will keep growing. bc_num_expand(&fracp2, fracp1.len + 1); bc_num_mulArray(&fracp1, base, &fracp2); @@ -2956,7 +3308,7 @@ err: bc_num_free(&fracp1); bc_num_free(&intp); bc_vec_free(&stack); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } /** @@ -2966,8 +3318,9 @@ err: * @param base The base to print in. * @param newline Whether to print backslash+newlines on long enough lines. */ -static void bc_num_printBase(BcNum *restrict n, BcBigDig base, bool newline) { - +static void +bc_num_printBase(BcNum* restrict n, BcBigDig base, bool newline) +{ size_t width; BcNumDigitOp print; bool neg = BC_NUM_NEG(n); @@ -2978,11 +3331,13 @@ static void bc_num_printBase(BcNum *restrict n, BcBigDig base, bool newline) { // Bases at hexadecimal and below are printed as one character, larger bases // are printed as a series of digits separated by spaces. - if (base <= BC_NUM_MAX_POSIX_IBASE) { + if (base <= BC_NUM_MAX_POSIX_IBASE) + { width = 1; print = bc_num_printHex; } - else { + else + { assert(base <= BC_BASE_POW); width = bc_num_log10(base - 1); print = bc_num_printDigits; @@ -2997,22 +3352,27 @@ static void bc_num_printBase(BcNum *restrict n, BcBigDig base, bool newline) { #if !BC_ENABLE_LIBRARY -void bc_num_stream(BcNum *restrict n) { +void +bc_num_stream(BcNum* restrict n) +{ bc_num_printNum(n, BC_NUM_STREAM_BASE, 1, bc_num_printChar, false); } #endif // !BC_ENABLE_LIBRARY -void bc_num_setup(BcNum *restrict n, BcDig *restrict num, size_t cap) { +void +bc_num_setup(BcNum* restrict n, BcDig* restrict num, size_t cap) +{ assert(n != NULL); n->num = num; n->cap = cap; bc_num_zero(n); } -void bc_num_init(BcNum *restrict n, size_t req) { - - BcDig *num; +void +bc_num_init(BcNum* restrict n, size_t req) +{ + BcDig* num; BC_SIG_ASSERT_LOCKED; @@ -3023,20 +3383,27 @@ void bc_num_init(BcNum *restrict n, size_t req) { req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; // If we can't use a temp, allocate. - if (req != BC_NUM_DEF_SIZE || (num = bc_vm_takeTemp()) == NULL) - num = bc_vm_malloc(BC_NUM_SIZE(req)); + if (req != BC_NUM_DEF_SIZE) num = bc_vm_malloc(BC_NUM_SIZE(req)); + else + { + num = bc_vm_getTemp() == NULL ? bc_vm_malloc(BC_NUM_SIZE(req)) : + bc_vm_takeTemp(); + } bc_num_setup(n, num, req); } -void bc_num_clear(BcNum *restrict n) { +void +bc_num_clear(BcNum* restrict n) +{ n->num = NULL; n->cap = 0; } -void bc_num_free(void *num) { - - BcNum *n = (BcNum*) num; +void +bc_num_free(void* num) +{ + BcNum* n = (BcNum*) num; BC_SIG_ASSERT_LOCKED; @@ -3046,8 +3413,9 @@ void bc_num_free(void *num) { else free(n->num); } -void bc_num_copy(BcNum *d, const BcNum *s) { - +void +bc_num_copy(BcNum* d, const BcNum* s) +{ assert(d != NULL && s != NULL); if (d == s) return; @@ -3059,35 +3427,43 @@ void bc_num_copy(BcNum *d, const BcNum *s) { // properly preserved. d->rdx = s->rdx; d->scale = s->scale; + // NOLINTNEXTLINE memcpy(d->num, s->num, BC_NUM_SIZE(d->len)); } -void bc_num_createCopy(BcNum *d, const BcNum *s) { +void +bc_num_createCopy(BcNum* d, const BcNum* s) +{ BC_SIG_ASSERT_LOCKED; bc_num_init(d, s->len); bc_num_copy(d, s); } -void bc_num_createFromBigdig(BcNum *restrict n, BcBigDig val) { +void +bc_num_createFromBigdig(BcNum* restrict n, BcBigDig val) +{ BC_SIG_ASSERT_LOCKED; bc_num_init(n, BC_NUM_BIGDIG_LOG10); bc_num_bigdig2num(n, val); } -size_t bc_num_scale(const BcNum *restrict n) { +size_t +bc_num_scale(const BcNum* restrict n) +{ return n->scale; } -size_t bc_num_len(const BcNum *restrict n) { - +size_t +bc_num_len(const BcNum* restrict n) +{ size_t len = n->len; // Always return at least 1. if (BC_NUM_ZERO(n)) return n->scale ? n->scale : 1; // If this is true, there is no integer portion of the number. - if (BC_NUM_RDX_VAL(n) == len) { - + if (BC_NUM_RDX_VAL(n) == len) + { // We have to take into account the fact that some of the digits right // after the decimal could be zero. If that is the case, we need to // ignore them until we hit the first non-zero digit. @@ -3113,15 +3489,23 @@ size_t bc_num_len(const BcNum *restrict n) { return len; } -void bc_num_parse(BcNum *restrict n, const char *restrict val, BcBigDig base) { +void +bc_num_parse(BcNum* restrict n, const char* restrict val, BcBigDig base) +{ +#if BC_DEBUG +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY +#endif // BC_DEBUG assert(n != NULL && val != NULL && base); - assert(base >= BC_NUM_MIN_BASE && base <= vm.maxes[BC_PROG_GLOBALS_IBASE]); + assert(base >= BC_NUM_MIN_BASE && base <= vm->maxes[BC_PROG_GLOBALS_IBASE]); assert(bc_num_strValid(val)); // A one character number is *always* parsed as though the base was the // maximum allowed ibase, per the bc spec. - if (!val[1]) { + if (!val[1]) + { BcBigDig dig = bc_num_parseChar(val[0], BC_NUM_MAX_LBASE); bc_num_bigdig2num(n, dig); } @@ -3131,22 +3515,30 @@ void bc_num_parse(BcNum *restrict n, const char *restrict val, BcBigDig base) { assert(BC_NUM_RDX_VALID(n)); } -void bc_num_print(BcNum *restrict n, BcBigDig base, bool newline) { - +void +bc_num_print(BcNum* restrict n, BcBigDig base, bool newline) +{ assert(n != NULL); assert(BC_ENABLE_EXTRA_MATH || base >= BC_NUM_MIN_BASE); // We may need a newline, just to start. bc_num_printNewline(); - if (BC_NUM_NONZERO(n)) { + if (BC_NUM_NONZERO(n)) + { +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY // Print the sign. if (BC_NUM_NEG(n)) bc_num_putchar('-', true); - // Print the leading zero if necessary. - if (BC_Z && BC_NUM_RDX_VAL(n) == n->len) + // Print the leading zero if necessary. We don't print when using + // scientific or engineering modes. + if (BC_Z && BC_NUM_RDX_VAL(n) == n->len && base != 0 && base != 1) + { bc_num_printHex(0, 1, false, !newline); + } } // Short-circuit 0. @@ -3154,18 +3546,27 @@ void bc_num_print(BcNum *restrict n, BcBigDig base, bool newline) { else if (base == BC_BASE) bc_num_printDecimal(n, newline); #if BC_ENABLE_EXTRA_MATH else if (base == 0 || base == 1) + { bc_num_printExponent(n, base != 0, newline); + } #endif // BC_ENABLE_EXTRA_MATH else bc_num_printBase(n, base, newline); if (newline) bc_num_putchar('\n', false); } -BcBigDig bc_num_bigdig2(const BcNum *restrict n) { +BcBigDig +bc_num_bigdig2(const BcNum* restrict n) +{ +#if BC_DEBUG +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY +#endif // BC_DEBUG // This function returns no errors because it's guaranteed to succeed if // its preconditions are met. Those preconditions include both n needs to - // be non-NULL, n being non-negative, and n being less than vm.max. If all + // be non-NULL, n being non-negative, and n being less than vm->max. If all // of that is true, then we can just convert without worrying about negative // errors or overflow. @@ -3174,26 +3575,28 @@ BcBigDig bc_num_bigdig2(const BcNum *restrict n) { assert(n != NULL); assert(!BC_NUM_NEG(n)); - assert(bc_num_cmp(n, &vm.max) < 0); + assert(bc_num_cmp(n, &vm->max) < 0); assert(n->len - nrdx <= 3); // There is a small speed win from unrolling the loop here, and since it // only adds 53 bytes, I decided that it was worth it. - switch (n->len - nrdx) { - + switch (n->len - nrdx) + { case 3: { r = (BcBigDig) n->num[nrdx + 2]; + + // Fallthrough. + BC_FALLTHROUGH } - // Fallthrough. - BC_FALLTHROUGH case 2: { r = r * BC_BASE_POW + (BcBigDig) n->num[nrdx + 1]; + + // Fallthrough. + BC_FALLTHROUGH } - // Fallthrough. - BC_FALLTHROUGH case 1: { @@ -3204,7 +3607,12 @@ BcBigDig bc_num_bigdig2(const BcNum *restrict n) { return r; } -BcBigDig bc_num_bigdig(const BcNum *restrict n) { +BcBigDig +bc_num_bigdig(const BcNum* restrict n) +{ +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY assert(n != NULL); @@ -3214,14 +3622,15 @@ BcBigDig bc_num_bigdig(const BcNum *restrict n) { // includes all instances of numbers inputted by the user or calculated by // the user. Otherwise, you can call the faster bc_num_bigdig2(). if (BC_ERR(BC_NUM_NEG(n))) bc_err(BC_ERR_MATH_NEGATIVE); - if (BC_ERR(bc_num_cmp(n, &vm.max) >= 0)) bc_err(BC_ERR_MATH_OVERFLOW); + if (BC_ERR(bc_num_cmp(n, &vm->max) >= 0)) bc_err(BC_ERR_MATH_OVERFLOW); return bc_num_bigdig2(n); } -void bc_num_bigdig2num(BcNum *restrict n, BcBigDig val) { - - BcDig *ptr; +void +bc_num_bigdig2num(BcNum* restrict n, BcBigDig val) +{ + BcDig* ptr; size_t i; assert(n != NULL); @@ -3238,18 +3647,24 @@ void bc_num_bigdig2num(BcNum *restrict n, BcBigDig val) { // The conversion is easy because numbers are laid out in little-endian // order. for (ptr = n->num, i = 0; val; ++i, val /= BC_BASE_POW) + { ptr[i] = val % BC_BASE_POW; + } n->len = i; } #if BC_ENABLE_EXTRA_MATH -void bc_num_rng(const BcNum *restrict n, BcRNG *rng) { - +void +bc_num_rng(const BcNum* restrict n, BcRNG* rng) +{ BcNum temp, temp2, intn, frac; BcRand state1, state2, inc1, inc2; size_t nrdx = BC_NUM_RDX_VAL(n); +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY // This function holds the secret of how I interpret a seed number for the // PRNG. Well, it's actually in the development manual @@ -3263,43 +3678,45 @@ void bc_num_rng(const BcNum *restrict n, BcRNG *rng) { bc_num_init(&frac, nrdx); bc_num_init(&intn, bc_num_int(n)); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; - assert(BC_NUM_RDX_VALID_NP(vm.max)); + assert(BC_NUM_RDX_VALID_NP(vm->max)); + // NOLINTNEXTLINE memcpy(frac.num, n->num, BC_NUM_SIZE(nrdx)); frac.len = nrdx; BC_NUM_RDX_SET_NP(frac, nrdx); frac.scale = n->scale; assert(BC_NUM_RDX_VALID_NP(frac)); - assert(BC_NUM_RDX_VALID_NP(vm.max2)); + assert(BC_NUM_RDX_VALID_NP(vm->max2)); // Multiply the fraction and truncate so that it's an integer. The // truncation is what clamps it, by the way. - bc_num_mul(&frac, &vm.max2, &temp, 0); + bc_num_mul(&frac, &vm->max2, &temp, 0); bc_num_truncate(&temp, temp.scale); bc_num_copy(&frac, &temp); // Get the integer. + // NOLINTNEXTLINE memcpy(intn.num, n->num + nrdx, BC_NUM_SIZE(bc_num_int(n))); intn.len = bc_num_int(n); // This assert is here because it has to be true. It is also here to justify // some optimizations. - assert(BC_NUM_NONZERO(&vm.max)); + assert(BC_NUM_NONZERO(&vm->max)); // If there *was* a fractional part... - if (BC_NUM_NONZERO(&frac)) { - + if (BC_NUM_NONZERO(&frac)) + { // This divmod splits frac into the two state parts. - bc_num_divmod(&frac, &vm.max, &temp, &temp2, 0); + bc_num_divmod(&frac, &vm->max, &temp, &temp2, 0); - // frac is guaranteed to be smaller than vm.max * vm.max (pow). - // This means that when dividing frac by vm.max, as above, the - // quotient and remainder are both guaranteed to be less than vm.max, + // frac is guaranteed to be smaller than vm->max * vm->max (pow). + // This means that when dividing frac by vm->max, as above, the + // quotient and remainder are both guaranteed to be less than vm->max, // which means we can use bc_num_bigdig2() here and not worry about // overflow. state1 = (BcRand) bc_num_bigdig2(&temp2); @@ -3308,22 +3725,23 @@ void bc_num_rng(const BcNum *restrict n, BcRNG *rng) { else state1 = state2 = 0; // If there *was* an integer part... - if (BC_NUM_NONZERO(&intn)) { - + if (BC_NUM_NONZERO(&intn)) + { // This divmod splits intn into the two inc parts. - bc_num_divmod(&intn, &vm.max, &temp, &temp2, 0); + bc_num_divmod(&intn, &vm->max, &temp, &temp2, 0); - // Because temp2 is the mod of vm.max, from above, it is guaranteed + // Because temp2 is the mod of vm->max, from above, it is guaranteed // to be small enough to use bc_num_bigdig2(). inc1 = (BcRand) bc_num_bigdig2(&temp2); // Clamp the second inc part. - if (bc_num_cmp(&temp, &vm.max) >= 0) { + if (bc_num_cmp(&temp, &vm->max) >= 0) + { bc_num_copy(&temp2, &temp); - bc_num_mod(&temp2, &vm.max, &temp, 0); + bc_num_mod(&temp2, &vm->max, &temp, 0); } - // The if statement above ensures that temp is less than vm.max, which + // The if statement above ensures that temp is less than vm->max, which // means that we can use bc_num_bigdig2() here. inc2 = (BcRand) bc_num_bigdig2(&temp); } @@ -3337,21 +3755,25 @@ err: bc_num_free(&frac); bc_num_free(&temp2); bc_num_free(&temp); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } -void bc_num_createFromRNG(BcNum *restrict n, BcRNG *rng) { - +void +bc_num_createFromRNG(BcNum* restrict n, BcRNG* rng) +{ BcRand s1, s2, i1, i2; BcNum conv, temp1, temp2, temp3; BcDig temp1_num[BC_RAND_NUM_SIZE], temp2_num[BC_RAND_NUM_SIZE]; BcDig conv_num[BC_NUM_BIGDIG_LOG10]; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY BC_SIG_LOCK; bc_num_init(&temp3, 2 * BC_RAND_NUM_SIZE); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; @@ -3360,12 +3782,12 @@ void bc_num_createFromRNG(BcNum *restrict n, BcRNG *rng) { bc_num_setup(&conv, conv_num, sizeof(conv_num) / sizeof(BcDig)); // This assert is here because it has to be true. It is also here to justify - // the assumption that vm.max is not zero. - assert(BC_NUM_NONZERO(&vm.max)); + // the assumption that vm->max is not zero. + assert(BC_NUM_NONZERO(&vm->max)); // Because this is true, we can just ignore math errors that would happen // otherwise. - assert(BC_NUM_NONZERO(&vm.max2)); + assert(BC_NUM_NONZERO(&vm->max2)); bc_rand_getRands(rng, &s1, &s2, &i1, &i2); @@ -3375,14 +3797,14 @@ void bc_num_createFromRNG(BcNum *restrict n, BcRNG *rng) { assert(BC_NUM_RDX_VALID_NP(conv)); // Multiply by max to make room for the first piece of state. - bc_num_mul(&conv, &vm.max, &temp1, 0); + bc_num_mul(&conv, &vm->max, &temp1, 0); // Add in the first piece of state. bc_num_bigdig2num(&conv, (BcBigDig) s1); bc_num_add(&conv, &temp1, &temp2, 0); // Divide to make it an entirely fractional part. - bc_num_div(&temp2, &vm.max2, &temp3, BC_RAND_STATE_BITS); + bc_num_div(&temp2, &vm->max2, &temp3, BC_RAND_STATE_BITS); // Now start on the increment parts. It's the same process without the // divide, so put the second piece of increment into a number. @@ -3391,7 +3813,7 @@ void bc_num_createFromRNG(BcNum *restrict n, BcRNG *rng) { assert(BC_NUM_RDX_VALID_NP(conv)); // Multiply by max to make room for the first piece of increment. - bc_num_mul(&conv, &vm.max, &temp1, 0); + bc_num_mul(&conv, &vm->max, &temp1, 0); // Add in the first piece of increment. bc_num_bigdig2num(&conv, (BcBigDig) i1); @@ -3405,13 +3827,14 @@ void bc_num_createFromRNG(BcNum *restrict n, BcRNG *rng) { err: BC_SIG_MAYLOCK; bc_num_free(&temp3); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } -void bc_num_irand(BcNum *restrict a, BcNum *restrict b, BcRNG *restrict rng) { - +void +bc_num_irand(BcNum* restrict a, BcNum* restrict b, BcRNG* restrict rng) +{ BcNum atemp; - size_t i, len; + size_t i; assert(a != b); @@ -3420,25 +3843,87 @@ void bc_num_irand(BcNum *restrict a, BcNum *restrict b, BcRNG *restrict rng) { // If either of these are true, then the numbers are integers. if (BC_NUM_ZERO(a) || BC_NUM_ONE(a)) return; +#if BC_GCC + // This is here in GCC to quiet the "maybe-uninitialized" warning. + atemp.num = NULL; + atemp.len = 0; +#endif // BC_GCC + if (BC_ERR(bc_num_nonInt(a, &atemp))) bc_err(BC_ERR_MATH_NON_INTEGER); + assert(atemp.num != NULL); assert(atemp.len); - len = atemp.len - 1; + if (atemp.len > 2) + { + size_t len; - // Just generate a random number for each limb. - for (i = 0; i < len; ++i) - b->num[i] = (BcDig) bc_rand_bounded(rng, BC_BASE_POW); + len = atemp.len - 2; + + // Just generate a random number for each limb. + for (i = 0; i < len; i += 2) + { + BcRand dig; + + dig = bc_rand_bounded(rng, BC_BASE_RAND_POW); - // Do the last digit explicitly because the bound must be right. But only - // do it if the limb does not equal 1. If it does, we have already hit the - // limit. - if (atemp.num[i] != 1) { - b->num[i] = (BcDig) bc_rand_bounded(rng, (BcRand) atemp.num[i]); - b->len = atemp.len; + b->num[i] = (BcDig) (dig % BC_BASE_POW); + b->num[i + 1] = (BcDig) (dig / BC_BASE_POW); + } + } + else + { + // We need this set. + i = 0; + } + + // This will be true if there's one full limb after the two limb groups. + if (i == atemp.len - 2) + { + // Increment this for easy use. + i += 1; + + // If the last digit is not one, we need to set a bound for it + // explicitly. Since there's still an empty limb, we need to fill that. + if (atemp.num[i] != 1) + { + BcRand dig; + BcRand bound; + + // Set the bound to the bound of the last limb times the amount + // needed to fill the second-to-last limb as well. + bound = ((BcRand) atemp.num[i]) * BC_BASE_POW; + + dig = bc_rand_bounded(rng, bound); + + // Fill the last two. + b->num[i - 1] = (BcDig) (dig % BC_BASE_POW); + b->num[i] = (BcDig) (dig / BC_BASE_POW); + + // Ensure that the length will be correct. If the last limb is zero, + // then the length needs to be one less than the bound. + b->len = atemp.len - (b->num[i] == 0); + } + // Here the last limb *is* one, which means the last limb does *not* + // need to be filled. Also, the length needs to be one less because the + // last limb is 0. + else + { + b->num[i - 1] = (BcDig) bc_rand_bounded(rng, BC_BASE_POW); + b->len = atemp.len - 1; + } + } + // Here, there is only one limb to fill. + else + { + // See above for how this works. + if (atemp.num[i] != 1) + { + b->num[i] = (BcDig) bc_rand_bounded(rng, (BcRand) atemp.num[i]); + b->len = atemp.len - (b->num[i] == 0); + } + else b->len = atemp.len - 1; } - // We want 1 less len in the case where we skip the last limb. - else b->len = len; bc_num_clean(b); @@ -3446,8 +3931,9 @@ void bc_num_irand(BcNum *restrict a, BcNum *restrict b, BcRNG *restrict rng) { } #endif // BC_ENABLE_EXTRA_MATH -size_t bc_num_addReq(const BcNum *a, const BcNum *b, size_t scale) { - +size_t +bc_num_addReq(const BcNum* a, const BcNum* b, size_t scale) +{ size_t aint, bint, ardx, brdx; // Addition and subtraction require the max of the length of the two numbers @@ -3469,8 +3955,9 @@ size_t bc_num_addReq(const BcNum *a, const BcNum *b, size_t scale) { return bc_vm_growSize(bc_vm_growSize(ardx, aint), 1); } -size_t bc_num_mulReq(const BcNum *a, const BcNum *b, size_t scale) { - +size_t +bc_num_mulReq(const BcNum* a, const BcNum* b, size_t scale) +{ size_t max, rdx; // Multiplication requires the sum of the lengths of the numbers. @@ -3485,8 +3972,9 @@ size_t bc_num_mulReq(const BcNum *a, const BcNum *b, size_t scale) { return rdx; } -size_t bc_num_divReq(const BcNum *a, const BcNum *b, size_t scale) { - +size_t +bc_num_divReq(const BcNum* a, const BcNum* b, size_t scale) +{ size_t max, rdx; // Division requires the length of the dividend plus the scale. @@ -3501,79 +3989,110 @@ size_t bc_num_divReq(const BcNum *a, const BcNum *b, size_t scale) { return rdx; } -size_t bc_num_powReq(const BcNum *a, const BcNum *b, size_t scale) { +size_t +bc_num_powReq(const BcNum* a, const BcNum* b, size_t scale) +{ BC_UNUSED(scale); return bc_vm_growSize(bc_vm_growSize(a->len, b->len), 1); } #if BC_ENABLE_EXTRA_MATH -size_t bc_num_placesReq(const BcNum *a, const BcNum *b, size_t scale) { +size_t +bc_num_placesReq(const BcNum* a, const BcNum* b, size_t scale) +{ BC_UNUSED(scale); return a->len + b->len - BC_NUM_RDX_VAL(a) - BC_NUM_RDX_VAL(b); } #endif // BC_ENABLE_EXTRA_MATH -void bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +void +bc_num_add(BcNum* a, BcNum* b, BcNum* c, size_t scale) +{ assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); bc_num_binary(a, b, c, false, bc_num_as, bc_num_addReq(a, b, scale)); } -void bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +void +bc_num_sub(BcNum* a, BcNum* b, BcNum* c, size_t scale) +{ assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); bc_num_binary(a, b, c, true, bc_num_as, bc_num_addReq(a, b, scale)); } -void bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +void +bc_num_mul(BcNum* a, BcNum* b, BcNum* c, size_t scale) +{ assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); bc_num_binary(a, b, c, scale, bc_num_m, bc_num_mulReq(a, b, scale)); } -void bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +void +bc_num_div(BcNum* a, BcNum* b, BcNum* c, size_t scale) +{ assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); bc_num_binary(a, b, c, scale, bc_num_d, bc_num_divReq(a, b, scale)); } -void bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +void +bc_num_mod(BcNum* a, BcNum* b, BcNum* c, size_t scale) +{ assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); bc_num_binary(a, b, c, scale, bc_num_rem, bc_num_divReq(a, b, scale)); } -void bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +void +bc_num_pow(BcNum* a, BcNum* b, BcNum* c, size_t scale) +{ assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); bc_num_binary(a, b, c, scale, bc_num_p, bc_num_powReq(a, b, scale)); } #if BC_ENABLE_EXTRA_MATH -void bc_num_places(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +void +bc_num_places(BcNum* a, BcNum* b, BcNum* c, size_t scale) +{ assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); bc_num_binary(a, b, c, scale, bc_num_place, bc_num_placesReq(a, b, scale)); } -void bc_num_lshift(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +void +bc_num_lshift(BcNum* a, BcNum* b, BcNum* c, size_t scale) +{ assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); bc_num_binary(a, b, c, scale, bc_num_left, bc_num_placesReq(a, b, scale)); } -void bc_num_rshift(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +void +bc_num_rshift(BcNum* a, BcNum* b, BcNum* c, size_t scale) +{ assert(BC_NUM_RDX_VALID(a)); assert(BC_NUM_RDX_VALID(b)); bc_num_binary(a, b, c, scale, bc_num_right, bc_num_placesReq(a, b, scale)); } #endif // BC_ENABLE_EXTRA_MATH -void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) { - - BcNum num1, num2, half, f, fprime, *x0, *x1, *temp; - size_t pow, len, rdx, req, resscale; +void +bc_num_sqrt(BcNum* restrict a, BcNum* restrict b, size_t scale) +{ + BcNum num1, num2, half, f, fprime; + BcNum* x0; + BcNum* x1; + BcNum* temp; + // realscale is meant to quiet a warning on GCC about longjmp() clobbering. + // This one is real. + size_t pow, len, rdx, req, resscale, realscale; BcDig half_digs[1]; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY assert(a != NULL && b != NULL && a != b); @@ -3581,21 +4100,23 @@ void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) { // We want to calculate to a's scale if it is bigger so that the result will // truncate properly. - if (a->scale > scale) scale = a->scale; + if (a->scale > scale) realscale = a->scale; + else realscale = scale; // Set parameters for the result. len = bc_vm_growSize(bc_num_intDigits(a), 1); - rdx = BC_NUM_RDX(scale); + rdx = BC_NUM_RDX(realscale); // Square root needs half of the length of the parameter. req = bc_vm_growSize(BC_MAX(rdx, BC_NUM_RDX_VAL(a)), len >> 1); + req = bc_vm_growSize(req, 1); BC_SIG_LOCK; // Unlike the binary operators, this function is the only single parameter // function and is expected to initialize the result. This means that it // expects that b is *NOT* preallocated. We allocate it here. - bc_num_init(b, bc_vm_growSize(req, 1)); + bc_num_init(b, req); BC_SIG_UNLOCK; @@ -3603,20 +4124,22 @@ void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) { assert(a->num != NULL && b->num != NULL); // Easy case. - if (BC_NUM_ZERO(a)) { - bc_num_setToZero(b, scale); + if (BC_NUM_ZERO(a)) + { + bc_num_setToZero(b, realscale); return; } // Another easy case. - if (BC_NUM_ONE(a)) { + if (BC_NUM_ONE(a)) + { bc_num_one(b); - bc_num_extend(b, scale); + bc_num_extend(b, realscale); return; } // Set the parameters again. - rdx = BC_NUM_RDX(scale); + rdx = BC_NUM_RDX(realscale); rdx = BC_MAX(rdx, BC_NUM_RDX_VAL(a)); len = bc_vm_growSize(a->len, rdx); @@ -3626,18 +4149,17 @@ void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) { bc_num_init(&num2, len); bc_num_setup(&half, half_digs, sizeof(half_digs) / sizeof(BcDig)); - // There is a division by two in the formula. We setup a number that's 1/2 + // There is a division by two in the formula. We set up a number that's 1/2 // so that we can use multiplication instead of heavy division. - bc_num_one(&half); + bc_num_setToZero(&half, 1); half.num[0] = BC_BASE_POW / 2; half.len = 1; BC_NUM_RDX_SET_NP(half, 1); - half.scale = 1; bc_num_init(&f, len); bc_num_init(&fprime, len); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; @@ -3652,10 +4174,11 @@ void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) { pow = bc_num_intDigits(a); // The code in this if statement calculates the initial estimate. First, if - // a is less than 0, then 0 is a good estimate. Otherwise, we want something - // in the same ballpark. That ballpark is pow. - if (pow) { - + // a is less than 1, then 0 is a good estimate. Otherwise, we want something + // in the same ballpark. That ballpark is half of pow because the result + // will have half the digits. + if (pow) + { // An odd number is served by starting with 2^((pow-1)/2), and an even // number is served by starting with 6^((pow-2)/2). Why? Because math. if (pow & 1) x0->num[0] = 2; @@ -3667,12 +4190,12 @@ void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) { // I can set the rdx here directly because neg should be false. x0->scale = x0->rdx = 0; - resscale = (scale + BC_BASE_DIGS) + 2; + resscale = (realscale + BC_BASE_DIGS) + 2; // This is the calculation loop. This compare goes to 0 eventually as the // difference between the two numbers gets smaller than resscale. - while (bc_num_cmp(x1, x0)) { - + while (bc_num_cmp(x1, x0)) + { assert(BC_NUM_NONZERO(x0)); // This loop directly corresponds to the iteration in Newton's method. @@ -3694,7 +4217,7 @@ void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) { // Copy to the result and truncate. bc_num_copy(b, x0); - if (b->scale > scale) bc_num_truncate(b, b->scale - scale); + if (b->scale > realscale) bc_num_truncate(b, b->scale - realscale); assert(!BC_NUM_NEG(b) || BC_NUM_NONZERO(b)); assert(BC_NUM_RDX_VALID(b)); @@ -3707,14 +4230,20 @@ err: bc_num_free(&f); bc_num_free(&num2); bc_num_free(&num1); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } -void bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) { - +void +bc_num_divmod(BcNum* a, BcNum* b, BcNum* c, BcNum* d, size_t scale) +{ size_t ts, len; BcNum *ptr_a, num2; - bool init = false; + // This is volatile to quiet a warning on GCC about clobbering with + // longjmp(). + volatile bool init = false; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY // The bulk of this function is just doing what bc_num_binary() does for the // binary operators. However, it assumes that only c and a can be equal. @@ -3727,8 +4256,9 @@ void bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) { assert(c != d && a != d && b != d && b != c); // Initialize or expand as necessary. - if (c == a) { - + if (c == a) + { + // NOLINTNEXTLINE memcpy(&num2, c, sizeof(BcNum)); ptr_a = &num2; @@ -3738,18 +4268,19 @@ void bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) { init = true; - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; } - else { + else + { ptr_a = a; bc_num_expand(c, len); } // Do the quick version if possible. - if (BC_NUM_NONZERO(a) && !BC_NUM_RDX_VAL(a) && - !BC_NUM_RDX_VAL(b) && b->len == 1 && !scale) + if (BC_NUM_NONZERO(a) && !BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b) && + b->len == 1 && !scale) { BcBigDig rem; @@ -3774,30 +4305,34 @@ void bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) { err: // Only cleanup if we initialized. - if (init) { + if (init) + { BC_SIG_MAYLOCK; bc_num_free(&num2); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } } -void bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d) { - +void +bc_num_modexp(BcNum* a, BcNum* b, BcNum* c, BcNum* restrict d) +{ BcNum base, exp, two, temp, atemp, btemp, ctemp; BcDig two_digs[2]; +#if BC_ENABLE_LIBRARY + BcVm* vm = bcl_getspecific(); +#endif // BC_ENABLE_LIBRARY assert(a != NULL && b != NULL && c != NULL && d != NULL); assert(a != d && b != d && c != d); if (BC_ERR(BC_NUM_ZERO(c))) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); - if (BC_ERR(BC_NUM_NEG(b))) bc_err(BC_ERR_MATH_NEGATIVE); -#ifndef NDEBUG +#if BC_DEBUG || BC_GCC // This is entirely for quieting a useless scan-build error. btemp.len = 0; ctemp.len = 0; -#endif // NDEBUG +#endif // BC_DEBUG || BC_GCC // Eliminate fractional parts that are zero or error if they are not zero. if (BC_ERR(bc_num_nonInt(a, &atemp) || bc_num_nonInt(b, &btemp) || @@ -3815,7 +4350,7 @@ void bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d) { bc_num_init(&temp, btemp.len + 1); bc_num_createCopy(&exp, &btemp); - BC_SETJMP_LOCKED(err); + BC_SETJMP_LOCKED(vm, err); BC_SIG_UNLOCK; @@ -3828,13 +4363,13 @@ void bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d) { // If you know the algorithm I used, the memory-efficient method, then this // loop should be self-explanatory because it is the calculation loop. - while (BC_NUM_NONZERO(&exp)) { - + while (BC_NUM_NONZERO(&exp)) + { // Num two cannot be 0, so no errors. bc_num_divmod(&exp, &two, &exp, &temp, 0); - if (BC_NUM_ONE(&temp) && !BC_NUM_NEG_NP(temp)) { - + if (BC_NUM_ONE(&temp) && !BC_NUM_NEG_NP(temp)) + { assert(BC_NUM_RDX_VALID(d)); assert(BC_NUM_RDX_VALID_NP(base)); @@ -3857,75 +4392,87 @@ err: bc_num_free(&exp); bc_num_free(&temp); bc_num_free(&base); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); assert(!BC_NUM_NEG(d) || d->len); assert(BC_NUM_RDX_VALID(d)); assert(!d->len || d->num[d->len - 1] || BC_NUM_RDX_VAL(d) == d->len); } #if BC_DEBUG_CODE -void bc_num_printDebug(const BcNum *n, const char *name, bool emptyline) { - bc_file_puts(&vm.fout, bc_flush_none, name); - bc_file_puts(&vm.fout, bc_flush_none, ": "); +void +bc_num_printDebug(const BcNum* n, const char* name, bool emptyline) +{ + bc_file_puts(&vm->fout, bc_flush_none, name); + bc_file_puts(&vm->fout, bc_flush_none, ": "); bc_num_printDecimal(n, true); - bc_file_putchar(&vm.fout, bc_flush_err, '\n'); - if (emptyline) bc_file_putchar(&vm.fout, bc_flush_err, '\n'); - vm.nchars = 0; + bc_file_putchar(&vm->fout, bc_flush_err, '\n'); + if (emptyline) bc_file_putchar(&vm->fout, bc_flush_err, '\n'); + vm->nchars = 0; } -void bc_num_printDigs(const BcDig *n, size_t len, bool emptyline) { - +void +bc_num_printDigs(const BcDig* n, size_t len, bool emptyline) +{ size_t i; for (i = len - 1; i < len; --i) - bc_file_printf(&vm.fout, " %lu", (unsigned long) n[i]); + { + bc_file_printf(&vm->fout, " %lu", (unsigned long) n[i]); + } - bc_file_putchar(&vm.fout, bc_flush_err, '\n'); - if (emptyline) bc_file_putchar(&vm.fout, bc_flush_err, '\n'); - vm.nchars = 0; + bc_file_putchar(&vm->fout, bc_flush_err, '\n'); + if (emptyline) bc_file_putchar(&vm->fout, bc_flush_err, '\n'); + vm->nchars = 0; } -void bc_num_printWithDigs(const BcNum *n, const char *name, bool emptyline) { - bc_file_puts(&vm.fout, bc_flush_none, name); - bc_file_printf(&vm.fout, " len: %zu, rdx: %zu, scale: %zu\n", - name, n->len, BC_NUM_RDX_VAL(n), n->scale); +void +bc_num_printWithDigs(const BcNum* n, const char* name, bool emptyline) +{ + bc_file_puts(&vm->fout, bc_flush_none, name); + bc_file_printf(&vm->fout, " len: %zu, rdx: %zu, scale: %zu\n", name, n->len, + BC_NUM_RDX_VAL(n), n->scale); bc_num_printDigs(n->num, n->len, emptyline); } -void bc_num_dump(const char *varname, const BcNum *n) { - +void +bc_num_dump(const char* varname, const BcNum* n) +{ ulong i, scale = n->scale; - bc_file_printf(&vm.ferr, "\n%s = %s", varname, + bc_file_printf(&vm->ferr, "\n%s = %s", varname, n->len ? (BC_NUM_NEG(n) ? "-" : "+") : "0 "); - for (i = n->len - 1; i < n->len; --i) { - + for (i = n->len - 1; i < n->len; --i) + { if (i + 1 == BC_NUM_RDX_VAL(n)) - bc_file_puts(&vm.ferr, bc_flush_none, ". "); + { + bc_file_puts(&vm->ferr, bc_flush_none, ". "); + } if (scale / BC_BASE_DIGS != BC_NUM_RDX_VAL(n) - i - 1) - bc_file_printf(&vm.ferr, "%lu ", (unsigned long) n->num[i]); - else { - + { + bc_file_printf(&vm->ferr, "%lu ", (unsigned long) n->num[i]); + } + else + { int mod = scale % BC_BASE_DIGS; int d = BC_BASE_DIGS - mod; BcDig div; - if (mod != 0) { + if (mod != 0) + { div = n->num[i] / ((BcDig) bc_num_pow10[(ulong) d]); - bc_file_printf(&vm.ferr, "%lu", (unsigned long) div); + bc_file_printf(&vm->ferr, "%lu", (unsigned long) div); } div = n->num[i] % ((BcDig) bc_num_pow10[(ulong) d]); - bc_file_printf(&vm.ferr, " ' %lu ", (unsigned long) div); + bc_file_printf(&vm->ferr, " ' %lu ", (unsigned long) div); } } - bc_file_printf(&vm.ferr, "(%zu | %zu.%zu / %zu) %lu\n", - n->scale, n->len, BC_NUM_RDX_VAL(n), n->cap, - (unsigned long) (void*) n->num); + bc_file_printf(&vm->ferr, "(%zu | %zu.%zu / %zu) %lu\n", n->scale, n->len, + BC_NUM_RDX_VAL(n), n->cap, (unsigned long) (void*) n->num); - bc_file_flush(&vm.ferr, bc_flush_err); + bc_file_flush(&vm->ferr, bc_flush_err); } #endif // BC_DEBUG_CODE |