xref: /freebsd/contrib/bc/src/num.c (revision aa339f1d5df9e38f36a34eb522355c4eebcae6c4)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
43aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
6d101cdd6SStefan Eßer  * Copyright (c) 2018-2023 Gavin D. Howard and contributors.
7252884aeSStefan Eßer  *
8252884aeSStefan Eßer  * Redistribution and use in source and binary forms, with or without
9252884aeSStefan Eßer  * modification, are permitted provided that the following conditions are met:
10252884aeSStefan Eßer  *
11252884aeSStefan Eßer  * * Redistributions of source code must retain the above copyright notice, this
12252884aeSStefan Eßer  *   list of conditions and the following disclaimer.
13252884aeSStefan Eßer  *
14252884aeSStefan Eßer  * * Redistributions in binary form must reproduce the above copyright notice,
15252884aeSStefan Eßer  *   this list of conditions and the following disclaimer in the documentation
16252884aeSStefan Eßer  *   and/or other materials provided with the distribution.
17252884aeSStefan Eßer  *
18252884aeSStefan Eßer  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19252884aeSStefan Eßer  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20252884aeSStefan Eßer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21252884aeSStefan Eßer  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22252884aeSStefan Eßer  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23252884aeSStefan Eßer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24252884aeSStefan Eßer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25252884aeSStefan Eßer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26252884aeSStefan Eßer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27252884aeSStefan Eßer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28252884aeSStefan Eßer  * POSSIBILITY OF SUCH DAMAGE.
29252884aeSStefan Eßer  *
30252884aeSStefan Eßer  * *****************************************************************************
31252884aeSStefan Eßer  *
32252884aeSStefan Eßer  * Code for the number type.
33252884aeSStefan Eßer  *
34252884aeSStefan Eßer  */
35252884aeSStefan Eßer 
36252884aeSStefan Eßer #include <assert.h>
37252884aeSStefan Eßer #include <ctype.h>
38252884aeSStefan Eßer #include <stdbool.h>
39252884aeSStefan Eßer #include <stdlib.h>
40252884aeSStefan Eßer #include <string.h>
41252884aeSStefan Eßer #include <setjmp.h>
42252884aeSStefan Eßer #include <limits.h>
43252884aeSStefan Eßer 
44252884aeSStefan Eßer #include <num.h>
45252884aeSStefan Eßer #include <rand.h>
46252884aeSStefan Eßer #include <vm.h>
47d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
48d101cdd6SStefan Eßer #include <library.h>
49d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
50252884aeSStefan Eßer 
5144d4804dSStefan Eßer // Before you try to understand this code, see the development manual
5244d4804dSStefan Eßer // (manuals/development.md#numbers).
5344d4804dSStefan Eßer 
5478bc019dSStefan Eßer static void
5578bc019dSStefan Eßer bc_num_m(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale);
56252884aeSStefan Eßer 
5744d4804dSStefan Eßer /**
5844d4804dSStefan Eßer  * Multiply two numbers and throw a math error if they overflow.
5944d4804dSStefan Eßer  * @param a  The first operand.
6044d4804dSStefan Eßer  * @param b  The second operand.
6144d4804dSStefan Eßer  * @return   The product of the two operands.
6244d4804dSStefan Eßer  */
6378bc019dSStefan Eßer static inline size_t
6478bc019dSStefan Eßer bc_num_mulOverflow(size_t a, size_t b)
6578bc019dSStefan Eßer {
6644d4804dSStefan Eßer 	size_t res = a * b;
6744d4804dSStefan Eßer 	if (BC_ERR(BC_VM_MUL_OVERFLOW(a, b, res))) bc_err(BC_ERR_MATH_OVERFLOW);
6844d4804dSStefan Eßer 	return res;
6944d4804dSStefan Eßer }
7044d4804dSStefan Eßer 
7144d4804dSStefan Eßer /**
7244d4804dSStefan Eßer  * Conditionally negate @a n based on @a neg. Algorithm taken from
7344d4804dSStefan Eßer  * https://graphics.stanford.edu/~seander/bithacks.html#ConditionalNegate .
7444d4804dSStefan Eßer  * @param n    The value to turn into a signed value and negate.
7544d4804dSStefan Eßer  * @param neg  The condition to negate or not.
7644d4804dSStefan Eßer  */
7778bc019dSStefan Eßer static inline ssize_t
7878bc019dSStefan Eßer bc_num_neg(size_t n, bool neg)
7978bc019dSStefan Eßer {
80252884aeSStefan Eßer 	return (((ssize_t) n) ^ -((ssize_t) neg)) + neg;
81252884aeSStefan Eßer }
82252884aeSStefan Eßer 
8344d4804dSStefan Eßer /**
8444d4804dSStefan Eßer  * Compare a BcNum against zero.
8544d4804dSStefan Eßer  * @param n  The number to compare.
8644d4804dSStefan Eßer  * @return   -1 if the number is less than 0, 1 if greater, and 0 if equal.
8744d4804dSStefan Eßer  */
8878bc019dSStefan Eßer ssize_t
8978bc019dSStefan Eßer bc_num_cmpZero(const BcNum* n)
9078bc019dSStefan Eßer {
9150696a6eSStefan Eßer 	return bc_num_neg((n)->len != 0, BC_NUM_NEG(n));
92252884aeSStefan Eßer }
93252884aeSStefan Eßer 
9444d4804dSStefan Eßer /**
9544d4804dSStefan Eßer  * Return the number of integer limbs in a BcNum. This is the opposite of rdx.
9644d4804dSStefan Eßer  * @param n  The number to return the amount of integer limbs for.
9744d4804dSStefan Eßer  * @return   The amount of integer limbs in @a n.
9844d4804dSStefan Eßer  */
9978bc019dSStefan Eßer static inline size_t
10078bc019dSStefan Eßer bc_num_int(const BcNum* n)
10178bc019dSStefan Eßer {
10250696a6eSStefan Eßer 	return n->len ? n->len - BC_NUM_RDX_VAL(n) : 0;
103252884aeSStefan Eßer }
104252884aeSStefan Eßer 
10544d4804dSStefan Eßer /**
10644d4804dSStefan Eßer  * Expand a number's allocation capacity to at least req limbs.
10744d4804dSStefan Eßer  * @param n    The number to expand.
10844d4804dSStefan Eßer  * @param req  The number limbs to expand the allocation capacity to.
10944d4804dSStefan Eßer  */
11078bc019dSStefan Eßer static void
11178bc019dSStefan Eßer bc_num_expand(BcNum* restrict n, size_t req)
11278bc019dSStefan Eßer {
113252884aeSStefan Eßer 	assert(n != NULL);
114252884aeSStefan Eßer 
115252884aeSStefan Eßer 	req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
116252884aeSStefan Eßer 
11778bc019dSStefan Eßer 	if (req > n->cap)
11878bc019dSStefan Eßer 	{
119252884aeSStefan Eßer 		BC_SIG_LOCK;
120252884aeSStefan Eßer 
121252884aeSStefan Eßer 		n->num = bc_vm_realloc(n->num, BC_NUM_SIZE(req));
122252884aeSStefan Eßer 		n->cap = req;
123252884aeSStefan Eßer 
124252884aeSStefan Eßer 		BC_SIG_UNLOCK;
125252884aeSStefan Eßer 	}
126252884aeSStefan Eßer }
127252884aeSStefan Eßer 
12844d4804dSStefan Eßer /**
12944d4804dSStefan Eßer  * Set a number to 0 with the specified scale.
13044d4804dSStefan Eßer  * @param n      The number to set to zero.
13144d4804dSStefan Eßer  * @param scale  The scale to set the number to.
13244d4804dSStefan Eßer  */
133d101cdd6SStefan Eßer static inline void
13478bc019dSStefan Eßer bc_num_setToZero(BcNum* restrict n, size_t scale)
13578bc019dSStefan Eßer {
136252884aeSStefan Eßer 	assert(n != NULL);
137252884aeSStefan Eßer 	n->scale = scale;
138252884aeSStefan Eßer 	n->len = n->rdx = 0;
139252884aeSStefan Eßer }
140252884aeSStefan Eßer 
14178bc019dSStefan Eßer void
14278bc019dSStefan Eßer bc_num_zero(BcNum* restrict n)
14378bc019dSStefan Eßer {
144252884aeSStefan Eßer 	bc_num_setToZero(n, 0);
145252884aeSStefan Eßer }
146252884aeSStefan Eßer 
14778bc019dSStefan Eßer void
14878bc019dSStefan Eßer bc_num_one(BcNum* restrict n)
14978bc019dSStefan Eßer {
150252884aeSStefan Eßer 	bc_num_zero(n);
151252884aeSStefan Eßer 	n->len = 1;
152252884aeSStefan Eßer 	n->num[0] = 1;
153252884aeSStefan Eßer }
154252884aeSStefan Eßer 
15544d4804dSStefan Eßer /**
15644d4804dSStefan Eßer  * "Cleans" a number, which means reducing the length if the most significant
15744d4804dSStefan Eßer  * limbs are zero.
15844d4804dSStefan Eßer  * @param n  The number to clean.
15944d4804dSStefan Eßer  */
16078bc019dSStefan Eßer static void
16178bc019dSStefan Eßer bc_num_clean(BcNum* restrict n)
16278bc019dSStefan Eßer {
16344d4804dSStefan Eßer 	// Reduce the length.
16478bc019dSStefan Eßer 	while (BC_NUM_NONZERO(n) && !n->num[n->len - 1])
16578bc019dSStefan Eßer 	{
16678bc019dSStefan Eßer 		n->len -= 1;
16778bc019dSStefan Eßer 	}
168252884aeSStefan Eßer 
16944d4804dSStefan Eßer 	// Special cases.
17050696a6eSStefan Eßer 	if (BC_NUM_ZERO(n)) n->rdx = 0;
17178bc019dSStefan Eßer 	else
17278bc019dSStefan Eßer 	{
17344d4804dSStefan Eßer 		// len must be at least as much as rdx.
17450696a6eSStefan Eßer 		size_t rdx = BC_NUM_RDX_VAL(n);
17550696a6eSStefan Eßer 		if (n->len < rdx) n->len = rdx;
176252884aeSStefan Eßer 	}
177252884aeSStefan Eßer }
178252884aeSStefan Eßer 
17944d4804dSStefan Eßer /**
18044d4804dSStefan Eßer  * Returns the log base 10 of @a i. I could have done this with floating-point
18144d4804dSStefan Eßer  * math, and in fact, I originally did. However, that was the only
18244d4804dSStefan Eßer  * floating-point code in the entire codebase, and I decided I didn't want any.
18344d4804dSStefan Eßer  * This is fast enough. Also, it might handle larger numbers better.
18444d4804dSStefan Eßer  * @param i  The number to return the log base 10 of.
18544d4804dSStefan Eßer  * @return   The log base 10 of @a i.
18644d4804dSStefan Eßer  */
18778bc019dSStefan Eßer static size_t
18878bc019dSStefan Eßer bc_num_log10(size_t i)
18978bc019dSStefan Eßer {
190252884aeSStefan Eßer 	size_t len;
19178bc019dSStefan Eßer 
19278bc019dSStefan Eßer 	for (len = 1; i; i /= BC_BASE, ++len)
19378bc019dSStefan Eßer 	{
19478bc019dSStefan Eßer 		continue;
19578bc019dSStefan Eßer 	}
19678bc019dSStefan Eßer 
197252884aeSStefan Eßer 	assert(len - 1 <= BC_BASE_DIGS + 1);
19878bc019dSStefan Eßer 
199252884aeSStefan Eßer 	return len - 1;
200252884aeSStefan Eßer }
201252884aeSStefan Eßer 
20244d4804dSStefan Eßer /**
20344d4804dSStefan Eßer  * Returns the number of decimal digits in a limb that are zero starting at the
20444d4804dSStefan Eßer  * most significant digits. This basically returns how much of the limb is used.
20544d4804dSStefan Eßer  * @param n  The number.
20644d4804dSStefan Eßer  * @return   The number of decimal digits that are 0 starting at the most
20744d4804dSStefan Eßer  *           significant digits.
20844d4804dSStefan Eßer  */
20978bc019dSStefan Eßer static inline size_t
21078bc019dSStefan Eßer bc_num_zeroDigits(const BcDig* n)
21178bc019dSStefan Eßer {
212252884aeSStefan Eßer 	assert(*n >= 0);
213252884aeSStefan Eßer 	assert(((size_t) *n) < BC_BASE_POW);
214252884aeSStefan Eßer 	return BC_BASE_DIGS - bc_num_log10((size_t) *n);
215252884aeSStefan Eßer }
216252884aeSStefan Eßer 
21744d4804dSStefan Eßer /**
21844d4804dSStefan Eßer  * Return the total number of integer digits in a number. This is the opposite
21944d4804dSStefan Eßer  * of scale, like bc_num_int() is the opposite of rdx.
22044d4804dSStefan Eßer  * @param n  The number.
22144d4804dSStefan Eßer  * @return   The number of integer digits in @a n.
22244d4804dSStefan Eßer  */
22378bc019dSStefan Eßer static size_t
22478bc019dSStefan Eßer bc_num_intDigits(const BcNum* n)
22578bc019dSStefan Eßer {
226252884aeSStefan Eßer 	size_t digits = bc_num_int(n) * BC_BASE_DIGS;
227252884aeSStefan Eßer 	if (digits > 0) digits -= bc_num_zeroDigits(n->num + n->len - 1);
228252884aeSStefan Eßer 	return digits;
229252884aeSStefan Eßer }
230252884aeSStefan Eßer 
23144d4804dSStefan Eßer /**
23244d4804dSStefan Eßer  * Returns the number of limbs of a number that are non-zero starting at the
23344d4804dSStefan Eßer  * most significant limbs. This expects that there are *no* integer limbs in the
23444d4804dSStefan Eßer  * number because it is specifically to figure out how many zero limbs after the
23544d4804dSStefan Eßer  * decimal place to ignore. If there are zero limbs after non-zero limbs, they
23644d4804dSStefan Eßer  * are counted as non-zero limbs.
23744d4804dSStefan Eßer  * @param n  The number.
23844d4804dSStefan Eßer  * @return   The number of non-zero limbs after the decimal point.
23944d4804dSStefan Eßer  */
24078bc019dSStefan Eßer static size_t
24178bc019dSStefan Eßer bc_num_nonZeroLen(const BcNum* restrict n)
24278bc019dSStefan Eßer {
243252884aeSStefan Eßer 	size_t i, len = n->len;
24478bc019dSStefan Eßer 
24550696a6eSStefan Eßer 	assert(len == BC_NUM_RDX_VAL(n));
24678bc019dSStefan Eßer 
24778bc019dSStefan Eßer 	for (i = len - 1; i < len && !n->num[i]; --i)
24878bc019dSStefan Eßer 	{
24978bc019dSStefan Eßer 		continue;
25078bc019dSStefan Eßer 	}
25178bc019dSStefan Eßer 
252252884aeSStefan Eßer 	assert(i + 1 > 0);
25378bc019dSStefan Eßer 
254252884aeSStefan Eßer 	return i + 1;
255252884aeSStefan Eßer }
256252884aeSStefan Eßer 
25744d4804dSStefan Eßer /**
25844d4804dSStefan Eßer  * Performs a one-limb add with a carry.
25944d4804dSStefan Eßer  * @param a      The first limb.
26044d4804dSStefan Eßer  * @param b      The second limb.
26144d4804dSStefan Eßer  * @param carry  An in/out parameter; the carry in from the previous add and the
26244d4804dSStefan Eßer  *               carry out from this add.
26344d4804dSStefan Eßer  * @return       The resulting limb sum.
26444d4804dSStefan Eßer  */
26578bc019dSStefan Eßer static BcDig
26678bc019dSStefan Eßer bc_num_addDigits(BcDig a, BcDig b, bool* carry)
26778bc019dSStefan Eßer {
268252884aeSStefan Eßer 	assert(((BcBigDig) BC_BASE_POW) * 2 == ((BcDig) BC_BASE_POW) * 2);
269d101cdd6SStefan Eßer 	assert(a < BC_BASE_POW && a >= 0);
270d101cdd6SStefan Eßer 	assert(b < BC_BASE_POW && b >= 0);
271252884aeSStefan Eßer 
272252884aeSStefan Eßer 	a += b + *carry;
273252884aeSStefan Eßer 	*carry = (a >= BC_BASE_POW);
274252884aeSStefan Eßer 	if (*carry) a -= BC_BASE_POW;
275252884aeSStefan Eßer 
276252884aeSStefan Eßer 	assert(a >= 0);
277252884aeSStefan Eßer 	assert(a < BC_BASE_POW);
278252884aeSStefan Eßer 
279252884aeSStefan Eßer 	return a;
280252884aeSStefan Eßer }
281252884aeSStefan Eßer 
28244d4804dSStefan Eßer /**
28344d4804dSStefan Eßer  * Performs a one-limb subtract with a carry.
28444d4804dSStefan Eßer  * @param a      The first limb.
28544d4804dSStefan Eßer  * @param b      The second limb.
28644d4804dSStefan Eßer  * @param carry  An in/out parameter; the carry in from the previous subtract
28744d4804dSStefan Eßer  *               and the carry out from this subtract.
28844d4804dSStefan Eßer  * @return       The resulting limb difference.
28944d4804dSStefan Eßer  */
29078bc019dSStefan Eßer static BcDig
29178bc019dSStefan Eßer bc_num_subDigits(BcDig a, BcDig b, bool* carry)
29278bc019dSStefan Eßer {
293d101cdd6SStefan Eßer 	assert(a < BC_BASE_POW && a >= 0);
294d101cdd6SStefan Eßer 	assert(b < BC_BASE_POW && b >= 0);
295252884aeSStefan Eßer 
296252884aeSStefan Eßer 	b += *carry;
297252884aeSStefan Eßer 	*carry = (a < b);
298252884aeSStefan Eßer 	if (*carry) a += BC_BASE_POW;
299252884aeSStefan Eßer 
300252884aeSStefan Eßer 	assert(a - b >= 0);
301252884aeSStefan Eßer 	assert(a - b < BC_BASE_POW);
302252884aeSStefan Eßer 
303252884aeSStefan Eßer 	return a - b;
304252884aeSStefan Eßer }
305252884aeSStefan Eßer 
30644d4804dSStefan Eßer /**
30744d4804dSStefan Eßer  * Add two BcDig arrays and store the result in the first array.
30844d4804dSStefan Eßer  * @param a    The first operand and out array.
30944d4804dSStefan Eßer  * @param b    The second operand.
31044d4804dSStefan Eßer  * @param len  The length of @a b.
31144d4804dSStefan Eßer  */
31278bc019dSStefan Eßer static void
31378bc019dSStefan Eßer bc_num_addArrays(BcDig* restrict a, const BcDig* restrict b, size_t len)
314252884aeSStefan Eßer {
315252884aeSStefan Eßer 	size_t i;
316252884aeSStefan Eßer 	bool carry = false;
317252884aeSStefan Eßer 
31878bc019dSStefan Eßer 	for (i = 0; i < len; ++i)
31978bc019dSStefan Eßer 	{
32078bc019dSStefan Eßer 		a[i] = bc_num_addDigits(a[i], b[i], &carry);
32178bc019dSStefan Eßer 	}
322252884aeSStefan Eßer 
32344d4804dSStefan Eßer 	// Take care of the extra limbs in the bigger array.
32478bc019dSStefan Eßer 	for (; carry; ++i)
32578bc019dSStefan Eßer 	{
32678bc019dSStefan Eßer 		a[i] = bc_num_addDigits(a[i], 0, &carry);
32778bc019dSStefan Eßer 	}
328252884aeSStefan Eßer }
329252884aeSStefan Eßer 
33044d4804dSStefan Eßer /**
33144d4804dSStefan Eßer  * Subtract two BcDig arrays and store the result in the first array.
33244d4804dSStefan Eßer  * @param a    The first operand and out array.
33344d4804dSStefan Eßer  * @param b    The second operand.
33444d4804dSStefan Eßer  * @param len  The length of @a b.
33544d4804dSStefan Eßer  */
33678bc019dSStefan Eßer static void
33778bc019dSStefan Eßer bc_num_subArrays(BcDig* restrict a, const BcDig* restrict b, size_t len)
338252884aeSStefan Eßer {
339252884aeSStefan Eßer 	size_t i;
340252884aeSStefan Eßer 	bool carry = false;
341252884aeSStefan Eßer 
34278bc019dSStefan Eßer 	for (i = 0; i < len; ++i)
34378bc019dSStefan Eßer 	{
34478bc019dSStefan Eßer 		a[i] = bc_num_subDigits(a[i], b[i], &carry);
34578bc019dSStefan Eßer 	}
346252884aeSStefan Eßer 
34744d4804dSStefan Eßer 	// Take care of the extra limbs in the bigger array.
34878bc019dSStefan Eßer 	for (; carry; ++i)
34978bc019dSStefan Eßer 	{
35078bc019dSStefan Eßer 		a[i] = bc_num_subDigits(a[i], 0, &carry);
35178bc019dSStefan Eßer 	}
352252884aeSStefan Eßer }
353252884aeSStefan Eßer 
35444d4804dSStefan Eßer /**
35544d4804dSStefan Eßer  * Multiply a BcNum array by a one-limb number. This is a faster version of
35644d4804dSStefan Eßer  * multiplication for when we can use it.
35744d4804dSStefan Eßer  * @param a  The BcNum to multiply by the one-limb number.
35844d4804dSStefan Eßer  * @param b  The one limb of the one-limb number.
35944d4804dSStefan Eßer  * @param c  The return parameter.
36044d4804dSStefan Eßer  */
36178bc019dSStefan Eßer static void
36278bc019dSStefan Eßer bc_num_mulArray(const BcNum* restrict a, BcBigDig b, BcNum* restrict c)
363252884aeSStefan Eßer {
364252884aeSStefan Eßer 	size_t i;
365252884aeSStefan Eßer 	BcBigDig carry = 0;
366252884aeSStefan Eßer 
367252884aeSStefan Eßer 	assert(b <= BC_BASE_POW);
368252884aeSStefan Eßer 
36944d4804dSStefan Eßer 	// Make sure the return parameter is big enough.
370252884aeSStefan Eßer 	if (a->len + 1 > c->cap) bc_num_expand(c, a->len + 1);
371252884aeSStefan Eßer 
37244d4804dSStefan Eßer 	// We want the entire return parameter to be zero for cleaning later.
37378bc019dSStefan Eßer 	// NOLINTNEXTLINE
374252884aeSStefan Eßer 	memset(c->num, 0, BC_NUM_SIZE(c->cap));
375252884aeSStefan Eßer 
37644d4804dSStefan Eßer 	// Actual multiplication loop.
37778bc019dSStefan Eßer 	for (i = 0; i < a->len; ++i)
37878bc019dSStefan Eßer 	{
379252884aeSStefan Eßer 		BcBigDig in = ((BcBigDig) a->num[i]) * b + carry;
380252884aeSStefan Eßer 		c->num[i] = in % BC_BASE_POW;
381252884aeSStefan Eßer 		carry = in / BC_BASE_POW;
382252884aeSStefan Eßer 	}
383252884aeSStefan Eßer 
384252884aeSStefan Eßer 	assert(carry < BC_BASE_POW);
38544d4804dSStefan Eßer 
38644d4804dSStefan Eßer 	// Finishing touches.
387252884aeSStefan Eßer 	c->num[i] = (BcDig) carry;
388d101cdd6SStefan Eßer 	assert(c->num[i] >= 0 && c->num[i] < BC_BASE_POW);
389252884aeSStefan Eßer 	c->len = a->len;
390252884aeSStefan Eßer 	c->len += (carry != 0);
391252884aeSStefan Eßer 
392252884aeSStefan Eßer 	bc_num_clean(c);
393252884aeSStefan Eßer 
39444d4804dSStefan Eßer 	// Postconditions.
39550696a6eSStefan Eßer 	assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c));
39650696a6eSStefan Eßer 	assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len);
39750696a6eSStefan Eßer 	assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len);
398252884aeSStefan Eßer }
399252884aeSStefan Eßer 
40044d4804dSStefan Eßer /**
40144d4804dSStefan Eßer  * Divide a BcNum array by a one-limb number. This is a faster version of divide
40244d4804dSStefan Eßer  * for when we can use it.
40344d4804dSStefan Eßer  * @param a    The BcNum to multiply by the one-limb number.
40444d4804dSStefan Eßer  * @param b    The one limb of the one-limb number.
40544d4804dSStefan Eßer  * @param c    The return parameter for the quotient.
40644d4804dSStefan Eßer  * @param rem  The return parameter for the remainder.
40744d4804dSStefan Eßer  */
40878bc019dSStefan Eßer static void
40978bc019dSStefan Eßer bc_num_divArray(const BcNum* restrict a, BcBigDig b, BcNum* restrict c,
41078bc019dSStefan Eßer                 BcBigDig* rem)
411252884aeSStefan Eßer {
412252884aeSStefan Eßer 	size_t i;
413252884aeSStefan Eßer 	BcBigDig carry = 0;
414252884aeSStefan Eßer 
415252884aeSStefan Eßer 	assert(c->cap >= a->len);
416252884aeSStefan Eßer 
41744d4804dSStefan Eßer 	// Actual division loop.
41878bc019dSStefan Eßer 	for (i = a->len - 1; i < a->len; --i)
41978bc019dSStefan Eßer 	{
420252884aeSStefan Eßer 		BcBigDig in = ((BcBigDig) a->num[i]) + carry * BC_BASE_POW;
421252884aeSStefan Eßer 		assert(in / b < BC_BASE_POW);
422252884aeSStefan Eßer 		c->num[i] = (BcDig) (in / b);
423d101cdd6SStefan Eßer 		assert(c->num[i] >= 0 && c->num[i] < BC_BASE_POW);
424252884aeSStefan Eßer 		carry = in % b;
425252884aeSStefan Eßer 	}
426252884aeSStefan Eßer 
42744d4804dSStefan Eßer 	// Finishing touches.
428252884aeSStefan Eßer 	c->len = a->len;
429252884aeSStefan Eßer 	bc_num_clean(c);
430252884aeSStefan Eßer 	*rem = carry;
431252884aeSStefan Eßer 
43244d4804dSStefan Eßer 	// Postconditions.
43350696a6eSStefan Eßer 	assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c));
43450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len);
43550696a6eSStefan Eßer 	assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len);
436252884aeSStefan Eßer }
437252884aeSStefan Eßer 
43844d4804dSStefan Eßer /**
43944d4804dSStefan Eßer  * Compare two BcDig arrays and return >0 if @a b is greater, <0 if @a b is
44044d4804dSStefan Eßer  * less, and 0 if equal. Both @a a and @a b must have the same length.
44144d4804dSStefan Eßer  * @param a    The first array.
44244d4804dSStefan Eßer  * @param b    The second array.
44344d4804dSStefan Eßer  * @param len  The minimum length of the arrays.
44444d4804dSStefan Eßer  */
44578bc019dSStefan Eßer static ssize_t
44678bc019dSStefan Eßer bc_num_compare(const BcDig* restrict a, const BcDig* restrict b, size_t len)
447252884aeSStefan Eßer {
448252884aeSStefan Eßer 	size_t i;
449252884aeSStefan Eßer 	BcDig c = 0;
45078bc019dSStefan Eßer 	for (i = len - 1; i < len && !(c = a[i] - b[i]); --i)
45178bc019dSStefan Eßer 	{
45278bc019dSStefan Eßer 		continue;
45378bc019dSStefan Eßer 	}
454252884aeSStefan Eßer 	return bc_num_neg(i + 1, c < 0);
455252884aeSStefan Eßer }
456252884aeSStefan Eßer 
45778bc019dSStefan Eßer ssize_t
45878bc019dSStefan Eßer bc_num_cmp(const BcNum* a, const BcNum* b)
45978bc019dSStefan Eßer {
46050696a6eSStefan Eßer 	size_t i, min, a_int, b_int, diff, ardx, brdx;
46178bc019dSStefan Eßer 	BcDig* max_num;
46278bc019dSStefan Eßer 	BcDig* min_num;
463252884aeSStefan Eßer 	bool a_max, neg = false;
464252884aeSStefan Eßer 	ssize_t cmp;
465252884aeSStefan Eßer 
466252884aeSStefan Eßer 	assert(a != NULL && b != NULL);
467252884aeSStefan Eßer 
46844d4804dSStefan Eßer 	// Same num? Equal.
469252884aeSStefan Eßer 	if (a == b) return 0;
47044d4804dSStefan Eßer 
47144d4804dSStefan Eßer 	// Easy cases.
47250696a6eSStefan Eßer 	if (BC_NUM_ZERO(a)) return bc_num_neg(b->len != 0, !BC_NUM_NEG(b));
473252884aeSStefan Eßer 	if (BC_NUM_ZERO(b)) return bc_num_cmpZero(a);
47478bc019dSStefan Eßer 	if (BC_NUM_NEG(a))
47578bc019dSStefan Eßer 	{
47650696a6eSStefan Eßer 		if (BC_NUM_NEG(b)) neg = true;
477252884aeSStefan Eßer 		else return -1;
478252884aeSStefan Eßer 	}
47950696a6eSStefan Eßer 	else if (BC_NUM_NEG(b)) return 1;
480252884aeSStefan Eßer 
48144d4804dSStefan Eßer 	// Get the number of int limbs in each number and get the difference.
482252884aeSStefan Eßer 	a_int = bc_num_int(a);
483252884aeSStefan Eßer 	b_int = bc_num_int(b);
484252884aeSStefan Eßer 	a_int -= b_int;
485252884aeSStefan Eßer 
48644d4804dSStefan Eßer 	// If there's a difference, then just return the comparison.
487252884aeSStefan Eßer 	if (a_int) return neg ? -((ssize_t) a_int) : (ssize_t) a_int;
488252884aeSStefan Eßer 
48944d4804dSStefan Eßer 	// Get the rdx's and figure out the max.
49050696a6eSStefan Eßer 	ardx = BC_NUM_RDX_VAL(a);
49150696a6eSStefan Eßer 	brdx = BC_NUM_RDX_VAL(b);
49250696a6eSStefan Eßer 	a_max = (ardx > brdx);
493252884aeSStefan Eßer 
49444d4804dSStefan Eßer 	// Set variables based on the above.
49578bc019dSStefan Eßer 	if (a_max)
49678bc019dSStefan Eßer 	{
49750696a6eSStefan Eßer 		min = brdx;
49850696a6eSStefan Eßer 		diff = ardx - brdx;
499252884aeSStefan Eßer 		max_num = a->num + diff;
500252884aeSStefan Eßer 		min_num = b->num;
501252884aeSStefan Eßer 	}
50278bc019dSStefan Eßer 	else
50378bc019dSStefan Eßer 	{
50450696a6eSStefan Eßer 		min = ardx;
50550696a6eSStefan Eßer 		diff = brdx - ardx;
506252884aeSStefan Eßer 		max_num = b->num + diff;
507252884aeSStefan Eßer 		min_num = a->num;
508252884aeSStefan Eßer 	}
509252884aeSStefan Eßer 
51044d4804dSStefan Eßer 	// Do a full limb-by-limb comparison.
511252884aeSStefan Eßer 	cmp = bc_num_compare(max_num, min_num, b_int + min);
512252884aeSStefan Eßer 
51344d4804dSStefan Eßer 	// If we found a difference, return it based on state.
514252884aeSStefan Eßer 	if (cmp) return bc_num_neg((size_t) cmp, !a_max == !neg);
515252884aeSStefan Eßer 
51644d4804dSStefan Eßer 	// If there was no difference, then the final step is to check which number
51744d4804dSStefan Eßer 	// has greater or lesser limbs beyond the other's.
51878bc019dSStefan Eßer 	for (max_num -= diff, i = diff - 1; i < diff; --i)
51978bc019dSStefan Eßer 	{
520252884aeSStefan Eßer 		if (max_num[i]) return bc_num_neg(1, !a_max == !neg);
521252884aeSStefan Eßer 	}
522252884aeSStefan Eßer 
523252884aeSStefan Eßer 	return 0;
524252884aeSStefan Eßer }
525252884aeSStefan Eßer 
52678bc019dSStefan Eßer void
52778bc019dSStefan Eßer bc_num_truncate(BcNum* restrict n, size_t places)
52878bc019dSStefan Eßer {
52950696a6eSStefan Eßer 	size_t nrdx, places_rdx;
530252884aeSStefan Eßer 
531252884aeSStefan Eßer 	if (!places) return;
532252884aeSStefan Eßer 
53344d4804dSStefan Eßer 	// Grab these needed values; places_rdx is the rdx equivalent to places like
53444d4804dSStefan Eßer 	// rdx is to scale.
53550696a6eSStefan Eßer 	nrdx = BC_NUM_RDX_VAL(n);
53650696a6eSStefan Eßer 	places_rdx = nrdx ? nrdx - BC_NUM_RDX(n->scale - places) : 0;
53744d4804dSStefan Eßer 
53844d4804dSStefan Eßer 	// We cannot truncate more places than we have.
539252884aeSStefan Eßer 	assert(places <= n->scale && (BC_NUM_ZERO(n) || places_rdx <= n->len));
540252884aeSStefan Eßer 
541252884aeSStefan Eßer 	n->scale -= places;
54250696a6eSStefan Eßer 	BC_NUM_RDX_SET(n, nrdx - places_rdx);
543252884aeSStefan Eßer 
54444d4804dSStefan Eßer 	// Only when the number is nonzero do we need to do the hard stuff.
54578bc019dSStefan Eßer 	if (BC_NUM_NONZERO(n))
54678bc019dSStefan Eßer 	{
547252884aeSStefan Eßer 		size_t pow;
548252884aeSStefan Eßer 
54944d4804dSStefan Eßer 		// This calculates how many decimal digits are in the least significant
55044d4804dSStefan Eßer 		// limb.
551252884aeSStefan Eßer 		pow = n->scale % BC_BASE_DIGS;
552252884aeSStefan Eßer 		pow = pow ? BC_BASE_DIGS - pow : 0;
553252884aeSStefan Eßer 		pow = bc_num_pow10[pow];
554252884aeSStefan Eßer 
555252884aeSStefan Eßer 		n->len -= places_rdx;
55644d4804dSStefan Eßer 
55744d4804dSStefan Eßer 		// We have to move limbs to maintain invariants. The limbs must begin at
55844d4804dSStefan Eßer 		// the beginning of the BcNum array.
55978bc019dSStefan Eßer 		// NOLINTNEXTLINE
560252884aeSStefan Eßer 		memmove(n->num, n->num + places_rdx, BC_NUM_SIZE(n->len));
561252884aeSStefan Eßer 
562252884aeSStefan Eßer 		// Clear the lower part of the last digit.
563252884aeSStefan Eßer 		if (BC_NUM_NONZERO(n)) n->num[0] -= n->num[0] % (BcDig) pow;
564252884aeSStefan Eßer 
565252884aeSStefan Eßer 		bc_num_clean(n);
566252884aeSStefan Eßer 	}
567252884aeSStefan Eßer }
568252884aeSStefan Eßer 
56978bc019dSStefan Eßer void
57078bc019dSStefan Eßer bc_num_extend(BcNum* restrict n, size_t places)
57178bc019dSStefan Eßer {
57250696a6eSStefan Eßer 	size_t nrdx, places_rdx;
573252884aeSStefan Eßer 
574252884aeSStefan Eßer 	if (!places) return;
57544d4804dSStefan Eßer 
57644d4804dSStefan Eßer 	// Easy case with zero; set the scale.
57778bc019dSStefan Eßer 	if (BC_NUM_ZERO(n))
57878bc019dSStefan Eßer 	{
579252884aeSStefan Eßer 		n->scale += places;
580252884aeSStefan Eßer 		return;
581252884aeSStefan Eßer 	}
582252884aeSStefan Eßer 
58344d4804dSStefan Eßer 	// Grab these needed values; places_rdx is the rdx equivalent to places like
58444d4804dSStefan Eßer 	// rdx is to scale.
58550696a6eSStefan Eßer 	nrdx = BC_NUM_RDX_VAL(n);
58650696a6eSStefan Eßer 	places_rdx = BC_NUM_RDX(places + n->scale) - nrdx;
587252884aeSStefan Eßer 
58844d4804dSStefan Eßer 	// This is the hard case. We need to expand the number, move the limbs, and
58944d4804dSStefan Eßer 	// set the limbs that were just cleared.
59078bc019dSStefan Eßer 	if (places_rdx)
59178bc019dSStefan Eßer 	{
592252884aeSStefan Eßer 		bc_num_expand(n, bc_vm_growSize(n->len, places_rdx));
59378bc019dSStefan Eßer 		// NOLINTNEXTLINE
594252884aeSStefan Eßer 		memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len));
59578bc019dSStefan Eßer 		// NOLINTNEXTLINE
596252884aeSStefan Eßer 		memset(n->num, 0, BC_NUM_SIZE(places_rdx));
597252884aeSStefan Eßer 	}
598252884aeSStefan Eßer 
59944d4804dSStefan Eßer 	// Finally, set scale and rdx.
60050696a6eSStefan Eßer 	BC_NUM_RDX_SET(n, nrdx + places_rdx);
601252884aeSStefan Eßer 	n->scale += places;
602252884aeSStefan Eßer 	n->len += places_rdx;
603252884aeSStefan Eßer 
60450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VAL(n) == BC_NUM_RDX(n->scale));
605252884aeSStefan Eßer }
606252884aeSStefan Eßer 
60744d4804dSStefan Eßer /**
60844d4804dSStefan Eßer  * Retires (finishes) a multiplication or division operation.
60944d4804dSStefan Eßer  */
61078bc019dSStefan Eßer static void
61178bc019dSStefan Eßer bc_num_retireMul(BcNum* restrict n, size_t scale, bool neg1, bool neg2)
612252884aeSStefan Eßer {
61344d4804dSStefan Eßer 	// Make sure scale is correct.
614252884aeSStefan Eßer 	if (n->scale < scale) bc_num_extend(n, scale - n->scale);
615252884aeSStefan Eßer 	else bc_num_truncate(n, n->scale - scale);
616252884aeSStefan Eßer 
617252884aeSStefan Eßer 	bc_num_clean(n);
61844d4804dSStefan Eßer 
61944d4804dSStefan Eßer 	// We need to ensure rdx is correct.
62050696a6eSStefan Eßer 	if (BC_NUM_NONZERO(n)) n->rdx = BC_NUM_NEG_VAL(n, !neg1 != !neg2);
621252884aeSStefan Eßer }
622252884aeSStefan Eßer 
62344d4804dSStefan Eßer /**
62444d4804dSStefan Eßer  * Splits a number into two BcNum's. This is used in Karatsuba.
62544d4804dSStefan Eßer  * @param n    The number to split.
62644d4804dSStefan Eßer  * @param idx  The index to split at.
62744d4804dSStefan Eßer  * @param a    An out parameter; the low part of @a n.
62844d4804dSStefan Eßer  * @param b    An out parameter; the high part of @a n.
62944d4804dSStefan Eßer  */
63078bc019dSStefan Eßer static void
63178bc019dSStefan Eßer bc_num_split(const BcNum* restrict n, size_t idx, BcNum* restrict a,
63278bc019dSStefan Eßer              BcNum* restrict b)
633252884aeSStefan Eßer {
63444d4804dSStefan Eßer 	// We want a and b to be clear.
635252884aeSStefan Eßer 	assert(BC_NUM_ZERO(a));
636252884aeSStefan Eßer 	assert(BC_NUM_ZERO(b));
637252884aeSStefan Eßer 
63844d4804dSStefan Eßer 	// The usual case.
63978bc019dSStefan Eßer 	if (idx < n->len)
64078bc019dSStefan Eßer 	{
64144d4804dSStefan Eßer 		// Set the fields first.
642252884aeSStefan Eßer 		b->len = n->len - idx;
643252884aeSStefan Eßer 		a->len = idx;
64450696a6eSStefan Eßer 		a->scale = b->scale = 0;
64550696a6eSStefan Eßer 		BC_NUM_RDX_SET(a, 0);
64650696a6eSStefan Eßer 		BC_NUM_RDX_SET(b, 0);
647252884aeSStefan Eßer 
648252884aeSStefan Eßer 		assert(a->cap >= a->len);
649252884aeSStefan Eßer 		assert(b->cap >= b->len);
650252884aeSStefan Eßer 
65144d4804dSStefan Eßer 		// Copy the arrays. This is not necessary for safety, but it is faster,
65244d4804dSStefan Eßer 		// for some reason.
65378bc019dSStefan Eßer 		// NOLINTNEXTLINE
654252884aeSStefan Eßer 		memcpy(b->num, n->num + idx, BC_NUM_SIZE(b->len));
65578bc019dSStefan Eßer 		// NOLINTNEXTLINE
656252884aeSStefan Eßer 		memcpy(a->num, n->num, BC_NUM_SIZE(idx));
657252884aeSStefan Eßer 
658252884aeSStefan Eßer 		bc_num_clean(b);
659252884aeSStefan Eßer 	}
66044d4804dSStefan Eßer 	// If the index is weird, just skip the split.
661252884aeSStefan Eßer 	else bc_num_copy(a, n);
662252884aeSStefan Eßer 
663252884aeSStefan Eßer 	bc_num_clean(a);
664252884aeSStefan Eßer }
665252884aeSStefan Eßer 
66644d4804dSStefan Eßer /**
66744d4804dSStefan Eßer  * Copies a number into another, but shifts the rdx so that the result number
66844d4804dSStefan Eßer  * only sees the integer part of the source number.
66944d4804dSStefan Eßer  * @param n  The number to copy.
67044d4804dSStefan Eßer  * @param r  The result number with a shifted rdx, len, and num.
67144d4804dSStefan Eßer  */
67278bc019dSStefan Eßer static void
67378bc019dSStefan Eßer bc_num_shiftRdx(const BcNum* restrict n, BcNum* restrict r)
67478bc019dSStefan Eßer {
67544d4804dSStefan Eßer 	size_t rdx = BC_NUM_RDX_VAL(n);
67644d4804dSStefan Eßer 
67744d4804dSStefan Eßer 	r->len = n->len - rdx;
67844d4804dSStefan Eßer 	r->cap = n->cap - rdx;
67944d4804dSStefan Eßer 	r->num = n->num + rdx;
68044d4804dSStefan Eßer 
68144d4804dSStefan Eßer 	BC_NUM_RDX_SET_NEG(r, 0, BC_NUM_NEG(n));
68244d4804dSStefan Eßer 	r->scale = 0;
68344d4804dSStefan Eßer }
68444d4804dSStefan Eßer 
68544d4804dSStefan Eßer /**
68644d4804dSStefan Eßer  * Shifts a number so that all of the least significant limbs of the number are
68744d4804dSStefan Eßer  * skipped. This must be undone by bc_num_unshiftZero().
68844d4804dSStefan Eßer  * @param n  The number to shift.
68944d4804dSStefan Eßer  */
69078bc019dSStefan Eßer static size_t
69178bc019dSStefan Eßer bc_num_shiftZero(BcNum* restrict n)
69278bc019dSStefan Eßer {
693d101cdd6SStefan Eßer 	// This is volatile to quiet a GCC warning about longjmp() clobbering.
694d101cdd6SStefan Eßer 	volatile size_t i;
695252884aeSStefan Eßer 
69644d4804dSStefan Eßer 	// If we don't have an integer, that is a problem, but it's also a bug
69744d4804dSStefan Eßer 	// because the caller should have set everything up right.
69850696a6eSStefan Eßer 	assert(!BC_NUM_RDX_VAL(n) || BC_NUM_ZERO(n));
699252884aeSStefan Eßer 
70078bc019dSStefan Eßer 	for (i = 0; i < n->len && !n->num[i]; ++i)
70178bc019dSStefan Eßer 	{
70278bc019dSStefan Eßer 		continue;
70378bc019dSStefan Eßer 	}
704252884aeSStefan Eßer 
705252884aeSStefan Eßer 	n->len -= i;
706252884aeSStefan Eßer 	n->num += i;
707252884aeSStefan Eßer 
708252884aeSStefan Eßer 	return i;
709252884aeSStefan Eßer }
710252884aeSStefan Eßer 
71144d4804dSStefan Eßer /**
71244d4804dSStefan Eßer  * Undo the damage done by bc_num_unshiftZero(). This must be called like all
71344d4804dSStefan Eßer  * cleanup functions: after a label used by setjmp() and longjmp().
71444d4804dSStefan Eßer  * @param n           The number to unshift.
71544d4804dSStefan Eßer  * @param places_rdx  The amount the number was originally shift.
71644d4804dSStefan Eßer  */
71778bc019dSStefan Eßer static void
71878bc019dSStefan Eßer bc_num_unshiftZero(BcNum* restrict n, size_t places_rdx)
71978bc019dSStefan Eßer {
720252884aeSStefan Eßer 	n->len += places_rdx;
721252884aeSStefan Eßer 	n->num -= places_rdx;
722252884aeSStefan Eßer }
723252884aeSStefan Eßer 
72444d4804dSStefan Eßer /**
72544d4804dSStefan Eßer  * Shifts the digits right within a number by no more than BC_BASE_DIGS - 1.
72644d4804dSStefan Eßer  * This is the final step on shifting numbers with the shift operators. It
72744d4804dSStefan Eßer  * depends on the caller to shift the limbs properly because all it does is
72844d4804dSStefan Eßer  * ensure that the rdx point is realigned to be between limbs.
72944d4804dSStefan Eßer  * @param n    The number to shift digits in.
73044d4804dSStefan Eßer  * @param dig  The number of places to shift right.
73144d4804dSStefan Eßer  */
73278bc019dSStefan Eßer static void
73378bc019dSStefan Eßer bc_num_shift(BcNum* restrict n, BcBigDig dig)
73478bc019dSStefan Eßer {
735252884aeSStefan Eßer 	size_t i, len = n->len;
736252884aeSStefan Eßer 	BcBigDig carry = 0, pow;
737252884aeSStefan Eßer 	BcDig* ptr = n->num;
738252884aeSStefan Eßer 
739252884aeSStefan Eßer 	assert(dig < BC_BASE_DIGS);
740252884aeSStefan Eßer 
74144d4804dSStefan Eßer 	// Figure out the parameters for division.
742252884aeSStefan Eßer 	pow = bc_num_pow10[dig];
743252884aeSStefan Eßer 	dig = bc_num_pow10[BC_BASE_DIGS - dig];
744252884aeSStefan Eßer 
74544d4804dSStefan Eßer 	// Run a series of divisions and mods with carries across the entire number
74644d4804dSStefan Eßer 	// array. This effectively shifts everything over.
74778bc019dSStefan Eßer 	for (i = len - 1; i < len; --i)
74878bc019dSStefan Eßer 	{
749252884aeSStefan Eßer 		BcBigDig in, temp;
750252884aeSStefan Eßer 		in = ((BcBigDig) ptr[i]);
751252884aeSStefan Eßer 		temp = carry * dig;
752252884aeSStefan Eßer 		carry = in % pow;
753252884aeSStefan Eßer 		ptr[i] = ((BcDig) (in / pow)) + (BcDig) temp;
754d101cdd6SStefan Eßer 		assert(ptr[i] >= 0 && ptr[i] < BC_BASE_POW);
755252884aeSStefan Eßer 	}
756252884aeSStefan Eßer 
757252884aeSStefan Eßer 	assert(!carry);
758252884aeSStefan Eßer }
759252884aeSStefan Eßer 
76044d4804dSStefan Eßer /**
76144d4804dSStefan Eßer  * Shift a number left by a certain number of places. This is the workhorse of
76244d4804dSStefan Eßer  * the left shift operator.
76344d4804dSStefan Eßer  * @param n       The number to shift left.
76444d4804dSStefan Eßer  * @param places  The amount of places to shift @a n left by.
76544d4804dSStefan Eßer  */
76678bc019dSStefan Eßer static void
76778bc019dSStefan Eßer bc_num_shiftLeft(BcNum* restrict n, size_t places)
76878bc019dSStefan Eßer {
769252884aeSStefan Eßer 	BcBigDig dig;
770252884aeSStefan Eßer 	size_t places_rdx;
771252884aeSStefan Eßer 	bool shift;
772252884aeSStefan Eßer 
773252884aeSStefan Eßer 	if (!places) return;
77444d4804dSStefan Eßer 
77544d4804dSStefan Eßer 	// Make sure to grow the number if necessary.
77678bc019dSStefan Eßer 	if (places > n->scale)
77778bc019dSStefan Eßer 	{
778252884aeSStefan Eßer 		size_t size = bc_vm_growSize(BC_NUM_RDX(places - n->scale), n->len);
77944d4804dSStefan Eßer 		if (size > SIZE_MAX - 1) bc_err(BC_ERR_MATH_OVERFLOW);
780252884aeSStefan Eßer 	}
78144d4804dSStefan Eßer 
78244d4804dSStefan Eßer 	// If zero, we can just set the scale and bail.
78378bc019dSStefan Eßer 	if (BC_NUM_ZERO(n))
78478bc019dSStefan Eßer 	{
785252884aeSStefan Eßer 		if (n->scale >= places) n->scale -= places;
786252884aeSStefan Eßer 		else n->scale = 0;
787252884aeSStefan Eßer 		return;
788252884aeSStefan Eßer 	}
789252884aeSStefan Eßer 
79044d4804dSStefan Eßer 	// When I changed bc to have multiple digits per limb, this was the hardest
79144d4804dSStefan Eßer 	// code to change. This and shift right. Make sure you understand this
79244d4804dSStefan Eßer 	// before attempting anything.
79344d4804dSStefan Eßer 
79444d4804dSStefan Eßer 	// This is how many limbs we will shift.
795252884aeSStefan Eßer 	dig = (BcBigDig) (places % BC_BASE_DIGS);
796252884aeSStefan Eßer 	shift = (dig != 0);
79744d4804dSStefan Eßer 
79844d4804dSStefan Eßer 	// Convert places to a rdx value.
799252884aeSStefan Eßer 	places_rdx = BC_NUM_RDX(places);
800252884aeSStefan Eßer 
80144d4804dSStefan Eßer 	// If the number is not an integer, we need special care. The reason an
80244d4804dSStefan Eßer 	// integer doesn't is because left shift would only extend the integer,
80344d4804dSStefan Eßer 	// whereas a non-integer might have its fractional part eliminated or only
80444d4804dSStefan Eßer 	// partially eliminated.
80578bc019dSStefan Eßer 	if (n->scale)
80678bc019dSStefan Eßer 	{
80750696a6eSStefan Eßer 		size_t nrdx = BC_NUM_RDX_VAL(n);
80850696a6eSStefan Eßer 
80944d4804dSStefan Eßer 		// If the number's rdx is bigger, that's the hard case.
81078bc019dSStefan Eßer 		if (nrdx >= places_rdx)
81178bc019dSStefan Eßer 		{
812252884aeSStefan Eßer 			size_t mod = n->scale % BC_BASE_DIGS, revdig;
813252884aeSStefan Eßer 
81444d4804dSStefan Eßer 			// We want mod to be in the range [1, BC_BASE_DIGS], not
81544d4804dSStefan Eßer 			// [0, BC_BASE_DIGS).
816252884aeSStefan Eßer 			mod = mod ? mod : BC_BASE_DIGS;
81744d4804dSStefan Eßer 
81844d4804dSStefan Eßer 			// We need to reverse dig to get the actual number of digits.
819252884aeSStefan Eßer 			revdig = dig ? BC_BASE_DIGS - dig : 0;
820252884aeSStefan Eßer 
82144d4804dSStefan Eßer 			// If the two overflow BC_BASE_DIGS, we need to move an extra place.
822252884aeSStefan Eßer 			if (mod + revdig > BC_BASE_DIGS) places_rdx = 1;
823252884aeSStefan Eßer 			else places_rdx = 0;
824252884aeSStefan Eßer 		}
82550696a6eSStefan Eßer 		else places_rdx -= nrdx;
826252884aeSStefan Eßer 	}
827252884aeSStefan Eßer 
82844d4804dSStefan Eßer 	// If this is non-zero, we need an extra place, so expand, move, and set.
82978bc019dSStefan Eßer 	if (places_rdx)
83078bc019dSStefan Eßer 	{
831252884aeSStefan Eßer 		bc_num_expand(n, bc_vm_growSize(n->len, places_rdx));
83278bc019dSStefan Eßer 		// NOLINTNEXTLINE
833252884aeSStefan Eßer 		memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len));
83478bc019dSStefan Eßer 		// NOLINTNEXTLINE
835252884aeSStefan Eßer 		memset(n->num, 0, BC_NUM_SIZE(places_rdx));
836252884aeSStefan Eßer 		n->len += places_rdx;
837252884aeSStefan Eßer 	}
838252884aeSStefan Eßer 
83944d4804dSStefan Eßer 	// Set the scale appropriately.
84078bc019dSStefan Eßer 	if (places > n->scale)
84178bc019dSStefan Eßer 	{
84250696a6eSStefan Eßer 		n->scale = 0;
84350696a6eSStefan Eßer 		BC_NUM_RDX_SET(n, 0);
84450696a6eSStefan Eßer 	}
84578bc019dSStefan Eßer 	else
84678bc019dSStefan Eßer 	{
847252884aeSStefan Eßer 		n->scale -= places;
84850696a6eSStefan Eßer 		BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale));
849252884aeSStefan Eßer 	}
850252884aeSStefan Eßer 
85144d4804dSStefan Eßer 	// Finally, shift within limbs.
852252884aeSStefan Eßer 	if (shift) bc_num_shift(n, BC_BASE_DIGS - dig);
853252884aeSStefan Eßer 
854252884aeSStefan Eßer 	bc_num_clean(n);
855252884aeSStefan Eßer }
856252884aeSStefan Eßer 
85778bc019dSStefan Eßer void
85878bc019dSStefan Eßer bc_num_shiftRight(BcNum* restrict n, size_t places)
85978bc019dSStefan Eßer {
860252884aeSStefan Eßer 	BcBigDig dig;
861252884aeSStefan Eßer 	size_t places_rdx, scale, scale_mod, int_len, expand;
862252884aeSStefan Eßer 	bool shift;
863252884aeSStefan Eßer 
864252884aeSStefan Eßer 	if (!places) return;
86544d4804dSStefan Eßer 
86644d4804dSStefan Eßer 	// If zero, we can just set the scale and bail.
86778bc019dSStefan Eßer 	if (BC_NUM_ZERO(n))
86878bc019dSStefan Eßer 	{
869252884aeSStefan Eßer 		n->scale += places;
870252884aeSStefan Eßer 		bc_num_expand(n, BC_NUM_RDX(n->scale));
871252884aeSStefan Eßer 		return;
872252884aeSStefan Eßer 	}
873252884aeSStefan Eßer 
87444d4804dSStefan Eßer 	// Amount within a limb we have to shift by.
875252884aeSStefan Eßer 	dig = (BcBigDig) (places % BC_BASE_DIGS);
876252884aeSStefan Eßer 	shift = (dig != 0);
87744d4804dSStefan Eßer 
878252884aeSStefan Eßer 	scale = n->scale;
87944d4804dSStefan Eßer 
88044d4804dSStefan Eßer 	// Figure out how the scale is affected.
881252884aeSStefan Eßer 	scale_mod = scale % BC_BASE_DIGS;
882252884aeSStefan Eßer 	scale_mod = scale_mod ? scale_mod : BC_BASE_DIGS;
88344d4804dSStefan Eßer 
88444d4804dSStefan Eßer 	// We need to know the int length and rdx for places.
885252884aeSStefan Eßer 	int_len = bc_num_int(n);
886252884aeSStefan Eßer 	places_rdx = BC_NUM_RDX(places);
887252884aeSStefan Eßer 
88844d4804dSStefan Eßer 	// If we are going to shift past a limb boundary or not, set accordingly.
88978bc019dSStefan Eßer 	if (scale_mod + dig > BC_BASE_DIGS)
89078bc019dSStefan Eßer 	{
891252884aeSStefan Eßer 		expand = places_rdx - 1;
892252884aeSStefan Eßer 		places_rdx = 1;
893252884aeSStefan Eßer 	}
89478bc019dSStefan Eßer 	else
89578bc019dSStefan Eßer 	{
896252884aeSStefan Eßer 		expand = places_rdx;
897252884aeSStefan Eßer 		places_rdx = 0;
898252884aeSStefan Eßer 	}
899252884aeSStefan Eßer 
90044d4804dSStefan Eßer 	// Clamp expanding.
901252884aeSStefan Eßer 	if (expand > int_len) expand -= int_len;
902252884aeSStefan Eßer 	else expand = 0;
903252884aeSStefan Eßer 
90444d4804dSStefan Eßer 	// Extend, expand, and zero.
905252884aeSStefan Eßer 	bc_num_extend(n, places_rdx * BC_BASE_DIGS);
906252884aeSStefan Eßer 	bc_num_expand(n, bc_vm_growSize(expand, n->len));
90778bc019dSStefan Eßer 	// NOLINTNEXTLINE
908252884aeSStefan Eßer 	memset(n->num + n->len, 0, BC_NUM_SIZE(expand));
90944d4804dSStefan Eßer 
91044d4804dSStefan Eßer 	// Set the fields.
911252884aeSStefan Eßer 	n->len += expand;
91250696a6eSStefan Eßer 	n->scale = 0;
91350696a6eSStefan Eßer 	BC_NUM_RDX_SET(n, 0);
914252884aeSStefan Eßer 
91544d4804dSStefan Eßer 	// Finally, shift within limbs.
916252884aeSStefan Eßer 	if (shift) bc_num_shift(n, dig);
917252884aeSStefan Eßer 
918252884aeSStefan Eßer 	n->scale = scale + places;
91950696a6eSStefan Eßer 	BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale));
920252884aeSStefan Eßer 
921252884aeSStefan Eßer 	bc_num_clean(n);
922252884aeSStefan Eßer 
92350696a6eSStefan Eßer 	assert(BC_NUM_RDX_VAL(n) <= n->len && n->len <= n->cap);
92450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VAL(n) == BC_NUM_RDX(n->scale));
925252884aeSStefan Eßer }
926252884aeSStefan Eßer 
92744d4804dSStefan Eßer /**
92844d4804dSStefan Eßer  * Tests if a number is a integer with scale or not. Returns true if the number
92944d4804dSStefan Eßer  * is not an integer. If it is, its integer shifted form is copied into the
93044d4804dSStefan Eßer  * result parameter for use where only integers are allowed.
93144d4804dSStefan Eßer  * @param n  The integer to test and shift.
93244d4804dSStefan Eßer  * @param r  The number to store the shifted result into. This number should
93344d4804dSStefan Eßer  *           *not* be allocated.
93444d4804dSStefan Eßer  * @return   True if the number is a non-integer, false otherwise.
93544d4804dSStefan Eßer  */
93678bc019dSStefan Eßer static bool
93778bc019dSStefan Eßer bc_num_nonInt(const BcNum* restrict n, BcNum* restrict r)
93878bc019dSStefan Eßer {
93944d4804dSStefan Eßer 	bool zero;
94044d4804dSStefan Eßer 	size_t i, rdx = BC_NUM_RDX_VAL(n);
94144d4804dSStefan Eßer 
94278bc019dSStefan Eßer 	if (!rdx)
94378bc019dSStefan Eßer 	{
94478bc019dSStefan Eßer 		// NOLINTNEXTLINE
94544d4804dSStefan Eßer 		memcpy(r, n, sizeof(BcNum));
94644d4804dSStefan Eßer 		return false;
94744d4804dSStefan Eßer 	}
94844d4804dSStefan Eßer 
94944d4804dSStefan Eßer 	zero = true;
95044d4804dSStefan Eßer 
95178bc019dSStefan Eßer 	for (i = 0; zero && i < rdx; ++i)
95278bc019dSStefan Eßer 	{
95378bc019dSStefan Eßer 		zero = (n->num[i] == 0);
95478bc019dSStefan Eßer 	}
95544d4804dSStefan Eßer 
95644d4804dSStefan Eßer 	if (BC_ERR(!zero)) return true;
95744d4804dSStefan Eßer 
95844d4804dSStefan Eßer 	bc_num_shiftRdx(n, r);
95944d4804dSStefan Eßer 
96044d4804dSStefan Eßer 	return false;
961252884aeSStefan Eßer }
962252884aeSStefan Eßer 
963252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
96444d4804dSStefan Eßer 
96544d4804dSStefan Eßer /**
96644d4804dSStefan Eßer  * Execute common code for an operater that needs an integer for the second
96744d4804dSStefan Eßer  * operand and return the integer operand as a BcBigDig.
96844d4804dSStefan Eßer  * @param a  The first operand.
96944d4804dSStefan Eßer  * @param b  The second operand.
97044d4804dSStefan Eßer  * @param c  The result operand.
97144d4804dSStefan Eßer  * @return   The second operand as a hardware integer.
97244d4804dSStefan Eßer  */
97378bc019dSStefan Eßer static BcBigDig
97478bc019dSStefan Eßer bc_num_intop(const BcNum* a, const BcNum* b, BcNum* restrict c)
975252884aeSStefan Eßer {
97644d4804dSStefan Eßer 	BcNum temp;
97744d4804dSStefan Eßer 
978d101cdd6SStefan Eßer #if BC_GCC
979d101cdd6SStefan Eßer 	temp.len = 0;
980d101cdd6SStefan Eßer 	temp.rdx = 0;
981d101cdd6SStefan Eßer 	temp.num = NULL;
982d101cdd6SStefan Eßer #endif // BC_GCC
983d101cdd6SStefan Eßer 
98444d4804dSStefan Eßer 	if (BC_ERR(bc_num_nonInt(b, &temp))) bc_err(BC_ERR_MATH_NON_INTEGER);
98544d4804dSStefan Eßer 
986252884aeSStefan Eßer 	bc_num_copy(c, a);
98744d4804dSStefan Eßer 
98844d4804dSStefan Eßer 	return bc_num_bigdig(&temp);
989252884aeSStefan Eßer }
990252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
991252884aeSStefan Eßer 
99244d4804dSStefan Eßer /**
99344d4804dSStefan Eßer  * This is the actual implementation of add *and* subtract. Since this function
99444d4804dSStefan Eßer  * doesn't need to use scale (per the bc spec), I am hijacking it to say whether
99544d4804dSStefan Eßer  * it's doing an add or a subtract. And then I convert substraction to addition
99644d4804dSStefan Eßer  * of negative second operand. This is a BcNumBinOp function.
99744d4804dSStefan Eßer  * @param a    The first operand.
99844d4804dSStefan Eßer  * @param b    The second operand.
99944d4804dSStefan Eßer  * @param c    The return parameter.
100044d4804dSStefan Eßer  * @param sub  Non-zero for a subtract, zero for an add.
100144d4804dSStefan Eßer  */
100278bc019dSStefan Eßer static void
100378bc019dSStefan Eßer bc_num_as(BcNum* a, BcNum* b, BcNum* restrict c, size_t sub)
100478bc019dSStefan Eßer {
100578bc019dSStefan Eßer 	BcDig* ptr_c;
100678bc019dSStefan Eßer 	BcDig* ptr_l;
100778bc019dSStefan Eßer 	BcDig* ptr_r;
1008252884aeSStefan Eßer 	size_t i, min_rdx, max_rdx, diff, a_int, b_int, min_len, max_len, max_int;
100950696a6eSStefan Eßer 	size_t len_l, len_r, ardx, brdx;
101050696a6eSStefan Eßer 	bool b_neg, do_sub, do_rev_sub, carry, c_neg;
1011252884aeSStefan Eßer 
101278bc019dSStefan Eßer 	if (BC_NUM_ZERO(b))
101378bc019dSStefan Eßer 	{
1014252884aeSStefan Eßer 		bc_num_copy(c, a);
1015252884aeSStefan Eßer 		return;
1016252884aeSStefan Eßer 	}
101744d4804dSStefan Eßer 
101878bc019dSStefan Eßer 	if (BC_NUM_ZERO(a))
101978bc019dSStefan Eßer 	{
1020252884aeSStefan Eßer 		bc_num_copy(c, b);
102150696a6eSStefan Eßer 		c->rdx = BC_NUM_NEG_VAL(c, BC_NUM_NEG(b) != sub);
1022252884aeSStefan Eßer 		return;
1023252884aeSStefan Eßer 	}
1024252884aeSStefan Eßer 
1025252884aeSStefan Eßer 	// Invert sign of b if it is to be subtracted. This operation must
102644d4804dSStefan Eßer 	// precede the tests for any of the operands being zero.
102750696a6eSStefan Eßer 	b_neg = (BC_NUM_NEG(b) != sub);
1028252884aeSStefan Eßer 
102944d4804dSStefan Eßer 	// Figure out if we will actually add the numbers if their signs are equal
103044d4804dSStefan Eßer 	// or subtract.
103150696a6eSStefan Eßer 	do_sub = (BC_NUM_NEG(a) != b_neg);
1032252884aeSStefan Eßer 
1033252884aeSStefan Eßer 	a_int = bc_num_int(a);
1034252884aeSStefan Eßer 	b_int = bc_num_int(b);
1035252884aeSStefan Eßer 	max_int = BC_MAX(a_int, b_int);
1036252884aeSStefan Eßer 
103744d4804dSStefan Eßer 	// Figure out which number will have its last limbs copied (for addition) or
103844d4804dSStefan Eßer 	// subtracted (for subtraction).
103950696a6eSStefan Eßer 	ardx = BC_NUM_RDX_VAL(a);
104050696a6eSStefan Eßer 	brdx = BC_NUM_RDX_VAL(b);
104150696a6eSStefan Eßer 	min_rdx = BC_MIN(ardx, brdx);
104250696a6eSStefan Eßer 	max_rdx = BC_MAX(ardx, brdx);
1043252884aeSStefan Eßer 	diff = max_rdx - min_rdx;
1044252884aeSStefan Eßer 
1045252884aeSStefan Eßer 	max_len = max_int + max_rdx;
1046252884aeSStefan Eßer 
104778bc019dSStefan Eßer 	if (do_sub)
104878bc019dSStefan Eßer 	{
1049252884aeSStefan Eßer 		// Check whether b has to be subtracted from a or a from b.
1050252884aeSStefan Eßer 		if (a_int != b_int) do_rev_sub = (a_int < b_int);
105150696a6eSStefan Eßer 		else if (ardx > brdx)
105278bc019dSStefan Eßer 		{
1053252884aeSStefan Eßer 			do_rev_sub = (bc_num_compare(a->num + diff, b->num, b->len) < 0);
1054252884aeSStefan Eßer 		}
105578bc019dSStefan Eßer 		else do_rev_sub = (bc_num_compare(a->num, b->num + diff, a->len) <= 0);
105678bc019dSStefan Eßer 	}
105778bc019dSStefan Eßer 	else
105878bc019dSStefan Eßer 	{
1059252884aeSStefan Eßer 		// The result array of the addition might come out one element
1060252884aeSStefan Eßer 		// longer than the bigger of the operand arrays.
1061252884aeSStefan Eßer 		max_len += 1;
1062252884aeSStefan Eßer 		do_rev_sub = (a_int < b_int);
1063252884aeSStefan Eßer 	}
1064252884aeSStefan Eßer 
1065252884aeSStefan Eßer 	assert(max_len <= c->cap);
1066252884aeSStefan Eßer 
106744d4804dSStefan Eßer 	// Cache values for simple code later.
106878bc019dSStefan Eßer 	if (do_rev_sub)
106978bc019dSStefan Eßer 	{
1070252884aeSStefan Eßer 		ptr_l = b->num;
1071252884aeSStefan Eßer 		ptr_r = a->num;
1072252884aeSStefan Eßer 		len_l = b->len;
1073252884aeSStefan Eßer 		len_r = a->len;
1074252884aeSStefan Eßer 	}
107578bc019dSStefan Eßer 	else
107678bc019dSStefan Eßer 	{
1077252884aeSStefan Eßer 		ptr_l = a->num;
1078252884aeSStefan Eßer 		ptr_r = b->num;
1079252884aeSStefan Eßer 		len_l = a->len;
1080252884aeSStefan Eßer 		len_r = b->len;
1081252884aeSStefan Eßer 	}
1082252884aeSStefan Eßer 
1083252884aeSStefan Eßer 	ptr_c = c->num;
1084252884aeSStefan Eßer 	carry = false;
1085252884aeSStefan Eßer 
108644d4804dSStefan Eßer 	// This is true if the numbers have a different number of limbs after the
108744d4804dSStefan Eßer 	// decimal point.
108878bc019dSStefan Eßer 	if (diff)
108978bc019dSStefan Eßer 	{
1090252884aeSStefan Eßer 		// If the rdx values of the operands do not match, the result will
1091252884aeSStefan Eßer 		// have low end elements that are the positive or negative trailing
1092252884aeSStefan Eßer 		// elements of the operand with higher rdx value.
109378bc019dSStefan Eßer 		if ((ardx > brdx) != do_rev_sub)
109478bc019dSStefan Eßer 		{
109550696a6eSStefan Eßer 			// !do_rev_sub && ardx > brdx || do_rev_sub && brdx > ardx
1096252884aeSStefan Eßer 			// The left operand has BcDig values that need to be copied,
1097252884aeSStefan Eßer 			// either from a or from b (in case of a reversed subtraction).
109878bc019dSStefan Eßer 			// NOLINTNEXTLINE
1099252884aeSStefan Eßer 			memcpy(ptr_c, ptr_l, BC_NUM_SIZE(diff));
1100252884aeSStefan Eßer 			ptr_l += diff;
1101252884aeSStefan Eßer 			len_l -= diff;
1102252884aeSStefan Eßer 		}
110378bc019dSStefan Eßer 		else
110478bc019dSStefan Eßer 		{
1105252884aeSStefan Eßer 			// The right operand has BcDig values that need to be copied
1106252884aeSStefan Eßer 			// or subtracted from zero (in case of a subtraction).
110778bc019dSStefan Eßer 			if (do_sub)
110878bc019dSStefan Eßer 			{
110950696a6eSStefan Eßer 				// do_sub (do_rev_sub && ardx > brdx ||
111050696a6eSStefan Eßer 				// !do_rev_sub && brdx > ardx)
1111252884aeSStefan Eßer 				for (i = 0; i < diff; i++)
111278bc019dSStefan Eßer 				{
1113252884aeSStefan Eßer 					ptr_c[i] = bc_num_subDigits(0, ptr_r[i], &carry);
1114252884aeSStefan Eßer 				}
111578bc019dSStefan Eßer 			}
111678bc019dSStefan Eßer 			else
111778bc019dSStefan Eßer 			{
111850696a6eSStefan Eßer 				// !do_sub && brdx > ardx
111978bc019dSStefan Eßer 				// NOLINTNEXTLINE
1120252884aeSStefan Eßer 				memcpy(ptr_c, ptr_r, BC_NUM_SIZE(diff));
1121252884aeSStefan Eßer 			}
1122252884aeSStefan Eßer 
112344d4804dSStefan Eßer 			// Future code needs to ignore the limbs we just did.
1124252884aeSStefan Eßer 			ptr_r += diff;
1125252884aeSStefan Eßer 			len_r -= diff;
1126252884aeSStefan Eßer 		}
1127252884aeSStefan Eßer 
112844d4804dSStefan Eßer 		// The return value pointer needs to ignore what we just did.
1129252884aeSStefan Eßer 		ptr_c += diff;
1130252884aeSStefan Eßer 	}
1131252884aeSStefan Eßer 
113244d4804dSStefan Eßer 	// This is the length that can be directly added/subtracted.
1133252884aeSStefan Eßer 	min_len = BC_MIN(len_l, len_r);
1134252884aeSStefan Eßer 
1135252884aeSStefan Eßer 	// After dealing with possible low array elements that depend on only one
113644d4804dSStefan Eßer 	// operand above, the actual add or subtract can be performed as if the rdx
113744d4804dSStefan Eßer 	// of both operands was the same.
113844d4804dSStefan Eßer 	//
1139252884aeSStefan Eßer 	// Inlining takes care of eliminating constant zero arguments to
1140252884aeSStefan Eßer 	// addDigit/subDigit (checked in disassembly of resulting bc binary
1141252884aeSStefan Eßer 	// compiled with gcc and clang).
114278bc019dSStefan Eßer 	if (do_sub)
114378bc019dSStefan Eßer 	{
114444d4804dSStefan Eßer 		// Actual subtraction.
1145252884aeSStefan Eßer 		for (i = 0; i < min_len; ++i)
114678bc019dSStefan Eßer 		{
1147252884aeSStefan Eßer 			ptr_c[i] = bc_num_subDigits(ptr_l[i], ptr_r[i], &carry);
114878bc019dSStefan Eßer 		}
114944d4804dSStefan Eßer 
115044d4804dSStefan Eßer 		// Finishing the limbs beyond the direct subtraction.
115178bc019dSStefan Eßer 		for (; i < len_l; ++i)
115278bc019dSStefan Eßer 		{
115378bc019dSStefan Eßer 			ptr_c[i] = bc_num_subDigits(ptr_l[i], 0, &carry);
1154252884aeSStefan Eßer 		}
115578bc019dSStefan Eßer 	}
115678bc019dSStefan Eßer 	else
115778bc019dSStefan Eßer 	{
115844d4804dSStefan Eßer 		// Actual addition.
1159252884aeSStefan Eßer 		for (i = 0; i < min_len; ++i)
116078bc019dSStefan Eßer 		{
1161252884aeSStefan Eßer 			ptr_c[i] = bc_num_addDigits(ptr_l[i], ptr_r[i], &carry);
116278bc019dSStefan Eßer 		}
116344d4804dSStefan Eßer 
116444d4804dSStefan Eßer 		// Finishing the limbs beyond the direct addition.
116578bc019dSStefan Eßer 		for (; i < len_l; ++i)
116678bc019dSStefan Eßer 		{
116778bc019dSStefan Eßer 			ptr_c[i] = bc_num_addDigits(ptr_l[i], 0, &carry);
116878bc019dSStefan Eßer 		}
116944d4804dSStefan Eßer 
117044d4804dSStefan Eßer 		// Addition can create an extra limb. We take care of that here.
1171252884aeSStefan Eßer 		ptr_c[i] = bc_num_addDigits(0, 0, &carry);
1172252884aeSStefan Eßer 	}
1173252884aeSStefan Eßer 
1174252884aeSStefan Eßer 	assert(carry == false);
1175252884aeSStefan Eßer 
1176252884aeSStefan Eßer 	// The result has the same sign as a, unless the operation was a
1177252884aeSStefan Eßer 	// reverse subtraction (b - a).
117850696a6eSStefan Eßer 	c_neg = BC_NUM_NEG(a) != (do_sub && do_rev_sub);
117950696a6eSStefan Eßer 	BC_NUM_RDX_SET_NEG(c, max_rdx, c_neg);
1180252884aeSStefan Eßer 	c->len = max_len;
1181252884aeSStefan Eßer 	c->scale = BC_MAX(a->scale, b->scale);
1182252884aeSStefan Eßer 
1183252884aeSStefan Eßer 	bc_num_clean(c);
1184252884aeSStefan Eßer }
1185252884aeSStefan Eßer 
118644d4804dSStefan Eßer /**
118744d4804dSStefan Eßer  * The simple multiplication that karatsuba dishes out to when the length of the
118844d4804dSStefan Eßer  * numbers gets low enough. This doesn't use scale because it treats the
118944d4804dSStefan Eßer  * operands as though they are integers.
119044d4804dSStefan Eßer  * @param a  The first operand.
119144d4804dSStefan Eßer  * @param b  The second operand.
119244d4804dSStefan Eßer  * @param c  The return parameter.
119344d4804dSStefan Eßer  */
119478bc019dSStefan Eßer static void
119578bc019dSStefan Eßer bc_num_m_simp(const BcNum* a, const BcNum* b, BcNum* restrict c)
119678bc019dSStefan Eßer {
1197252884aeSStefan Eßer 	size_t i, alen = a->len, blen = b->len, clen;
119878bc019dSStefan Eßer 	BcDig* ptr_a = a->num;
119978bc019dSStefan Eßer 	BcDig* ptr_b = b->num;
120078bc019dSStefan Eßer 	BcDig* ptr_c;
1201252884aeSStefan Eßer 	BcBigDig sum = 0, carry = 0;
1202252884aeSStefan Eßer 
1203252884aeSStefan Eßer 	assert(sizeof(sum) >= sizeof(BcDig) * 2);
120450696a6eSStefan Eßer 	assert(!BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b));
1205252884aeSStefan Eßer 
120644d4804dSStefan Eßer 	// Make sure c is big enough.
1207252884aeSStefan Eßer 	clen = bc_vm_growSize(alen, blen);
1208252884aeSStefan Eßer 	bc_num_expand(c, bc_vm_growSize(clen, 1));
1209252884aeSStefan Eßer 
121044d4804dSStefan Eßer 	// If we don't memset, then we might have uninitialized data use later.
1211252884aeSStefan Eßer 	ptr_c = c->num;
121278bc019dSStefan Eßer 	// NOLINTNEXTLINE
1213252884aeSStefan Eßer 	memset(ptr_c, 0, BC_NUM_SIZE(c->cap));
1214252884aeSStefan Eßer 
121544d4804dSStefan Eßer 	// This is the actual multiplication loop. It uses the lattice form of long
121644d4804dSStefan Eßer 	// multiplication (see the explanation on the web page at
121744d4804dSStefan Eßer 	// https://knilt.arcc.albany.edu/What_is_Lattice_Multiplication or the
121844d4804dSStefan Eßer 	// explanation at Wikipedia).
121978bc019dSStefan Eßer 	for (i = 0; i < clen; ++i)
122078bc019dSStefan Eßer 	{
1221252884aeSStefan Eßer 		ssize_t sidx = (ssize_t) (i - blen + 1);
122244d4804dSStefan Eßer 		size_t j, k;
1223252884aeSStefan Eßer 
122444d4804dSStefan Eßer 		// These are the start indices.
122544d4804dSStefan Eßer 		j = (size_t) BC_MAX(0, sidx);
122644d4804dSStefan Eßer 		k = BC_MIN(i, blen - 1);
122744d4804dSStefan Eßer 
122844d4804dSStefan Eßer 		// On every iteration of this loop, a multiplication happens, then the
122944d4804dSStefan Eßer 		// sum is automatically calculated.
123078bc019dSStefan Eßer 		for (; j < alen && k < blen; ++j, --k)
123178bc019dSStefan Eßer 		{
1232252884aeSStefan Eßer 			sum += ((BcBigDig) ptr_a[j]) * ((BcBigDig) ptr_b[k]);
1233252884aeSStefan Eßer 
123478bc019dSStefan Eßer 			if (sum >= ((BcBigDig) BC_BASE_POW) * BC_BASE_POW)
123578bc019dSStefan Eßer 			{
1236252884aeSStefan Eßer 				carry += sum / BC_BASE_POW;
1237252884aeSStefan Eßer 				sum %= BC_BASE_POW;
1238252884aeSStefan Eßer 			}
1239252884aeSStefan Eßer 		}
1240252884aeSStefan Eßer 
124144d4804dSStefan Eßer 		// Calculate the carry.
124278bc019dSStefan Eßer 		if (sum >= BC_BASE_POW)
124378bc019dSStefan Eßer 		{
1244252884aeSStefan Eßer 			carry += sum / BC_BASE_POW;
1245252884aeSStefan Eßer 			sum %= BC_BASE_POW;
1246252884aeSStefan Eßer 		}
1247252884aeSStefan Eßer 
124844d4804dSStefan Eßer 		// Store and set up for next iteration.
1249252884aeSStefan Eßer 		ptr_c[i] = (BcDig) sum;
1250252884aeSStefan Eßer 		assert(ptr_c[i] < BC_BASE_POW);
1251252884aeSStefan Eßer 		sum = carry;
1252252884aeSStefan Eßer 		carry = 0;
1253252884aeSStefan Eßer 	}
1254252884aeSStefan Eßer 
1255252884aeSStefan Eßer 	// This should always be true because there should be no carry on the last
1256252884aeSStefan Eßer 	// digit; multiplication never goes above the sum of both lengths.
1257252884aeSStefan Eßer 	assert(!sum);
1258252884aeSStefan Eßer 
1259252884aeSStefan Eßer 	c->len = clen;
1260252884aeSStefan Eßer }
1261252884aeSStefan Eßer 
126244d4804dSStefan Eßer /**
126344d4804dSStefan Eßer  * Does a shifted add or subtract for Karatsuba below. This calls either
126444d4804dSStefan Eßer  * bc_num_addArrays() or bc_num_subArrays().
126544d4804dSStefan Eßer  * @param n      An in/out parameter; the first operand and return parameter.
126644d4804dSStefan Eßer  * @param a      The second operand.
126744d4804dSStefan Eßer  * @param shift  The amount to shift @a n by when adding/subtracting.
126844d4804dSStefan Eßer  * @param op     The function to call, either bc_num_addArrays() or
126944d4804dSStefan Eßer  *               bc_num_subArrays().
127044d4804dSStefan Eßer  */
127178bc019dSStefan Eßer static void
127278bc019dSStefan Eßer bc_num_shiftAddSub(BcNum* restrict n, const BcNum* restrict a, size_t shift,
127378bc019dSStefan Eßer                    BcNumShiftAddOp op)
1274252884aeSStefan Eßer {
1275252884aeSStefan Eßer 	assert(n->len >= shift + a->len);
127650696a6eSStefan Eßer 	assert(!BC_NUM_RDX_VAL(n) && !BC_NUM_RDX_VAL(a));
1277252884aeSStefan Eßer 	op(n->num + shift, a->num, a->len);
1278252884aeSStefan Eßer }
1279252884aeSStefan Eßer 
128044d4804dSStefan Eßer /**
128144d4804dSStefan Eßer  * Implements the Karatsuba algorithm.
128244d4804dSStefan Eßer  */
128378bc019dSStefan Eßer static void
128478bc019dSStefan Eßer bc_num_k(const BcNum* a, const BcNum* b, BcNum* restrict c)
128578bc019dSStefan Eßer {
1286252884aeSStefan Eßer 	size_t max, max2, total;
1287252884aeSStefan Eßer 	BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
128878bc019dSStefan Eßer 	BcDig* digs;
128978bc019dSStefan Eßer 	BcDig* dig_ptr;
1290252884aeSStefan Eßer 	BcNumShiftAddOp op;
1291252884aeSStefan Eßer 	bool aone = BC_NUM_ONE(a);
1292d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
1293d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
1294d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
1295252884aeSStefan Eßer 
1296252884aeSStefan Eßer 	assert(BC_NUM_ZERO(c));
1297252884aeSStefan Eßer 
1298252884aeSStefan Eßer 	if (BC_NUM_ZERO(a) || BC_NUM_ZERO(b)) return;
129944d4804dSStefan Eßer 
130078bc019dSStefan Eßer 	if (aone || BC_NUM_ONE(b))
130178bc019dSStefan Eßer 	{
1302252884aeSStefan Eßer 		bc_num_copy(c, aone ? b : a);
130350696a6eSStefan Eßer 		if ((aone && BC_NUM_NEG(a)) || BC_NUM_NEG(b)) BC_NUM_NEG_TGL(c);
1304252884aeSStefan Eßer 		return;
1305252884aeSStefan Eßer 	}
130644d4804dSStefan Eßer 
130744d4804dSStefan Eßer 	// Shell out to the simple algorithm with certain conditions.
130878bc019dSStefan Eßer 	if (a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
130978bc019dSStefan Eßer 	{
1310252884aeSStefan Eßer 		bc_num_m_simp(a, b, c);
1311252884aeSStefan Eßer 		return;
1312252884aeSStefan Eßer 	}
1313252884aeSStefan Eßer 
131444d4804dSStefan Eßer 	// We need to calculate the max size of the numbers that can result from the
131544d4804dSStefan Eßer 	// operations.
1316252884aeSStefan Eßer 	max = BC_MAX(a->len, b->len);
1317252884aeSStefan Eßer 	max = BC_MAX(max, BC_NUM_DEF_SIZE);
1318252884aeSStefan Eßer 	max2 = (max + 1) / 2;
1319252884aeSStefan Eßer 
132044d4804dSStefan Eßer 	// Calculate the space needed for all of the temporary allocations. We do
132144d4804dSStefan Eßer 	// this to just allocate once.
1322252884aeSStefan Eßer 	total = bc_vm_arraySize(BC_NUM_KARATSUBA_ALLOCS, max);
1323252884aeSStefan Eßer 
1324252884aeSStefan Eßer 	BC_SIG_LOCK;
1325252884aeSStefan Eßer 
132644d4804dSStefan Eßer 	// Allocate space for all of the temporaries.
1327252884aeSStefan Eßer 	digs = dig_ptr = bc_vm_malloc(BC_NUM_SIZE(total));
1328252884aeSStefan Eßer 
132944d4804dSStefan Eßer 	// Set up the temporaries.
1330252884aeSStefan Eßer 	bc_num_setup(&l1, dig_ptr, max);
1331252884aeSStefan Eßer 	dig_ptr += max;
1332252884aeSStefan Eßer 	bc_num_setup(&h1, dig_ptr, max);
1333252884aeSStefan Eßer 	dig_ptr += max;
1334252884aeSStefan Eßer 	bc_num_setup(&l2, dig_ptr, max);
1335252884aeSStefan Eßer 	dig_ptr += max;
1336252884aeSStefan Eßer 	bc_num_setup(&h2, dig_ptr, max);
1337252884aeSStefan Eßer 	dig_ptr += max;
1338252884aeSStefan Eßer 	bc_num_setup(&m1, dig_ptr, max);
1339252884aeSStefan Eßer 	dig_ptr += max;
1340252884aeSStefan Eßer 	bc_num_setup(&m2, dig_ptr, max);
134144d4804dSStefan Eßer 
134244d4804dSStefan Eßer 	// Some temporaries need the ability to grow, so we allocate them
134344d4804dSStefan Eßer 	// separately.
1344252884aeSStefan Eßer 	max = bc_vm_growSize(max, 1);
1345252884aeSStefan Eßer 	bc_num_init(&z0, max);
1346252884aeSStefan Eßer 	bc_num_init(&z1, max);
1347252884aeSStefan Eßer 	bc_num_init(&z2, max);
1348252884aeSStefan Eßer 	max = bc_vm_growSize(max, max) + 1;
1349252884aeSStefan Eßer 	bc_num_init(&temp, max);
1350252884aeSStefan Eßer 
1351d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
1352252884aeSStefan Eßer 
1353252884aeSStefan Eßer 	BC_SIG_UNLOCK;
1354252884aeSStefan Eßer 
135544d4804dSStefan Eßer 	// First, set up c.
1356252884aeSStefan Eßer 	bc_num_expand(c, max);
1357252884aeSStefan Eßer 	c->len = max;
135878bc019dSStefan Eßer 	// NOLINTNEXTLINE
1359252884aeSStefan Eßer 	memset(c->num, 0, BC_NUM_SIZE(c->len));
1360252884aeSStefan Eßer 
136144d4804dSStefan Eßer 	// Split the parameters.
136244d4804dSStefan Eßer 	bc_num_split(a, max2, &l1, &h1);
136344d4804dSStefan Eßer 	bc_num_split(b, max2, &l2, &h2);
136444d4804dSStefan Eßer 
136544d4804dSStefan Eßer 	// Do the subtraction.
1366252884aeSStefan Eßer 	bc_num_sub(&h1, &l1, &m1, 0);
1367252884aeSStefan Eßer 	bc_num_sub(&l2, &h2, &m2, 0);
1368252884aeSStefan Eßer 
136944d4804dSStefan Eßer 	// The if statements below are there for efficiency reasons. The best way to
137044d4804dSStefan Eßer 	// understand them is to understand the Karatsuba algorithm because now that
137144d4804dSStefan Eßer 	// the ollocations and splits are done, the algorithm is pretty
137244d4804dSStefan Eßer 	// straightforward.
137344d4804dSStefan Eßer 
137478bc019dSStefan Eßer 	if (BC_NUM_NONZERO(&h1) && BC_NUM_NONZERO(&h2))
137578bc019dSStefan Eßer 	{
137650696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(h1));
137750696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(h2));
137850696a6eSStefan Eßer 
1379252884aeSStefan Eßer 		bc_num_m(&h1, &h2, &z2, 0);
1380252884aeSStefan Eßer 		bc_num_clean(&z2);
1381252884aeSStefan Eßer 
1382252884aeSStefan Eßer 		bc_num_shiftAddSub(c, &z2, max2 * 2, bc_num_addArrays);
1383252884aeSStefan Eßer 		bc_num_shiftAddSub(c, &z2, max2, bc_num_addArrays);
1384252884aeSStefan Eßer 	}
1385252884aeSStefan Eßer 
138678bc019dSStefan Eßer 	if (BC_NUM_NONZERO(&l1) && BC_NUM_NONZERO(&l2))
138778bc019dSStefan Eßer 	{
138850696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(l1));
138950696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(l2));
139050696a6eSStefan Eßer 
1391252884aeSStefan Eßer 		bc_num_m(&l1, &l2, &z0, 0);
1392252884aeSStefan Eßer 		bc_num_clean(&z0);
1393252884aeSStefan Eßer 
1394252884aeSStefan Eßer 		bc_num_shiftAddSub(c, &z0, max2, bc_num_addArrays);
1395252884aeSStefan Eßer 		bc_num_shiftAddSub(c, &z0, 0, bc_num_addArrays);
1396252884aeSStefan Eßer 	}
1397252884aeSStefan Eßer 
139878bc019dSStefan Eßer 	if (BC_NUM_NONZERO(&m1) && BC_NUM_NONZERO(&m2))
139978bc019dSStefan Eßer 	{
140050696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(m1));
140150696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(m1));
140250696a6eSStefan Eßer 
1403252884aeSStefan Eßer 		bc_num_m(&m1, &m2, &z1, 0);
1404252884aeSStefan Eßer 		bc_num_clean(&z1);
1405252884aeSStefan Eßer 
140650696a6eSStefan Eßer 		op = (BC_NUM_NEG_NP(m1) != BC_NUM_NEG_NP(m2)) ?
140778bc019dSStefan Eßer 		         bc_num_subArrays :
140878bc019dSStefan Eßer 		         bc_num_addArrays;
1409252884aeSStefan Eßer 		bc_num_shiftAddSub(c, &z1, max2, op);
1410252884aeSStefan Eßer 	}
1411252884aeSStefan Eßer 
1412252884aeSStefan Eßer err:
1413252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
1414252884aeSStefan Eßer 	free(digs);
1415252884aeSStefan Eßer 	bc_num_free(&temp);
1416252884aeSStefan Eßer 	bc_num_free(&z2);
1417252884aeSStefan Eßer 	bc_num_free(&z1);
1418252884aeSStefan Eßer 	bc_num_free(&z0);
1419d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
1420252884aeSStefan Eßer }
1421252884aeSStefan Eßer 
142244d4804dSStefan Eßer /**
142344d4804dSStefan Eßer  * Does checks for Karatsuba. It also changes things to ensure that the
142444d4804dSStefan Eßer  * Karatsuba and simple multiplication can treat the numbers as integers. This
142544d4804dSStefan Eßer  * is a BcNumBinOp function.
142644d4804dSStefan Eßer  * @param a      The first operand.
142744d4804dSStefan Eßer  * @param b      The second operand.
142844d4804dSStefan Eßer  * @param c      The return parameter.
142944d4804dSStefan Eßer  * @param scale  The current scale.
143044d4804dSStefan Eßer  */
143178bc019dSStefan Eßer static void
143278bc019dSStefan Eßer bc_num_m(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
143378bc019dSStefan Eßer {
1434252884aeSStefan Eßer 	BcNum cpa, cpb;
1435d101cdd6SStefan Eßer 	size_t ascale, bscale, ardx, brdx, zero, len, rscale;
1436d101cdd6SStefan Eßer 	// These are meant to quiet warnings on GCC about longjmp() clobbering.
1437d101cdd6SStefan Eßer 	// The problem is real here.
1438d101cdd6SStefan Eßer 	size_t scale1, scale2, realscale;
1439d101cdd6SStefan Eßer 	// These are meant to quiet the GCC longjmp() clobbering, even though it
1440d101cdd6SStefan Eßer 	// does not apply here.
1441d101cdd6SStefan Eßer 	volatile size_t azero;
1442d101cdd6SStefan Eßer 	volatile size_t bzero;
1443d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
1444d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
1445d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
1446252884aeSStefan Eßer 
144750696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
144850696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
144950696a6eSStefan Eßer 
1450252884aeSStefan Eßer 	bc_num_zero(c);
145144d4804dSStefan Eßer 
1452252884aeSStefan Eßer 	ascale = a->scale;
1453252884aeSStefan Eßer 	bscale = b->scale;
145444d4804dSStefan Eßer 
145544d4804dSStefan Eßer 	// This sets the final scale according to the bc spec.
1456d101cdd6SStefan Eßer 	scale1 = BC_MAX(scale, ascale);
1457d101cdd6SStefan Eßer 	scale2 = BC_MAX(scale1, bscale);
1458252884aeSStefan Eßer 	rscale = ascale + bscale;
1459d101cdd6SStefan Eßer 	realscale = BC_MIN(rscale, scale2);
1460252884aeSStefan Eßer 
146144d4804dSStefan Eßer 	// If this condition is true, we can use bc_num_mulArray(), which would be
146244d4804dSStefan Eßer 	// much faster.
146378bc019dSStefan Eßer 	if ((a->len == 1 || b->len == 1) && !a->rdx && !b->rdx)
146478bc019dSStefan Eßer 	{
1465252884aeSStefan Eßer 		BcNum* operand;
1466252884aeSStefan Eßer 		BcBigDig dig;
1467252884aeSStefan Eßer 
146844d4804dSStefan Eßer 		// Set the correct operands.
146978bc019dSStefan Eßer 		if (a->len == 1)
147078bc019dSStefan Eßer 		{
1471252884aeSStefan Eßer 			dig = (BcBigDig) a->num[0];
1472252884aeSStefan Eßer 			operand = b;
1473252884aeSStefan Eßer 		}
147478bc019dSStefan Eßer 		else
147578bc019dSStefan Eßer 		{
1476252884aeSStefan Eßer 			dig = (BcBigDig) b->num[0];
1477252884aeSStefan Eßer 			operand = a;
1478252884aeSStefan Eßer 		}
1479252884aeSStefan Eßer 
1480252884aeSStefan Eßer 		bc_num_mulArray(operand, dig, c);
1481252884aeSStefan Eßer 
148244d4804dSStefan Eßer 		// Need to make sure the sign is correct.
148350696a6eSStefan Eßer 		if (BC_NUM_NONZERO(c))
148478bc019dSStefan Eßer 		{
148550696a6eSStefan Eßer 			c->rdx = BC_NUM_NEG_VAL(c, BC_NUM_NEG(a) != BC_NUM_NEG(b));
148678bc019dSStefan Eßer 		}
1487252884aeSStefan Eßer 
1488252884aeSStefan Eßer 		return;
1489252884aeSStefan Eßer 	}
1490252884aeSStefan Eßer 
149150696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
149250696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
149350696a6eSStefan Eßer 
1494252884aeSStefan Eßer 	BC_SIG_LOCK;
1495252884aeSStefan Eßer 
149644d4804dSStefan Eßer 	// We need copies because of all of the mutation needed to make Karatsuba
149744d4804dSStefan Eßer 	// think the numbers are integers.
149850696a6eSStefan Eßer 	bc_num_init(&cpa, a->len + BC_NUM_RDX_VAL(a));
149950696a6eSStefan Eßer 	bc_num_init(&cpb, b->len + BC_NUM_RDX_VAL(b));
1500252884aeSStefan Eßer 
1501d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, init_err);
1502252884aeSStefan Eßer 
1503252884aeSStefan Eßer 	BC_SIG_UNLOCK;
1504252884aeSStefan Eßer 
1505252884aeSStefan Eßer 	bc_num_copy(&cpa, a);
1506252884aeSStefan Eßer 	bc_num_copy(&cpb, b);
1507252884aeSStefan Eßer 
150850696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID_NP(cpa));
150950696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID_NP(cpb));
1510252884aeSStefan Eßer 
151150696a6eSStefan Eßer 	BC_NUM_NEG_CLR_NP(cpa);
151250696a6eSStefan Eßer 	BC_NUM_NEG_CLR_NP(cpb);
151350696a6eSStefan Eßer 
151450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID_NP(cpa));
151550696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID_NP(cpb));
151650696a6eSStefan Eßer 
151744d4804dSStefan Eßer 	// These are what makes them appear like integers.
151850696a6eSStefan Eßer 	ardx = BC_NUM_RDX_VAL_NP(cpa) * BC_BASE_DIGS;
1519252884aeSStefan Eßer 	bc_num_shiftLeft(&cpa, ardx);
1520252884aeSStefan Eßer 
152150696a6eSStefan Eßer 	brdx = BC_NUM_RDX_VAL_NP(cpb) * BC_BASE_DIGS;
1522252884aeSStefan Eßer 	bc_num_shiftLeft(&cpb, brdx);
1523252884aeSStefan Eßer 
1524252884aeSStefan Eßer 	// We need to reset the jump here because azero and bzero are used in the
1525252884aeSStefan Eßer 	// cleanup, and local variables are not guaranteed to be the same after a
1526252884aeSStefan Eßer 	// jump.
1527252884aeSStefan Eßer 	BC_SIG_LOCK;
1528252884aeSStefan Eßer 
1529d101cdd6SStefan Eßer 	BC_UNSETJMP(vm);
1530252884aeSStefan Eßer 
153144d4804dSStefan Eßer 	// We want to ignore zero limbs.
1532252884aeSStefan Eßer 	azero = bc_num_shiftZero(&cpa);
1533252884aeSStefan Eßer 	bzero = bc_num_shiftZero(&cpb);
1534252884aeSStefan Eßer 
1535d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
1536252884aeSStefan Eßer 
1537252884aeSStefan Eßer 	BC_SIG_UNLOCK;
1538252884aeSStefan Eßer 
1539252884aeSStefan Eßer 	bc_num_clean(&cpa);
1540252884aeSStefan Eßer 	bc_num_clean(&cpb);
1541252884aeSStefan Eßer 
1542252884aeSStefan Eßer 	bc_num_k(&cpa, &cpb, c);
1543252884aeSStefan Eßer 
154444d4804dSStefan Eßer 	// The return parameter needs to have its scale set. This is the start. It
154544d4804dSStefan Eßer 	// also needs to be shifted by the same amount as a and b have limbs after
154644d4804dSStefan Eßer 	// the decimal point.
1547252884aeSStefan Eßer 	zero = bc_vm_growSize(azero, bzero);
1548252884aeSStefan Eßer 	len = bc_vm_growSize(c->len, zero);
1549252884aeSStefan Eßer 
1550252884aeSStefan Eßer 	bc_num_expand(c, len);
155144d4804dSStefan Eßer 
155244d4804dSStefan Eßer 	// Shift c based on the limbs after the decimal point in a and b.
1553252884aeSStefan Eßer 	bc_num_shiftLeft(c, (len - c->len) * BC_BASE_DIGS);
1554252884aeSStefan Eßer 	bc_num_shiftRight(c, ardx + brdx);
1555252884aeSStefan Eßer 
1556d101cdd6SStefan Eßer 	bc_num_retireMul(c, realscale, BC_NUM_NEG(a), BC_NUM_NEG(b));
1557252884aeSStefan Eßer 
1558252884aeSStefan Eßer err:
1559252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
1560252884aeSStefan Eßer 	bc_num_unshiftZero(&cpb, bzero);
1561252884aeSStefan Eßer 	bc_num_unshiftZero(&cpa, azero);
1562d101cdd6SStefan Eßer init_err:
1563d101cdd6SStefan Eßer 	BC_SIG_MAYLOCK;
1564d101cdd6SStefan Eßer 	bc_num_free(&cpb);
1565252884aeSStefan Eßer 	bc_num_free(&cpa);
1566d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
1567252884aeSStefan Eßer }
1568252884aeSStefan Eßer 
156944d4804dSStefan Eßer /**
157044d4804dSStefan Eßer  * Returns true if the BcDig array has non-zero limbs, false otherwise.
157144d4804dSStefan Eßer  * @param a    The array to test.
157244d4804dSStefan Eßer  * @param len  The length of the array.
157344d4804dSStefan Eßer  * @return     True if @a has any non-zero limbs, false otherwise.
157444d4804dSStefan Eßer  */
157578bc019dSStefan Eßer static bool
157678bc019dSStefan Eßer bc_num_nonZeroDig(BcDig* restrict a, size_t len)
157778bc019dSStefan Eßer {
1578252884aeSStefan Eßer 	size_t i;
157978bc019dSStefan Eßer 
1580d101cdd6SStefan Eßer 	for (i = len - 1; i < len; --i)
158178bc019dSStefan Eßer 	{
1582d101cdd6SStefan Eßer 		if (a[i] != 0) return true;
158378bc019dSStefan Eßer 	}
158478bc019dSStefan Eßer 
1585d101cdd6SStefan Eßer 	return false;
1586252884aeSStefan Eßer }
1587252884aeSStefan Eßer 
158844d4804dSStefan Eßer /**
158944d4804dSStefan Eßer  * Compares a BcDig array against a BcNum. This is especially suited for
159044d4804dSStefan Eßer  * division. Returns >0 if @a a is greater than @a b, <0 if it is less, and =0
159144d4804dSStefan Eßer  * if they are equal.
159244d4804dSStefan Eßer  * @param a    The array.
159344d4804dSStefan Eßer  * @param b    The number.
159444d4804dSStefan Eßer  * @param len  The length to assume the arrays are. This is always less than the
159544d4804dSStefan Eßer  *             actual length because of how this is implemented.
159644d4804dSStefan Eßer  */
159778bc019dSStefan Eßer static ssize_t
159878bc019dSStefan Eßer bc_num_divCmp(const BcDig* a, const BcNum* b, size_t len)
159978bc019dSStefan Eßer {
1600252884aeSStefan Eßer 	ssize_t cmp;
1601252884aeSStefan Eßer 
1602252884aeSStefan Eßer 	if (b->len > len && a[len]) cmp = bc_num_compare(a, b->num, len + 1);
160378bc019dSStefan Eßer 	else if (b->len <= len)
160478bc019dSStefan Eßer 	{
1605252884aeSStefan Eßer 		if (a[len]) cmp = 1;
1606252884aeSStefan Eßer 		else cmp = bc_num_compare(a, b->num, len);
1607252884aeSStefan Eßer 	}
1608252884aeSStefan Eßer 	else cmp = -1;
1609252884aeSStefan Eßer 
1610252884aeSStefan Eßer 	return cmp;
1611252884aeSStefan Eßer }
1612252884aeSStefan Eßer 
161344d4804dSStefan Eßer /**
161444d4804dSStefan Eßer  * Extends the two operands of a division by BC_BASE_DIGS minus the number of
161544d4804dSStefan Eßer  * digits in the divisor estimate. In other words, it is shifting the numbers in
161644d4804dSStefan Eßer  * order to force the divisor estimate to fill the limb.
161744d4804dSStefan Eßer  * @param a        The first operand.
161844d4804dSStefan Eßer  * @param b        The second operand.
161944d4804dSStefan Eßer  * @param divisor  The divisor estimate.
162044d4804dSStefan Eßer  */
162178bc019dSStefan Eßer static void
162278bc019dSStefan Eßer bc_num_divExtend(BcNum* restrict a, BcNum* restrict b, BcBigDig divisor)
1623252884aeSStefan Eßer {
1624252884aeSStefan Eßer 	size_t pow;
1625252884aeSStefan Eßer 
1626252884aeSStefan Eßer 	assert(divisor < BC_BASE_POW);
1627252884aeSStefan Eßer 
1628252884aeSStefan Eßer 	pow = BC_BASE_DIGS - bc_num_log10((size_t) divisor);
1629252884aeSStefan Eßer 
1630252884aeSStefan Eßer 	bc_num_shiftLeft(a, pow);
1631252884aeSStefan Eßer 	bc_num_shiftLeft(b, pow);
1632252884aeSStefan Eßer }
1633252884aeSStefan Eßer 
163444d4804dSStefan Eßer /**
163544d4804dSStefan Eßer  * Actually does division. This is a rewrite of my original code by Stefan Esser
163644d4804dSStefan Eßer  * from FreeBSD.
163744d4804dSStefan Eßer  * @param a      The first operand.
163844d4804dSStefan Eßer  * @param b      The second operand.
163944d4804dSStefan Eßer  * @param c      The return parameter.
164044d4804dSStefan Eßer  * @param scale  The current scale.
164144d4804dSStefan Eßer  */
164278bc019dSStefan Eßer static void
164378bc019dSStefan Eßer bc_num_d_long(BcNum* restrict a, BcNum* restrict b, BcNum* restrict c,
164478bc019dSStefan Eßer               size_t scale)
1645252884aeSStefan Eßer {
1646252884aeSStefan Eßer 	BcBigDig divisor;
1647d101cdd6SStefan Eßer 	size_t i, rdx;
1648d101cdd6SStefan Eßer 	// This is volatile and len 2 and reallen exist to quiet the GCC warning
1649d101cdd6SStefan Eßer 	// about clobbering on longjmp(). This one is possible, I think.
1650d101cdd6SStefan Eßer 	volatile size_t len;
1651d101cdd6SStefan Eßer 	size_t len2, reallen;
1652d101cdd6SStefan Eßer 	// This is volatile and realend exists to quiet the GCC warning about
1653d101cdd6SStefan Eßer 	// clobbering on longjmp(). This one is possible, I think.
1654d101cdd6SStefan Eßer 	volatile size_t end;
1655d101cdd6SStefan Eßer 	size_t realend;
1656252884aeSStefan Eßer 	BcNum cpb;
1657d101cdd6SStefan Eßer 	// This is volatile and realnonzero exists to quiet the GCC warning about
1658d101cdd6SStefan Eßer 	// clobbering on longjmp(). This one is possible, I think.
1659d101cdd6SStefan Eßer 	volatile bool nonzero;
1660d101cdd6SStefan Eßer 	bool realnonzero;
1661d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
1662d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
1663d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
1664252884aeSStefan Eßer 
1665252884aeSStefan Eßer 	assert(b->len < a->len);
166644d4804dSStefan Eßer 
1667252884aeSStefan Eßer 	len = b->len;
1668252884aeSStefan Eßer 	end = a->len - len;
166944d4804dSStefan Eßer 
1670252884aeSStefan Eßer 	assert(len >= 1);
1671252884aeSStefan Eßer 
167244d4804dSStefan Eßer 	// This is a final time to make sure c is big enough and that its array is
167344d4804dSStefan Eßer 	// properly zeroed.
1674252884aeSStefan Eßer 	bc_num_expand(c, a->len);
167578bc019dSStefan Eßer 	// NOLINTNEXTLINE
1676252884aeSStefan Eßer 	memset(c->num, 0, c->cap * sizeof(BcDig));
1677252884aeSStefan Eßer 
167844d4804dSStefan Eßer 	// Setup.
167950696a6eSStefan Eßer 	BC_NUM_RDX_SET(c, BC_NUM_RDX_VAL(a));
1680252884aeSStefan Eßer 	c->scale = a->scale;
1681252884aeSStefan Eßer 	c->len = a->len;
1682252884aeSStefan Eßer 
168344d4804dSStefan Eßer 	// This is pulling the most significant limb of b in order to establish a
168444d4804dSStefan Eßer 	// good "estimate" for the actual divisor.
1685252884aeSStefan Eßer 	divisor = (BcBigDig) b->num[len - 1];
1686252884aeSStefan Eßer 
168744d4804dSStefan Eßer 	// The entire bit of code in this if statement is to tighten the estimate of
168844d4804dSStefan Eßer 	// the divisor. The condition asks if b has any other non-zero limbs.
168978bc019dSStefan Eßer 	if (len > 1 && bc_num_nonZeroDig(b->num, len - 1))
169078bc019dSStefan Eßer 	{
169144d4804dSStefan Eßer 		// This takes a little bit of understanding. The "10*BC_BASE_DIGS/6+1"
169244d4804dSStefan Eßer 		// results in either 16 for 64-bit 9-digit limbs or 7 for 32-bit 4-digit
169344d4804dSStefan Eßer 		// limbs. Then it shifts a 1 by that many, which in both cases, puts the
169444d4804dSStefan Eßer 		// result above *half* of the max value a limb can store. Basically,
169544d4804dSStefan Eßer 		// this quickly calculates if the divisor is greater than half the max
169644d4804dSStefan Eßer 		// of a limb.
1697252884aeSStefan Eßer 		nonzero = (divisor > 1 << ((10 * BC_BASE_DIGS) / 6 + 1));
1698252884aeSStefan Eßer 
169944d4804dSStefan Eßer 		// If the divisor is *not* greater than half the limb...
170078bc019dSStefan Eßer 		if (!nonzero)
170178bc019dSStefan Eßer 		{
170244d4804dSStefan Eßer 			// Extend the parameters by the number of missing digits in the
170344d4804dSStefan Eßer 			// divisor.
1704252884aeSStefan Eßer 			bc_num_divExtend(a, b, divisor);
1705252884aeSStefan Eßer 
170644d4804dSStefan Eßer 			// Check bc_num_d(). In there, we grow a again and again. We do it
170744d4804dSStefan Eßer 			// again here; we *always* want to be sure it is big enough.
1708d101cdd6SStefan Eßer 			len2 = BC_MAX(a->len, b->len);
1709d101cdd6SStefan Eßer 			bc_num_expand(a, len2 + 1);
1710252884aeSStefan Eßer 
171144d4804dSStefan Eßer 			// Make a have a zero most significant limb to match the len.
1712d101cdd6SStefan Eßer 			if (len2 + 1 > a->len) a->len = len2 + 1;
1713252884aeSStefan Eßer 
171444d4804dSStefan Eßer 			// Grab the new divisor estimate, new because the shift has made it
171544d4804dSStefan Eßer 			// different.
1716d101cdd6SStefan Eßer 			reallen = b->len;
1717d101cdd6SStefan Eßer 			realend = a->len - reallen;
1718d101cdd6SStefan Eßer 			divisor = (BcBigDig) b->num[reallen - 1];
1719252884aeSStefan Eßer 
1720d101cdd6SStefan Eßer 			realnonzero = bc_num_nonZeroDig(b->num, reallen - 1);
1721252884aeSStefan Eßer 		}
1722d101cdd6SStefan Eßer 		else
1723d101cdd6SStefan Eßer 		{
1724d101cdd6SStefan Eßer 			realend = end;
1725d101cdd6SStefan Eßer 			realnonzero = nonzero;
1726d101cdd6SStefan Eßer 		}
1727d101cdd6SStefan Eßer 	}
1728d101cdd6SStefan Eßer 	else
1729d101cdd6SStefan Eßer 	{
1730d101cdd6SStefan Eßer 		realend = end;
1731d101cdd6SStefan Eßer 		realnonzero = false;
1732252884aeSStefan Eßer 	}
1733252884aeSStefan Eßer 
173444d4804dSStefan Eßer 	// If b has other nonzero limbs, we want the divisor to be one higher, so
173544d4804dSStefan Eßer 	// that it is an upper bound.
1736d101cdd6SStefan Eßer 	divisor += realnonzero;
1737252884aeSStefan Eßer 
173844d4804dSStefan Eßer 	// Make sure c can fit the new length.
1739252884aeSStefan Eßer 	bc_num_expand(c, a->len);
174078bc019dSStefan Eßer 	// NOLINTNEXTLINE
1741252884aeSStefan Eßer 	memset(c->num, 0, BC_NUM_SIZE(c->cap));
1742252884aeSStefan Eßer 
1743252884aeSStefan Eßer 	assert(c->scale >= scale);
174450696a6eSStefan Eßer 	rdx = BC_NUM_RDX_VAL(c) - BC_NUM_RDX(scale);
1745252884aeSStefan Eßer 
1746252884aeSStefan Eßer 	BC_SIG_LOCK;
1747252884aeSStefan Eßer 
1748252884aeSStefan Eßer 	bc_num_init(&cpb, len + 1);
1749252884aeSStefan Eßer 
1750d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
1751252884aeSStefan Eßer 
1752252884aeSStefan Eßer 	BC_SIG_UNLOCK;
1753252884aeSStefan Eßer 
175444d4804dSStefan Eßer 	// This is the actual division loop.
1755d101cdd6SStefan Eßer 	for (i = realend - 1; i < realend && i >= rdx && BC_NUM_NONZERO(a); --i)
175678bc019dSStefan Eßer 	{
1757252884aeSStefan Eßer 		ssize_t cmp;
1758252884aeSStefan Eßer 		BcDig* n;
1759252884aeSStefan Eßer 		BcBigDig result;
1760252884aeSStefan Eßer 
1761252884aeSStefan Eßer 		n = a->num + i;
1762252884aeSStefan Eßer 		assert(n >= a->num);
1763252884aeSStefan Eßer 		result = 0;
1764252884aeSStefan Eßer 
1765252884aeSStefan Eßer 		cmp = bc_num_divCmp(n, b, len);
1766252884aeSStefan Eßer 
176744d4804dSStefan Eßer 		// This is true if n is greater than b, which means that division can
176844d4804dSStefan Eßer 		// proceed, so this inner loop is the part that implements one instance
176944d4804dSStefan Eßer 		// of the division.
177078bc019dSStefan Eßer 		while (cmp >= 0)
177178bc019dSStefan Eßer 		{
177244d4804dSStefan Eßer 			BcBigDig n1, dividend, quotient;
1773252884aeSStefan Eßer 
177444d4804dSStefan Eßer 			// These should be named obviously enough. Just imagine that it's a
177544d4804dSStefan Eßer 			// division of one limb. Because that's what it is.
1776252884aeSStefan Eßer 			n1 = (BcBigDig) n[len];
1777252884aeSStefan Eßer 			dividend = n1 * BC_BASE_POW + (BcBigDig) n[len - 1];
177844d4804dSStefan Eßer 			quotient = (dividend / divisor);
1779252884aeSStefan Eßer 
178044d4804dSStefan Eßer 			// If this is true, then we can just subtract. Remember: setting
178144d4804dSStefan Eßer 			// quotient to 1 is not bad because we already know that n is
178244d4804dSStefan Eßer 			// greater than b.
178378bc019dSStefan Eßer 			if (quotient <= 1)
178478bc019dSStefan Eßer 			{
178544d4804dSStefan Eßer 				quotient = 1;
1786252884aeSStefan Eßer 				bc_num_subArrays(n, b->num, len);
1787252884aeSStefan Eßer 			}
178878bc019dSStefan Eßer 			else
178978bc019dSStefan Eßer 			{
179044d4804dSStefan Eßer 				assert(quotient <= BC_BASE_POW);
1791252884aeSStefan Eßer 
179244d4804dSStefan Eßer 				// We need to multiply and subtract for a quotient above 1.
179344d4804dSStefan Eßer 				bc_num_mulArray(b, (BcBigDig) quotient, &cpb);
1794252884aeSStefan Eßer 				bc_num_subArrays(n, cpb.num, cpb.len);
1795252884aeSStefan Eßer 			}
1796252884aeSStefan Eßer 
179744d4804dSStefan Eßer 			// The result is the *real* quotient, by the way, but it might take
179844d4804dSStefan Eßer 			// multiple trips around this loop to get it.
179944d4804dSStefan Eßer 			result += quotient;
1800252884aeSStefan Eßer 			assert(result <= BC_BASE_POW);
1801252884aeSStefan Eßer 
180244d4804dSStefan Eßer 			// And here's why it might take multiple trips: n might *still* be
180344d4804dSStefan Eßer 			// greater than b. So we have to loop again. That's what this is
180444d4804dSStefan Eßer 			// setting up for: the condition of the while loop.
1805d101cdd6SStefan Eßer 			if (realnonzero) cmp = bc_num_divCmp(n, b, len);
1806252884aeSStefan Eßer 			else cmp = -1;
1807252884aeSStefan Eßer 		}
1808252884aeSStefan Eßer 
1809252884aeSStefan Eßer 		assert(result < BC_BASE_POW);
1810252884aeSStefan Eßer 
181144d4804dSStefan Eßer 		// Store the actual limb quotient.
1812252884aeSStefan Eßer 		c->num[i] = (BcDig) result;
1813252884aeSStefan Eßer 	}
1814252884aeSStefan Eßer 
1815252884aeSStefan Eßer err:
1816252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
1817252884aeSStefan Eßer 	bc_num_free(&cpb);
1818d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
1819252884aeSStefan Eßer }
1820252884aeSStefan Eßer 
182144d4804dSStefan Eßer /**
182244d4804dSStefan Eßer  * Implements division. This is a BcNumBinOp function.
182344d4804dSStefan Eßer  * @param a      The first operand.
182444d4804dSStefan Eßer  * @param b      The second operand.
182544d4804dSStefan Eßer  * @param c      The return parameter.
182644d4804dSStefan Eßer  * @param scale  The current scale.
182744d4804dSStefan Eßer  */
182878bc019dSStefan Eßer static void
182978bc019dSStefan Eßer bc_num_d(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
183078bc019dSStefan Eßer {
183150696a6eSStefan Eßer 	size_t len, cpardx;
1832252884aeSStefan Eßer 	BcNum cpa, cpb;
1833d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
1834d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
1835d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
1836252884aeSStefan Eßer 
183744d4804dSStefan Eßer 	if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO);
183844d4804dSStefan Eßer 
183978bc019dSStefan Eßer 	if (BC_NUM_ZERO(a))
184078bc019dSStefan Eßer 	{
1841252884aeSStefan Eßer 		bc_num_setToZero(c, scale);
1842252884aeSStefan Eßer 		return;
1843252884aeSStefan Eßer 	}
184444d4804dSStefan Eßer 
184578bc019dSStefan Eßer 	if (BC_NUM_ONE(b))
184678bc019dSStefan Eßer 	{
1847252884aeSStefan Eßer 		bc_num_copy(c, a);
184850696a6eSStefan Eßer 		bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b));
1849252884aeSStefan Eßer 		return;
1850252884aeSStefan Eßer 	}
185144d4804dSStefan Eßer 
185244d4804dSStefan Eßer 	// If this is true, we can use bc_num_divArray(), which would be faster.
185378bc019dSStefan Eßer 	if (!BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b) && b->len == 1 && !scale)
185478bc019dSStefan Eßer 	{
1855252884aeSStefan Eßer 		BcBigDig rem;
1856252884aeSStefan Eßer 		bc_num_divArray(a, (BcBigDig) b->num[0], c, &rem);
185750696a6eSStefan Eßer 		bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b));
1858252884aeSStefan Eßer 		return;
1859252884aeSStefan Eßer 	}
1860252884aeSStefan Eßer 
186150696a6eSStefan Eßer 	len = bc_num_divReq(a, b, scale);
1862252884aeSStefan Eßer 
1863252884aeSStefan Eßer 	BC_SIG_LOCK;
1864252884aeSStefan Eßer 
186544d4804dSStefan Eßer 	// Initialize copies of the parameters. We want the length of the first
186644d4804dSStefan Eßer 	// operand copy to be as big as the result because of the way the division
186744d4804dSStefan Eßer 	// is implemented.
1868252884aeSStefan Eßer 	bc_num_init(&cpa, len);
1869252884aeSStefan Eßer 	bc_num_copy(&cpa, a);
1870252884aeSStefan Eßer 	bc_num_createCopy(&cpb, b);
1871252884aeSStefan Eßer 
1872d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
1873252884aeSStefan Eßer 
1874252884aeSStefan Eßer 	BC_SIG_UNLOCK;
1875252884aeSStefan Eßer 
1876252884aeSStefan Eßer 	len = b->len;
1877252884aeSStefan Eßer 
187844d4804dSStefan Eßer 	// Like the above comment, we want the copy of the first parameter to be
187944d4804dSStefan Eßer 	// larger than the second parameter.
188078bc019dSStefan Eßer 	if (len > cpa.len)
188178bc019dSStefan Eßer 	{
1882252884aeSStefan Eßer 		bc_num_expand(&cpa, bc_vm_growSize(len, 2));
1883252884aeSStefan Eßer 		bc_num_extend(&cpa, (len - cpa.len) * BC_BASE_DIGS);
1884252884aeSStefan Eßer 	}
1885252884aeSStefan Eßer 
188650696a6eSStefan Eßer 	cpardx = BC_NUM_RDX_VAL_NP(cpa);
188750696a6eSStefan Eßer 	cpa.scale = cpardx * BC_BASE_DIGS;
1888252884aeSStefan Eßer 
188944d4804dSStefan Eßer 	// This is just setting up the scale in preparation for the division.
1890252884aeSStefan Eßer 	bc_num_extend(&cpa, b->scale);
189150696a6eSStefan Eßer 	cpardx = BC_NUM_RDX_VAL_NP(cpa) - BC_NUM_RDX(b->scale);
189250696a6eSStefan Eßer 	BC_NUM_RDX_SET_NP(cpa, cpardx);
189350696a6eSStefan Eßer 	cpa.scale = cpardx * BC_BASE_DIGS;
1894252884aeSStefan Eßer 
189544d4804dSStefan Eßer 	// Once again, just setting things up, this time to match scale.
189678bc019dSStefan Eßer 	if (scale > cpa.scale)
189778bc019dSStefan Eßer 	{
1898252884aeSStefan Eßer 		bc_num_extend(&cpa, scale);
189950696a6eSStefan Eßer 		cpardx = BC_NUM_RDX_VAL_NP(cpa);
190050696a6eSStefan Eßer 		cpa.scale = cpardx * BC_BASE_DIGS;
1901252884aeSStefan Eßer 	}
1902252884aeSStefan Eßer 
190344d4804dSStefan Eßer 	// Grow if necessary.
1904252884aeSStefan Eßer 	if (cpa.cap == cpa.len) bc_num_expand(&cpa, bc_vm_growSize(cpa.len, 1));
1905252884aeSStefan Eßer 
1906252884aeSStefan Eßer 	// We want an extra zero in front to make things simpler.
1907252884aeSStefan Eßer 	cpa.num[cpa.len++] = 0;
1908252884aeSStefan Eßer 
190944d4804dSStefan Eßer 	// Still setting things up. Why all of these things are needed is not
191044d4804dSStefan Eßer 	// something that can be easily explained, but it has to do with making the
191144d4804dSStefan Eßer 	// actual algorithm easier to understand because it can assume a lot of
191244d4804dSStefan Eßer 	// things. Thus, you should view all of this setup code as establishing
191344d4804dSStefan Eßer 	// assumptions for bc_num_d_long(), where the actual division happens.
191444d4804dSStefan Eßer 	if (cpardx == cpa.len) cpa.len = bc_num_nonZeroLen(&cpa);
191544d4804dSStefan Eßer 	if (BC_NUM_RDX_VAL_NP(cpb) == cpb.len) cpb.len = bc_num_nonZeroLen(&cpb);
191650696a6eSStefan Eßer 	cpb.scale = 0;
191750696a6eSStefan Eßer 	BC_NUM_RDX_SET_NP(cpb, 0);
1918252884aeSStefan Eßer 
1919252884aeSStefan Eßer 	bc_num_d_long(&cpa, &cpb, c, scale);
1920252884aeSStefan Eßer 
192150696a6eSStefan Eßer 	bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b));
1922252884aeSStefan Eßer 
1923252884aeSStefan Eßer err:
1924252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
1925252884aeSStefan Eßer 	bc_num_free(&cpb);
1926252884aeSStefan Eßer 	bc_num_free(&cpa);
1927d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
1928252884aeSStefan Eßer }
1929252884aeSStefan Eßer 
193044d4804dSStefan Eßer /**
193144d4804dSStefan Eßer  * Implements divmod. This is the actual modulus function; since modulus
193244d4804dSStefan Eßer  * requires a division anyway, this returns the quotient and modulus. Either can
193344d4804dSStefan Eßer  * be thrown out as desired.
193444d4804dSStefan Eßer  * @param a      The first operand.
193544d4804dSStefan Eßer  * @param b      The second operand.
193644d4804dSStefan Eßer  * @param c      The return parameter for the quotient.
193744d4804dSStefan Eßer  * @param d      The return parameter for the modulus.
193844d4804dSStefan Eßer  * @param scale  The current scale.
193944d4804dSStefan Eßer  * @param ts     The scale that the operation should be done to. Yes, it's not
194044d4804dSStefan Eßer  *               necessarily the same as scale, per the bc spec.
194144d4804dSStefan Eßer  */
194278bc019dSStefan Eßer static void
194378bc019dSStefan Eßer bc_num_r(BcNum* a, BcNum* b, BcNum* restrict c, BcNum* restrict d, size_t scale,
194478bc019dSStefan Eßer          size_t ts)
1945252884aeSStefan Eßer {
1946252884aeSStefan Eßer 	BcNum temp;
1947d101cdd6SStefan Eßer 	// realscale is meant to quiet a warning on GCC about longjmp() clobbering.
1948d101cdd6SStefan Eßer 	// This one is real.
1949d101cdd6SStefan Eßer 	size_t realscale;
1950252884aeSStefan Eßer 	bool neg;
1951d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
1952d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
1953d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
1954252884aeSStefan Eßer 
195544d4804dSStefan Eßer 	if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO);
195644d4804dSStefan Eßer 
195778bc019dSStefan Eßer 	if (BC_NUM_ZERO(a))
195878bc019dSStefan Eßer 	{
1959252884aeSStefan Eßer 		bc_num_setToZero(c, ts);
1960252884aeSStefan Eßer 		bc_num_setToZero(d, ts);
1961252884aeSStefan Eßer 		return;
1962252884aeSStefan Eßer 	}
1963252884aeSStefan Eßer 
1964252884aeSStefan Eßer 	BC_SIG_LOCK;
1965252884aeSStefan Eßer 
1966252884aeSStefan Eßer 	bc_num_init(&temp, d->cap);
1967252884aeSStefan Eßer 
1968d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
1969252884aeSStefan Eßer 
1970252884aeSStefan Eßer 	BC_SIG_UNLOCK;
1971252884aeSStefan Eßer 
197244d4804dSStefan Eßer 	// Division.
1973252884aeSStefan Eßer 	bc_num_d(a, b, c, scale);
1974252884aeSStefan Eßer 
197544d4804dSStefan Eßer 	// We want an extra digit so we can safely truncate.
1976d101cdd6SStefan Eßer 	if (scale) realscale = ts + 1;
1977d101cdd6SStefan Eßer 	else realscale = scale;
1978252884aeSStefan Eßer 
197950696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(c));
198050696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
198150696a6eSStefan Eßer 
198244d4804dSStefan Eßer 	// Implement the rest of the (a - (a / b) * b) formula.
1983d101cdd6SStefan Eßer 	bc_num_m(c, b, &temp, realscale);
1984d101cdd6SStefan Eßer 	bc_num_sub(a, &temp, d, realscale);
1985252884aeSStefan Eßer 
198644d4804dSStefan Eßer 	// Extend if necessary.
1987252884aeSStefan Eßer 	if (ts > d->scale && BC_NUM_NONZERO(d)) bc_num_extend(d, ts - d->scale);
1988252884aeSStefan Eßer 
198950696a6eSStefan Eßer 	neg = BC_NUM_NEG(d);
199050696a6eSStefan Eßer 	bc_num_retireMul(d, ts, BC_NUM_NEG(a), BC_NUM_NEG(b));
199150696a6eSStefan Eßer 	d->rdx = BC_NUM_NEG_VAL(d, BC_NUM_NONZERO(d) ? neg : false);
1992252884aeSStefan Eßer 
1993252884aeSStefan Eßer err:
1994252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
1995252884aeSStefan Eßer 	bc_num_free(&temp);
1996d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
1997252884aeSStefan Eßer }
1998252884aeSStefan Eßer 
199944d4804dSStefan Eßer /**
200044d4804dSStefan Eßer  * Implements modulus/remainder. (Yes, I know they are different, but not in the
200144d4804dSStefan Eßer  * context of bc.) This is a BcNumBinOp function.
200244d4804dSStefan Eßer  * @param a      The first operand.
200344d4804dSStefan Eßer  * @param b      The second operand.
200444d4804dSStefan Eßer  * @param c      The return parameter.
200544d4804dSStefan Eßer  * @param scale  The current scale.
200644d4804dSStefan Eßer  */
200778bc019dSStefan Eßer static void
200878bc019dSStefan Eßer bc_num_rem(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
200978bc019dSStefan Eßer {
2010252884aeSStefan Eßer 	BcNum c1;
2011252884aeSStefan Eßer 	size_t ts;
2012d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2013d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
2014d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2015252884aeSStefan Eßer 
2016252884aeSStefan Eßer 	ts = bc_vm_growSize(scale, b->scale);
2017252884aeSStefan Eßer 	ts = BC_MAX(ts, a->scale);
2018252884aeSStefan Eßer 
2019252884aeSStefan Eßer 	BC_SIG_LOCK;
2020252884aeSStefan Eßer 
202144d4804dSStefan Eßer 	// Need a temp for the quotient.
2022252884aeSStefan Eßer 	bc_num_init(&c1, bc_num_mulReq(a, b, ts));
2023252884aeSStefan Eßer 
2024d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
2025252884aeSStefan Eßer 
2026252884aeSStefan Eßer 	BC_SIG_UNLOCK;
2027252884aeSStefan Eßer 
2028252884aeSStefan Eßer 	bc_num_r(a, b, &c1, c, scale, ts);
2029252884aeSStefan Eßer 
2030252884aeSStefan Eßer err:
2031252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
2032252884aeSStefan Eßer 	bc_num_free(&c1);
2033d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
2034252884aeSStefan Eßer }
2035252884aeSStefan Eßer 
203644d4804dSStefan Eßer /**
203744d4804dSStefan Eßer  * Implements power (exponentiation). This is a BcNumBinOp function.
203844d4804dSStefan Eßer  * @param a      The first operand.
203944d4804dSStefan Eßer  * @param b      The second operand.
204044d4804dSStefan Eßer  * @param c      The return parameter.
204144d4804dSStefan Eßer  * @param scale  The current scale.
204244d4804dSStefan Eßer  */
204378bc019dSStefan Eßer static void
204478bc019dSStefan Eßer bc_num_p(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
204578bc019dSStefan Eßer {
204644d4804dSStefan Eßer 	BcNum copy, btemp;
204744d4804dSStefan Eßer 	BcBigDig exp;
2048d101cdd6SStefan Eßer 	// realscale is meant to quiet a warning on GCC about longjmp() clobbering.
2049d101cdd6SStefan Eßer 	// This one is real.
2050d101cdd6SStefan Eßer 	size_t powrdx, resrdx, realscale;
205144d4804dSStefan Eßer 	bool neg;
2052d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2053d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
2054d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2055d101cdd6SStefan Eßer 
2056d101cdd6SStefan Eßer 	// This is here to silence a warning from GCC.
2057d101cdd6SStefan Eßer #if BC_GCC
2058d101cdd6SStefan Eßer 	btemp.len = 0;
2059d101cdd6SStefan Eßer 	btemp.rdx = 0;
2060d101cdd6SStefan Eßer 	btemp.num = NULL;
2061d101cdd6SStefan Eßer #endif // BC_GCC
2062252884aeSStefan Eßer 
206344d4804dSStefan Eßer 	if (BC_ERR(bc_num_nonInt(b, &btemp))) bc_err(BC_ERR_MATH_NON_INTEGER);
2064252884aeSStefan Eßer 
2065d101cdd6SStefan Eßer 	assert(btemp.len == 0 || btemp.num != NULL);
2066d101cdd6SStefan Eßer 
206778bc019dSStefan Eßer 	if (BC_NUM_ZERO(&btemp))
206878bc019dSStefan Eßer 	{
2069252884aeSStefan Eßer 		bc_num_one(c);
2070252884aeSStefan Eßer 		return;
2071252884aeSStefan Eßer 	}
207244d4804dSStefan Eßer 
207378bc019dSStefan Eßer 	if (BC_NUM_ZERO(a))
207478bc019dSStefan Eßer 	{
207544d4804dSStefan Eßer 		if (BC_NUM_NEG_NP(btemp)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO);
2076252884aeSStefan Eßer 		bc_num_setToZero(c, scale);
2077252884aeSStefan Eßer 		return;
2078252884aeSStefan Eßer 	}
207944d4804dSStefan Eßer 
208078bc019dSStefan Eßer 	if (BC_NUM_ONE(&btemp))
208178bc019dSStefan Eßer 	{
208244d4804dSStefan Eßer 		if (!BC_NUM_NEG_NP(btemp)) bc_num_copy(c, a);
2083252884aeSStefan Eßer 		else bc_num_inv(a, c, scale);
2084252884aeSStefan Eßer 		return;
2085252884aeSStefan Eßer 	}
2086252884aeSStefan Eßer 
208744d4804dSStefan Eßer 	neg = BC_NUM_NEG_NP(btemp);
208844d4804dSStefan Eßer 	BC_NUM_NEG_CLR_NP(btemp);
2089252884aeSStefan Eßer 
209044d4804dSStefan Eßer 	exp = bc_num_bigdig(&btemp);
209144d4804dSStefan Eßer 
209244d4804dSStefan Eßer 	BC_SIG_LOCK;
2093252884aeSStefan Eßer 
2094252884aeSStefan Eßer 	bc_num_createCopy(&copy, a);
2095252884aeSStefan Eßer 
2096d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
2097252884aeSStefan Eßer 
2098252884aeSStefan Eßer 	BC_SIG_UNLOCK;
2099252884aeSStefan Eßer 
210044d4804dSStefan Eßer 	// If this is true, then we do not have to do a division, and we need to
210144d4804dSStefan Eßer 	// set scale accordingly.
210278bc019dSStefan Eßer 	if (!neg)
210378bc019dSStefan Eßer 	{
210444d4804dSStefan Eßer 		size_t max = BC_MAX(scale, a->scale), scalepow;
210544d4804dSStefan Eßer 		scalepow = bc_num_mulOverflow(a->scale, exp);
2106d101cdd6SStefan Eßer 		realscale = BC_MIN(scalepow, max);
2107252884aeSStefan Eßer 	}
2108d101cdd6SStefan Eßer 	else realscale = scale;
2109252884aeSStefan Eßer 
211044d4804dSStefan Eßer 	// This is only implementing the first exponentiation by squaring, until it
211144d4804dSStefan Eßer 	// reaches the first time where the square is actually used.
211278bc019dSStefan Eßer 	for (powrdx = a->scale; !(exp & 1); exp >>= 1)
211378bc019dSStefan Eßer 	{
2114252884aeSStefan Eßer 		powrdx <<= 1;
211550696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(copy));
2116252884aeSStefan Eßer 		bc_num_mul(&copy, &copy, &copy, powrdx);
2117252884aeSStefan Eßer 	}
2118252884aeSStefan Eßer 
211944d4804dSStefan Eßer 	// Make c a copy of copy for the purpose of saving the squares that should
212044d4804dSStefan Eßer 	// be saved.
2121252884aeSStefan Eßer 	bc_num_copy(c, &copy);
2122252884aeSStefan Eßer 	resrdx = powrdx;
2123252884aeSStefan Eßer 
212444d4804dSStefan Eßer 	// Now finish the exponentiation by squaring, this time saving the squares
212544d4804dSStefan Eßer 	// as necessary.
212678bc019dSStefan Eßer 	while (exp >>= 1)
212778bc019dSStefan Eßer 	{
2128252884aeSStefan Eßer 		powrdx <<= 1;
212950696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(copy));
2130252884aeSStefan Eßer 		bc_num_mul(&copy, &copy, &copy, powrdx);
2131252884aeSStefan Eßer 
213244d4804dSStefan Eßer 		// If this is true, we want to save that particular square. This does
213344d4804dSStefan Eßer 		// that by multiplying c with copy.
213478bc019dSStefan Eßer 		if (exp & 1)
213578bc019dSStefan Eßer 		{
2136252884aeSStefan Eßer 			resrdx += powrdx;
213750696a6eSStefan Eßer 			assert(BC_NUM_RDX_VALID(c));
213850696a6eSStefan Eßer 			assert(BC_NUM_RDX_VALID_NP(copy));
2139252884aeSStefan Eßer 			bc_num_mul(c, &copy, c, resrdx);
2140252884aeSStefan Eßer 		}
2141252884aeSStefan Eßer 	}
2142252884aeSStefan Eßer 
214344d4804dSStefan Eßer 	// Invert if necessary.
2144d101cdd6SStefan Eßer 	if (neg) bc_num_inv(c, c, realscale);
2145252884aeSStefan Eßer 
214644d4804dSStefan Eßer 	// Truncate if necessary.
2147d101cdd6SStefan Eßer 	if (c->scale > realscale) bc_num_truncate(c, c->scale - realscale);
2148252884aeSStefan Eßer 
214944d4804dSStefan Eßer 	bc_num_clean(c);
2150252884aeSStefan Eßer 
2151252884aeSStefan Eßer err:
2152252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
2153252884aeSStefan Eßer 	bc_num_free(&copy);
2154d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
2155252884aeSStefan Eßer }
2156252884aeSStefan Eßer 
2157252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
215844d4804dSStefan Eßer /**
215944d4804dSStefan Eßer  * Implements the places operator. This is a BcNumBinOp function.
216044d4804dSStefan Eßer  * @param a      The first operand.
216144d4804dSStefan Eßer  * @param b      The second operand.
216244d4804dSStefan Eßer  * @param c      The return parameter.
216344d4804dSStefan Eßer  * @param scale  The current scale.
216444d4804dSStefan Eßer  */
216578bc019dSStefan Eßer static void
216678bc019dSStefan Eßer bc_num_place(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
216778bc019dSStefan Eßer {
216844d4804dSStefan Eßer 	BcBigDig val;
2169252884aeSStefan Eßer 
2170252884aeSStefan Eßer 	BC_UNUSED(scale);
2171252884aeSStefan Eßer 
217244d4804dSStefan Eßer 	val = bc_num_intop(a, b, c);
2173252884aeSStefan Eßer 
217444d4804dSStefan Eßer 	// Just truncate or extend as appropriate.
2175252884aeSStefan Eßer 	if (val < c->scale) bc_num_truncate(c, c->scale - val);
2176252884aeSStefan Eßer 	else if (val > c->scale) bc_num_extend(c, val - c->scale);
2177252884aeSStefan Eßer }
2178252884aeSStefan Eßer 
217944d4804dSStefan Eßer /**
218044d4804dSStefan Eßer  * Implements the left shift operator. This is a BcNumBinOp function.
218144d4804dSStefan Eßer  */
218278bc019dSStefan Eßer static void
218378bc019dSStefan Eßer bc_num_left(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
218478bc019dSStefan Eßer {
218544d4804dSStefan Eßer 	BcBigDig val;
2186252884aeSStefan Eßer 
2187252884aeSStefan Eßer 	BC_UNUSED(scale);
2188252884aeSStefan Eßer 
218944d4804dSStefan Eßer 	val = bc_num_intop(a, b, c);
2190252884aeSStefan Eßer 
2191252884aeSStefan Eßer 	bc_num_shiftLeft(c, (size_t) val);
2192252884aeSStefan Eßer }
2193252884aeSStefan Eßer 
219444d4804dSStefan Eßer /**
219544d4804dSStefan Eßer  * Implements the right shift operator. This is a BcNumBinOp function.
219644d4804dSStefan Eßer  */
219778bc019dSStefan Eßer static void
219878bc019dSStefan Eßer bc_num_right(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
219978bc019dSStefan Eßer {
220044d4804dSStefan Eßer 	BcBigDig val;
2201252884aeSStefan Eßer 
2202252884aeSStefan Eßer 	BC_UNUSED(scale);
2203252884aeSStefan Eßer 
220444d4804dSStefan Eßer 	val = bc_num_intop(a, b, c);
2205252884aeSStefan Eßer 
2206252884aeSStefan Eßer 	if (BC_NUM_ZERO(c)) return;
2207252884aeSStefan Eßer 
2208252884aeSStefan Eßer 	bc_num_shiftRight(c, (size_t) val);
2209252884aeSStefan Eßer }
2210252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
2211252884aeSStefan Eßer 
221244d4804dSStefan Eßer /**
221344d4804dSStefan Eßer  * Prepares for, and calls, a binary operator function. This is probably the
221444d4804dSStefan Eßer  * most important function in the entire file because it establishes assumptions
221544d4804dSStefan Eßer  * that make the rest of the code so easy. Those assumptions include:
221644d4804dSStefan Eßer  *
221744d4804dSStefan Eßer  * - a is not the same pointer as c.
221844d4804dSStefan Eßer  * - b is not the same pointer as c.
221944d4804dSStefan Eßer  * - there is enough room in c for the result.
222044d4804dSStefan Eßer  *
222144d4804dSStefan Eßer  * Without these, this whole function would basically have to be duplicated for
222244d4804dSStefan Eßer  * *all* binary operators.
222344d4804dSStefan Eßer  *
222444d4804dSStefan Eßer  * @param a      The first operand.
222544d4804dSStefan Eßer  * @param b      The second operand.
222644d4804dSStefan Eßer  * @param c      The return parameter.
222744d4804dSStefan Eßer  * @param scale  The current scale.
222844d4804dSStefan Eßer  * @param req    The number of limbs needed to fit the result.
222944d4804dSStefan Eßer  */
223078bc019dSStefan Eßer static void
223178bc019dSStefan Eßer bc_num_binary(BcNum* a, BcNum* b, BcNum* c, size_t scale, BcNumBinOp op,
223278bc019dSStefan Eßer               size_t req)
2233252884aeSStefan Eßer {
223478bc019dSStefan Eßer 	BcNum* ptr_a;
223578bc019dSStefan Eßer 	BcNum* ptr_b;
223678bc019dSStefan Eßer 	BcNum num2;
2237d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2238d101cdd6SStefan Eßer 	BcVm* vm = NULL;
2239d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2240252884aeSStefan Eßer 
2241252884aeSStefan Eßer 	assert(a != NULL && b != NULL && c != NULL && op != NULL);
2242252884aeSStefan Eßer 
224350696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
224450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
224550696a6eSStefan Eßer 
2246252884aeSStefan Eßer 	BC_SIG_LOCK;
2247252884aeSStefan Eßer 
2248d101cdd6SStefan Eßer 	ptr_a = c == a ? &num2 : a;
2249d101cdd6SStefan Eßer 	ptr_b = c == b ? &num2 : b;
2250252884aeSStefan Eßer 
225144d4804dSStefan Eßer 	// Actually reallocate. If we don't reallocate, we want to expand at the
225244d4804dSStefan Eßer 	// very least.
2253d101cdd6SStefan Eßer 	if (c == a || c == b)
225478bc019dSStefan Eßer 	{
2255d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2256d101cdd6SStefan Eßer 		vm = bcl_getspecific();
2257d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2258d101cdd6SStefan Eßer 
2259d101cdd6SStefan Eßer 		// NOLINTNEXTLINE
2260d101cdd6SStefan Eßer 		memcpy(&num2, c, sizeof(BcNum));
2261d101cdd6SStefan Eßer 
2262252884aeSStefan Eßer 		bc_num_init(c, req);
2263252884aeSStefan Eßer 
226444d4804dSStefan Eßer 		// Must prepare for cleanup. We want this here so that locals that got
226544d4804dSStefan Eßer 		// set stay set since a longjmp() is not guaranteed to preserve locals.
2266d101cdd6SStefan Eßer 		BC_SETJMP_LOCKED(vm, err);
2267252884aeSStefan Eßer 		BC_SIG_UNLOCK;
2268252884aeSStefan Eßer 	}
226978bc019dSStefan Eßer 	else
227078bc019dSStefan Eßer 	{
2271252884aeSStefan Eßer 		BC_SIG_UNLOCK;
2272252884aeSStefan Eßer 		bc_num_expand(c, req);
2273252884aeSStefan Eßer 	}
2274252884aeSStefan Eßer 
227544d4804dSStefan Eßer 	// It is okay for a and b to be the same. If a binary operator function does
227644d4804dSStefan Eßer 	// need them to be different, the binary operator function is responsible
227744d4804dSStefan Eßer 	// for that.
227844d4804dSStefan Eßer 
227944d4804dSStefan Eßer 	// Call the actual binary operator function.
2280252884aeSStefan Eßer 	op(ptr_a, ptr_b, c, scale);
2281252884aeSStefan Eßer 
228250696a6eSStefan Eßer 	assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c));
228350696a6eSStefan Eßer 	assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len);
228450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(c));
228550696a6eSStefan Eßer 	assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len);
2286252884aeSStefan Eßer 
2287252884aeSStefan Eßer err:
228844d4804dSStefan Eßer 	// Cleanup only needed if we initialized c to a new number.
2289d101cdd6SStefan Eßer 	if (c == a || c == b)
229078bc019dSStefan Eßer 	{
2291252884aeSStefan Eßer 		BC_SIG_MAYLOCK;
2292252884aeSStefan Eßer 		bc_num_free(&num2);
2293d101cdd6SStefan Eßer 		BC_LONGJMP_CONT(vm);
2294252884aeSStefan Eßer 	}
2295252884aeSStefan Eßer }
2296252884aeSStefan Eßer 
229744d4804dSStefan Eßer /**
229844d4804dSStefan Eßer  * Tests a number string for validity. This function has a history; I originally
229944d4804dSStefan Eßer  * wrote it because I did not trust my parser. Over time, however, I came to
230044d4804dSStefan Eßer  * trust it, so I was able to relegate this function to debug builds only, and I
230144d4804dSStefan Eßer  * used it in assert()'s. But then I created the library, and well, I can't
230244d4804dSStefan Eßer  * trust users, so I reused this for yelling at users.
230344d4804dSStefan Eßer  * @param val  The string to check to see if it's a valid number string.
230444d4804dSStefan Eßer  * @return     True if the string is a valid number string, false otherwise.
230544d4804dSStefan Eßer  */
230678bc019dSStefan Eßer bool
230778bc019dSStefan Eßer bc_num_strValid(const char* restrict val)
230878bc019dSStefan Eßer {
2309252884aeSStefan Eßer 	bool radix = false;
2310252884aeSStefan Eßer 	size_t i, len = strlen(val);
2311252884aeSStefan Eßer 
231244d4804dSStefan Eßer 	// Notice that I don't check if there is a negative sign. That is not part
231344d4804dSStefan Eßer 	// of a valid number, except in the library. The library-specific code takes
231444d4804dSStefan Eßer 	// care of that part.
231544d4804dSStefan Eßer 
231644d4804dSStefan Eßer 	// Nothing in the string is okay.
2317252884aeSStefan Eßer 	if (!len) return true;
2318252884aeSStefan Eßer 
231944d4804dSStefan Eßer 	// Loop through the characters.
232078bc019dSStefan Eßer 	for (i = 0; i < len; ++i)
232178bc019dSStefan Eßer 	{
2322252884aeSStefan Eßer 		BcDig c = val[i];
2323252884aeSStefan Eßer 
232444d4804dSStefan Eßer 		// If we have found a radix point...
232578bc019dSStefan Eßer 		if (c == '.')
232678bc019dSStefan Eßer 		{
232744d4804dSStefan Eßer 			// We don't allow two radices.
2328252884aeSStefan Eßer 			if (radix) return false;
2329252884aeSStefan Eßer 
2330252884aeSStefan Eßer 			radix = true;
2331252884aeSStefan Eßer 			continue;
2332252884aeSStefan Eßer 		}
2333252884aeSStefan Eßer 
233444d4804dSStefan Eßer 		// We only allow digits and uppercase letters.
2335252884aeSStefan Eßer 		if (!(isdigit(c) || isupper(c))) return false;
2336252884aeSStefan Eßer 	}
2337252884aeSStefan Eßer 
2338252884aeSStefan Eßer 	return true;
2339252884aeSStefan Eßer }
2340252884aeSStefan Eßer 
234144d4804dSStefan Eßer /**
234244d4804dSStefan Eßer  * Parses one character and returns the digit that corresponds to that
234344d4804dSStefan Eßer  * character according to the base.
234444d4804dSStefan Eßer  * @param c     The character to parse.
234544d4804dSStefan Eßer  * @param base  The base.
234644d4804dSStefan Eßer  * @return      The character as a digit.
234744d4804dSStefan Eßer  */
234878bc019dSStefan Eßer static BcBigDig
234978bc019dSStefan Eßer bc_num_parseChar(char c, size_t base)
235078bc019dSStefan Eßer {
235144d4804dSStefan Eßer 	assert(isupper(c) || isdigit(c));
235244d4804dSStefan Eßer 
235344d4804dSStefan Eßer 	// If a letter...
235478bc019dSStefan Eßer 	if (isupper(c))
235578bc019dSStefan Eßer 	{
2356d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2357d101cdd6SStefan Eßer 		BcVm* vm = bcl_getspecific();
2358d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2359d101cdd6SStefan Eßer 
236044d4804dSStefan Eßer 		// This returns the digit that directly corresponds with the letter.
2361252884aeSStefan Eßer 		c = BC_NUM_NUM_LETTER(c);
236244d4804dSStefan Eßer 
236344d4804dSStefan Eßer 		// If the digit is greater than the base, we clamp.
2364d101cdd6SStefan Eßer 		if (BC_DIGIT_CLAMP)
2365d101cdd6SStefan Eßer 		{
236644d4804dSStefan Eßer 			c = ((size_t) c) >= base ? (char) base - 1 : c;
2367252884aeSStefan Eßer 		}
2368d101cdd6SStefan Eßer 	}
236944d4804dSStefan Eßer 	// Straight convert the digit to a number.
2370252884aeSStefan Eßer 	else c -= '0';
2371252884aeSStefan Eßer 
2372252884aeSStefan Eßer 	return (BcBigDig) (uchar) c;
2373252884aeSStefan Eßer }
2374252884aeSStefan Eßer 
237544d4804dSStefan Eßer /**
237644d4804dSStefan Eßer  * Parses a string as a decimal number. This is separate because it's going to
237744d4804dSStefan Eßer  * be the most used, and it can be heavily optimized for decimal only.
237844d4804dSStefan Eßer  * @param n    The number to parse into and return. Must be preallocated.
237944d4804dSStefan Eßer  * @param val  The string to parse.
238044d4804dSStefan Eßer  */
238178bc019dSStefan Eßer static void
238278bc019dSStefan Eßer bc_num_parseDecimal(BcNum* restrict n, const char* restrict val)
238378bc019dSStefan Eßer {
2384252884aeSStefan Eßer 	size_t len, i, temp, mod;
2385252884aeSStefan Eßer 	const char* ptr;
2386252884aeSStefan Eßer 	bool zero = true, rdx;
2387d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2388d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
2389d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2390252884aeSStefan Eßer 
239144d4804dSStefan Eßer 	// Eat leading zeroes.
239278bc019dSStefan Eßer 	for (i = 0; val[i] == '0'; ++i)
239378bc019dSStefan Eßer 	{
239478bc019dSStefan Eßer 		continue;
239578bc019dSStefan Eßer 	}
2396252884aeSStefan Eßer 
2397252884aeSStefan Eßer 	val += i;
2398252884aeSStefan Eßer 	assert(!val[0] || isalnum(val[0]) || val[0] == '.');
2399252884aeSStefan Eßer 
240044d4804dSStefan Eßer 	// All 0's. We can just return, since this procedure expects a virgin
240144d4804dSStefan Eßer 	// (already 0) BcNum.
2402252884aeSStefan Eßer 	if (!val[0]) return;
2403252884aeSStefan Eßer 
240444d4804dSStefan Eßer 	// The length of the string is the length of the number, except it might be
240544d4804dSStefan Eßer 	// one bigger because of a decimal point.
2406252884aeSStefan Eßer 	len = strlen(val);
2407252884aeSStefan Eßer 
240844d4804dSStefan Eßer 	// Find the location of the decimal point.
2409252884aeSStefan Eßer 	ptr = strchr(val, '.');
2410252884aeSStefan Eßer 	rdx = (ptr != NULL);
2411252884aeSStefan Eßer 
241244d4804dSStefan Eßer 	// We eat leading zeroes again. These leading zeroes are different because
241344d4804dSStefan Eßer 	// they will come after the decimal point if they exist, and since that's
241444d4804dSStefan Eßer 	// the case, they must be preserved.
241578bc019dSStefan Eßer 	for (i = 0; i < len && (zero = (val[i] == '0' || val[i] == '.')); ++i)
241678bc019dSStefan Eßer 	{
241778bc019dSStefan Eßer 		continue;
241878bc019dSStefan Eßer 	}
2419252884aeSStefan Eßer 
242044d4804dSStefan Eßer 	// Set the scale of the number based on the location of the decimal point.
242144d4804dSStefan Eßer 	// The casts to uintptr_t is to ensure that bc does not hit undefined
242244d4804dSStefan Eßer 	// behavior when doing math on the values.
242378bc019dSStefan Eßer 	n->scale = (size_t) (rdx *
242478bc019dSStefan Eßer 	                     (((uintptr_t) (val + len)) - (((uintptr_t) ptr) + 1)));
2425252884aeSStefan Eßer 
242644d4804dSStefan Eßer 	// Set rdx.
242750696a6eSStefan Eßer 	BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale));
242844d4804dSStefan Eßer 
242944d4804dSStefan Eßer 	// Calculate length. First, the length of the integer, then the number of
243044d4804dSStefan Eßer 	// digits in the last limb, then the length.
2431252884aeSStefan Eßer 	i = len - (ptr == val ? 0 : i) - rdx;
2432252884aeSStefan Eßer 	temp = BC_NUM_ROUND_POW(i);
2433252884aeSStefan Eßer 	mod = n->scale % BC_BASE_DIGS;
2434252884aeSStefan Eßer 	i = mod ? BC_BASE_DIGS - mod : 0;
2435252884aeSStefan Eßer 	n->len = ((temp + i) / BC_BASE_DIGS);
2436252884aeSStefan Eßer 
2437d101cdd6SStefan Eßer 	// Expand and zero. The plus extra is in case the lack of clamping causes
2438d101cdd6SStefan Eßer 	// the number to overflow the original bounds.
2439d101cdd6SStefan Eßer 	bc_num_expand(n, n->len + !BC_DIGIT_CLAMP);
244078bc019dSStefan Eßer 	// NOLINTNEXTLINE
2441d101cdd6SStefan Eßer 	memset(n->num, 0, BC_NUM_SIZE(n->len + !BC_DIGIT_CLAMP));
2442252884aeSStefan Eßer 
244378bc019dSStefan Eßer 	if (zero)
244478bc019dSStefan Eßer 	{
244550696a6eSStefan Eßer 		// I think I can set rdx directly to zero here because n should be a
244650696a6eSStefan Eßer 		// new number with sign set to false.
244750696a6eSStefan Eßer 		n->len = n->rdx = 0;
244850696a6eSStefan Eßer 	}
244978bc019dSStefan Eßer 	else
245078bc019dSStefan Eßer 	{
245144d4804dSStefan Eßer 		// There is actually stuff to parse if we make it here. Yay...
2452252884aeSStefan Eßer 		BcBigDig exp, pow;
2453252884aeSStefan Eßer 
2454252884aeSStefan Eßer 		assert(i <= BC_NUM_BIGDIG_MAX);
2455252884aeSStefan Eßer 
245644d4804dSStefan Eßer 		// The exponent and power.
2457252884aeSStefan Eßer 		exp = (BcBigDig) i;
2458252884aeSStefan Eßer 		pow = bc_num_pow10[exp];
2459252884aeSStefan Eßer 
246044d4804dSStefan Eßer 		// Parse loop. We parse backwards because numbers are stored little
246144d4804dSStefan Eßer 		// endian.
246278bc019dSStefan Eßer 		for (i = len - 1; i < len; --i, ++exp)
246378bc019dSStefan Eßer 		{
2464252884aeSStefan Eßer 			char c = val[i];
2465252884aeSStefan Eßer 
246644d4804dSStefan Eßer 			// Skip the decimal point.
2467252884aeSStefan Eßer 			if (c == '.') exp -= 1;
246878bc019dSStefan Eßer 			else
246978bc019dSStefan Eßer 			{
247044d4804dSStefan Eßer 				// The index of the limb.
2471252884aeSStefan Eßer 				size_t idx = exp / BC_BASE_DIGS;
2472d101cdd6SStefan Eßer 				BcBigDig dig;
2473252884aeSStefan Eßer 
2474d101cdd6SStefan Eßer 				if (isupper(c))
2475d101cdd6SStefan Eßer 				{
247644d4804dSStefan Eßer 					// Clamp for the base.
2477d101cdd6SStefan Eßer 					if (!BC_DIGIT_CLAMP) c = BC_NUM_NUM_LETTER(c);
2478d101cdd6SStefan Eßer 					else c = 9;
2479d101cdd6SStefan Eßer 				}
2480d101cdd6SStefan Eßer 				else c -= '0';
248144d4804dSStefan Eßer 
2482d101cdd6SStefan Eßer 				// Add the digit to the limb. This takes care of overflow from
2483d101cdd6SStefan Eßer 				// lack of clamping.
2484d101cdd6SStefan Eßer 				dig = ((BcBigDig) n->num[idx]) + ((BcBigDig) c) * pow;
2485d101cdd6SStefan Eßer 				if (dig >= BC_BASE_POW)
2486d101cdd6SStefan Eßer 				{
2487d101cdd6SStefan Eßer 					// We cannot go over BC_BASE_POW with clamping.
2488d101cdd6SStefan Eßer 					assert(!BC_DIGIT_CLAMP);
2489d101cdd6SStefan Eßer 
2490d101cdd6SStefan Eßer 					n->num[idx + 1] = (BcDig) (dig / BC_BASE_POW);
2491d101cdd6SStefan Eßer 					n->num[idx] = (BcDig) (dig % BC_BASE_POW);
2492d101cdd6SStefan Eßer 					assert(n->num[idx] >= 0 && n->num[idx] < BC_BASE_POW);
2493d101cdd6SStefan Eßer 					assert(n->num[idx + 1] >= 0 &&
2494d101cdd6SStefan Eßer 					       n->num[idx + 1] < BC_BASE_POW);
2495d101cdd6SStefan Eßer 				}
2496d101cdd6SStefan Eßer 				else
2497d101cdd6SStefan Eßer 				{
2498d101cdd6SStefan Eßer 					n->num[idx] = (BcDig) dig;
2499d101cdd6SStefan Eßer 					assert(n->num[idx] >= 0 && n->num[idx] < BC_BASE_POW);
2500d101cdd6SStefan Eßer 				}
2501252884aeSStefan Eßer 
250244d4804dSStefan Eßer 				// Adjust the power and exponent.
2503252884aeSStefan Eßer 				if ((exp + 1) % BC_BASE_DIGS == 0) pow = 1;
2504252884aeSStefan Eßer 				else pow *= BC_BASE;
2505252884aeSStefan Eßer 			}
2506252884aeSStefan Eßer 		}
2507252884aeSStefan Eßer 	}
2508d101cdd6SStefan Eßer 
2509d101cdd6SStefan Eßer 	// Make sure to add one to the length if needed from lack of clamping.
2510d101cdd6SStefan Eßer 	n->len += (!BC_DIGIT_CLAMP && n->num[n->len] != 0);
2511252884aeSStefan Eßer }
2512252884aeSStefan Eßer 
251344d4804dSStefan Eßer /**
251444d4804dSStefan Eßer  * Parse a number in any base (besides decimal).
251544d4804dSStefan Eßer  * @param n     The number to parse into and return. Must be preallocated.
251644d4804dSStefan Eßer  * @param val   The string to parse.
251744d4804dSStefan Eßer  * @param base  The base to parse as.
251844d4804dSStefan Eßer  */
251978bc019dSStefan Eßer static void
252078bc019dSStefan Eßer bc_num_parseBase(BcNum* restrict n, const char* restrict val, BcBigDig base)
2521252884aeSStefan Eßer {
252278bc019dSStefan Eßer 	BcNum temp, mult1, mult2, result1, result2;
252378bc019dSStefan Eßer 	BcNum* m1;
252478bc019dSStefan Eßer 	BcNum* m2;
252578bc019dSStefan Eßer 	BcNum* ptr;
2526252884aeSStefan Eßer 	char c = 0;
2527252884aeSStefan Eßer 	bool zero = true;
2528252884aeSStefan Eßer 	BcBigDig v;
2529d101cdd6SStefan Eßer 	size_t digs, len = strlen(val);
2530d101cdd6SStefan Eßer 	// This is volatile to quiet a warning on GCC about longjmp() clobbering.
2531d101cdd6SStefan Eßer 	volatile size_t i;
2532d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2533d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
2534d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2535252884aeSStefan Eßer 
253644d4804dSStefan Eßer 	// If zero, just return because the number should be virgin (already 0).
253778bc019dSStefan Eßer 	for (i = 0; zero && i < len; ++i)
253878bc019dSStefan Eßer 	{
253978bc019dSStefan Eßer 		zero = (val[i] == '.' || val[i] == '0');
254078bc019dSStefan Eßer 	}
2541252884aeSStefan Eßer 	if (zero) return;
2542252884aeSStefan Eßer 
2543252884aeSStefan Eßer 	BC_SIG_LOCK;
2544252884aeSStefan Eßer 
2545252884aeSStefan Eßer 	bc_num_init(&temp, BC_NUM_BIGDIG_LOG10);
2546252884aeSStefan Eßer 	bc_num_init(&mult1, BC_NUM_BIGDIG_LOG10);
2547252884aeSStefan Eßer 
2548d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, int_err);
2549252884aeSStefan Eßer 
2550252884aeSStefan Eßer 	BC_SIG_UNLOCK;
2551252884aeSStefan Eßer 
255244d4804dSStefan Eßer 	// We split parsing into parsing the integer and parsing the fractional
255344d4804dSStefan Eßer 	// part.
255444d4804dSStefan Eßer 
255544d4804dSStefan Eßer 	// Parse the integer part. This is the easy part because we just multiply
255644d4804dSStefan Eßer 	// the number by the base, then add the digit.
255778bc019dSStefan Eßer 	for (i = 0; i < len && (c = val[i]) && c != '.'; ++i)
255878bc019dSStefan Eßer 	{
255944d4804dSStefan Eßer 		// Convert the character to a digit.
2560252884aeSStefan Eßer 		v = bc_num_parseChar(c, base);
2561252884aeSStefan Eßer 
256244d4804dSStefan Eßer 		// Multiply the number.
2563252884aeSStefan Eßer 		bc_num_mulArray(n, base, &mult1);
256444d4804dSStefan Eßer 
256544d4804dSStefan Eßer 		// Convert the digit to a number and add.
2566252884aeSStefan Eßer 		bc_num_bigdig2num(&temp, v);
2567252884aeSStefan Eßer 		bc_num_add(&mult1, &temp, n, 0);
2568252884aeSStefan Eßer 	}
2569252884aeSStefan Eßer 
257044d4804dSStefan Eßer 	// If this condition is true, then we are done. We still need to do cleanup
257144d4804dSStefan Eßer 	// though.
257210328f8bSStefan Eßer 	if (i == len && !val[i]) goto int_err;
2573252884aeSStefan Eßer 
257444d4804dSStefan Eßer 	// If we get here, we *must* be at the radix point.
257510328f8bSStefan Eßer 	assert(val[i] == '.');
2576252884aeSStefan Eßer 
2577252884aeSStefan Eßer 	BC_SIG_LOCK;
2578252884aeSStefan Eßer 
257944d4804dSStefan Eßer 	// Unset the jump to reset in for these new initializations.
2580d101cdd6SStefan Eßer 	BC_UNSETJMP(vm);
2581252884aeSStefan Eßer 
2582252884aeSStefan Eßer 	bc_num_init(&mult2, BC_NUM_BIGDIG_LOG10);
2583252884aeSStefan Eßer 	bc_num_init(&result1, BC_NUM_DEF_SIZE);
2584252884aeSStefan Eßer 	bc_num_init(&result2, BC_NUM_DEF_SIZE);
2585252884aeSStefan Eßer 	bc_num_one(&mult1);
2586252884aeSStefan Eßer 
2587d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
2588252884aeSStefan Eßer 
2589252884aeSStefan Eßer 	BC_SIG_UNLOCK;
2590252884aeSStefan Eßer 
259144d4804dSStefan Eßer 	// Pointers for easy switching.
2592252884aeSStefan Eßer 	m1 = &mult1;
2593252884aeSStefan Eßer 	m2 = &mult2;
2594252884aeSStefan Eßer 
259544d4804dSStefan Eßer 	// Parse the fractional part. This is the hard part.
259678bc019dSStefan Eßer 	for (i += 1, digs = 0; i < len && (c = val[i]); ++i, ++digs)
259778bc019dSStefan Eßer 	{
259850696a6eSStefan Eßer 		size_t rdx;
259950696a6eSStefan Eßer 
260044d4804dSStefan Eßer 		// Convert the character to a digit.
2601252884aeSStefan Eßer 		v = bc_num_parseChar(c, base);
2602252884aeSStefan Eßer 
260344d4804dSStefan Eßer 		// We keep growing result2 according to the base because the more digits
260444d4804dSStefan Eßer 		// after the radix, the more significant the digits close to the radix
260544d4804dSStefan Eßer 		// should be.
2606252884aeSStefan Eßer 		bc_num_mulArray(&result1, base, &result2);
2607252884aeSStefan Eßer 
260844d4804dSStefan Eßer 		// Convert the digit to a number.
2609252884aeSStefan Eßer 		bc_num_bigdig2num(&temp, v);
261044d4804dSStefan Eßer 
261144d4804dSStefan Eßer 		// Add the digit into the fraction part.
2612252884aeSStefan Eßer 		bc_num_add(&result2, &temp, &result1, 0);
261344d4804dSStefan Eßer 
261444d4804dSStefan Eßer 		// Keep growing m1 and m2 for use after the loop.
2615252884aeSStefan Eßer 		bc_num_mulArray(m1, base, m2);
2616252884aeSStefan Eßer 
261750696a6eSStefan Eßer 		rdx = BC_NUM_RDX_VAL(m2);
261850696a6eSStefan Eßer 
261950696a6eSStefan Eßer 		if (m2->len < rdx) m2->len = rdx;
2620252884aeSStefan Eßer 
262144d4804dSStefan Eßer 		// Switch.
2622252884aeSStefan Eßer 		ptr = m1;
2623252884aeSStefan Eßer 		m1 = m2;
2624252884aeSStefan Eßer 		m2 = ptr;
2625252884aeSStefan Eßer 	}
2626252884aeSStefan Eßer 
2627252884aeSStefan Eßer 	// This one cannot be a divide by 0 because mult starts out at 1, then is
262844d4804dSStefan Eßer 	// multiplied by base, and base cannot be 0, so mult cannot be 0. And this
262944d4804dSStefan Eßer 	// is the reason we keep growing m1 and m2; this division is what converts
263044d4804dSStefan Eßer 	// the parsed fractional part from an integer to a fractional part.
2631252884aeSStefan Eßer 	bc_num_div(&result1, m1, &result2, digs * 2);
263244d4804dSStefan Eßer 
263344d4804dSStefan Eßer 	// Pretruncate.
2634252884aeSStefan Eßer 	bc_num_truncate(&result2, digs);
263544d4804dSStefan Eßer 
263644d4804dSStefan Eßer 	// The final add of the integer part to the fractional part.
2637252884aeSStefan Eßer 	bc_num_add(n, &result2, n, digs);
2638252884aeSStefan Eßer 
263944d4804dSStefan Eßer 	// Basic cleanup.
264078bc019dSStefan Eßer 	if (BC_NUM_NONZERO(n))
264178bc019dSStefan Eßer 	{
2642252884aeSStefan Eßer 		if (n->scale < digs) bc_num_extend(n, digs - n->scale);
2643252884aeSStefan Eßer 	}
2644252884aeSStefan Eßer 	else bc_num_zero(n);
2645252884aeSStefan Eßer 
2646252884aeSStefan Eßer err:
2647252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
2648252884aeSStefan Eßer 	bc_num_free(&result2);
2649252884aeSStefan Eßer 	bc_num_free(&result1);
2650252884aeSStefan Eßer 	bc_num_free(&mult2);
2651252884aeSStefan Eßer int_err:
2652252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
2653252884aeSStefan Eßer 	bc_num_free(&mult1);
2654252884aeSStefan Eßer 	bc_num_free(&temp);
2655d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
2656252884aeSStefan Eßer }
2657252884aeSStefan Eßer 
265844d4804dSStefan Eßer /**
265944d4804dSStefan Eßer  * Prints a backslash+newline combo if the number of characters needs it. This
266044d4804dSStefan Eßer  * is really a convenience function.
266144d4804dSStefan Eßer  */
266278bc019dSStefan Eßer static inline void
266378bc019dSStefan Eßer bc_num_printNewline(void)
266478bc019dSStefan Eßer {
266550696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY
2666d101cdd6SStefan Eßer 	if (vm->nchars >= vm->line_len - 1 && vm->line_len)
266778bc019dSStefan Eßer 	{
26687e5c51e5SStefan Eßer 		bc_vm_putchar('\\', bc_flush_none);
26697e5c51e5SStefan Eßer 		bc_vm_putchar('\n', bc_flush_err);
2670252884aeSStefan Eßer 	}
267150696a6eSStefan Eßer #endif // !BC_ENABLE_LIBRARY
2672252884aeSStefan Eßer }
2673252884aeSStefan Eßer 
267444d4804dSStefan Eßer /**
267544d4804dSStefan Eßer  * Prints a character after a backslash+newline, if needed.
267644d4804dSStefan Eßer  * @param c       The character to print.
267744d4804dSStefan Eßer  * @param bslash  Whether to print a backslash+newline.
267844d4804dSStefan Eßer  */
267978bc019dSStefan Eßer static void
268078bc019dSStefan Eßer bc_num_putchar(int c, bool bslash)
268178bc019dSStefan Eßer {
268244d4804dSStefan Eßer 	if (c != '\n' && bslash) bc_num_printNewline();
26837e5c51e5SStefan Eßer 	bc_vm_putchar(c, bc_flush_save);
2684252884aeSStefan Eßer }
2685252884aeSStefan Eßer 
268644d4804dSStefan Eßer #if !BC_ENABLE_LIBRARY
268744d4804dSStefan Eßer 
268844d4804dSStefan Eßer /**
268944d4804dSStefan Eßer  * Prints a character for a number's digit. This is for printing for dc's P
269044d4804dSStefan Eßer  * command. This function does not need to worry about radix points. This is a
269144d4804dSStefan Eßer  * BcNumDigitOp.
269244d4804dSStefan Eßer  * @param n       The "digit" to print.
269344d4804dSStefan Eßer  * @param len     The "length" of the digit, or number of characters that will
269444d4804dSStefan Eßer  *                need to be printed for the digit.
269544d4804dSStefan Eßer  * @param rdx     True if a decimal (radix) point should be printed.
269644d4804dSStefan Eßer  * @param bslash  True if a backslash+newline should be printed if the character
269744d4804dSStefan Eßer  *                limit for the line is reached, false otherwise.
269844d4804dSStefan Eßer  */
269978bc019dSStefan Eßer static void
270078bc019dSStefan Eßer bc_num_printChar(size_t n, size_t len, bool rdx, bool bslash)
270178bc019dSStefan Eßer {
2702252884aeSStefan Eßer 	BC_UNUSED(rdx);
2703252884aeSStefan Eßer 	BC_UNUSED(len);
270444d4804dSStefan Eßer 	BC_UNUSED(bslash);
2705252884aeSStefan Eßer 	assert(len == 1);
27067e5c51e5SStefan Eßer 	bc_vm_putchar((uchar) n, bc_flush_save);
2707252884aeSStefan Eßer }
2708252884aeSStefan Eßer 
270944d4804dSStefan Eßer #endif // !BC_ENABLE_LIBRARY
271044d4804dSStefan Eßer 
271144d4804dSStefan Eßer /**
271244d4804dSStefan Eßer  * Prints a series of characters for large bases. This is for printing in bases
271344d4804dSStefan Eßer  * above hexadecimal. This is a BcNumDigitOp.
271444d4804dSStefan Eßer  * @param n       The "digit" to print.
271544d4804dSStefan Eßer  * @param len     The "length" of the digit, or number of characters that will
271644d4804dSStefan Eßer  *                need to be printed for the digit.
271744d4804dSStefan Eßer  * @param rdx     True if a decimal (radix) point should be printed.
271844d4804dSStefan Eßer  * @param bslash  True if a backslash+newline should be printed if the character
271944d4804dSStefan Eßer  *                limit for the line is reached, false otherwise.
272044d4804dSStefan Eßer  */
272178bc019dSStefan Eßer static void
272278bc019dSStefan Eßer bc_num_printDigits(size_t n, size_t len, bool rdx, bool bslash)
272378bc019dSStefan Eßer {
2724252884aeSStefan Eßer 	size_t exp, pow;
2725252884aeSStefan Eßer 
272644d4804dSStefan Eßer 	// If needed, print the radix; otherwise, print a space to separate digits.
272744d4804dSStefan Eßer 	bc_num_putchar(rdx ? '.' : ' ', true);
2728252884aeSStefan Eßer 
272944d4804dSStefan Eßer 	// Calculate the exponent and power.
273078bc019dSStefan Eßer 	for (exp = 0, pow = 1; exp < len - 1; ++exp, pow *= BC_BASE)
273178bc019dSStefan Eßer 	{
273278bc019dSStefan Eßer 		continue;
273378bc019dSStefan Eßer 	}
2734252884aeSStefan Eßer 
273544d4804dSStefan Eßer 	// Print each character individually.
273678bc019dSStefan Eßer 	for (exp = 0; exp < len; pow /= BC_BASE, ++exp)
273778bc019dSStefan Eßer 	{
273844d4804dSStefan Eßer 		// The individual subdigit.
2739252884aeSStefan Eßer 		size_t dig = n / pow;
274044d4804dSStefan Eßer 
274144d4804dSStefan Eßer 		// Take the subdigit away.
2742252884aeSStefan Eßer 		n -= dig * pow;
274344d4804dSStefan Eßer 
274444d4804dSStefan Eßer 		// Print the subdigit.
274544d4804dSStefan Eßer 		bc_num_putchar(((uchar) dig) + '0', bslash || exp != len - 1);
2746252884aeSStefan Eßer 	}
2747252884aeSStefan Eßer }
2748252884aeSStefan Eßer 
274944d4804dSStefan Eßer /**
275044d4804dSStefan Eßer  * Prints a character for a number's digit. This is for printing in bases for
275144d4804dSStefan Eßer  * hexadecimal and below because they always print only one character at a time.
275244d4804dSStefan Eßer  * This is a BcNumDigitOp.
275344d4804dSStefan Eßer  * @param n       The "digit" to print.
275444d4804dSStefan Eßer  * @param len     The "length" of the digit, or number of characters that will
275544d4804dSStefan Eßer  *                need to be printed for the digit.
275644d4804dSStefan Eßer  * @param rdx     True if a decimal (radix) point should be printed.
275744d4804dSStefan Eßer  * @param bslash  True if a backslash+newline should be printed if the character
275844d4804dSStefan Eßer  *                limit for the line is reached, false otherwise.
275944d4804dSStefan Eßer  */
276078bc019dSStefan Eßer static void
276178bc019dSStefan Eßer bc_num_printHex(size_t n, size_t len, bool rdx, bool bslash)
276278bc019dSStefan Eßer {
2763252884aeSStefan Eßer 	BC_UNUSED(len);
276444d4804dSStefan Eßer 	BC_UNUSED(bslash);
2765252884aeSStefan Eßer 
2766252884aeSStefan Eßer 	assert(len == 1);
2767252884aeSStefan Eßer 
276844d4804dSStefan Eßer 	if (rdx) bc_num_putchar('.', true);
2769252884aeSStefan Eßer 
277044d4804dSStefan Eßer 	bc_num_putchar(bc_num_hex_digits[n], bslash);
2771252884aeSStefan Eßer }
2772252884aeSStefan Eßer 
277344d4804dSStefan Eßer /**
277444d4804dSStefan Eßer  * Prints a decimal number. This is specially written for optimization since
277544d4804dSStefan Eßer  * this will be used the most and because bc's numbers are already in decimal.
277644d4804dSStefan Eßer  * @param n        The number to print.
277744d4804dSStefan Eßer  * @param newline  Whether to print backslash+newlines on long enough lines.
277844d4804dSStefan Eßer  */
277978bc019dSStefan Eßer static void
278078bc019dSStefan Eßer bc_num_printDecimal(const BcNum* restrict n, bool newline)
278178bc019dSStefan Eßer {
278250696a6eSStefan Eßer 	size_t i, j, rdx = BC_NUM_RDX_VAL(n);
2783252884aeSStefan Eßer 	bool zero = true;
2784252884aeSStefan Eßer 	size_t buffer[BC_BASE_DIGS];
2785252884aeSStefan Eßer 
278644d4804dSStefan Eßer 	// Print loop.
278778bc019dSStefan Eßer 	for (i = n->len - 1; i < n->len; --i)
278878bc019dSStefan Eßer 	{
2789252884aeSStefan Eßer 		BcDig n9 = n->num[i];
2790252884aeSStefan Eßer 		size_t temp;
2791252884aeSStefan Eßer 		bool irdx = (i == rdx - 1);
2792252884aeSStefan Eßer 
279344d4804dSStefan Eßer 		// Calculate the number of digits in the limb.
2794252884aeSStefan Eßer 		zero = (zero & !irdx);
2795252884aeSStefan Eßer 		temp = n->scale % BC_BASE_DIGS;
2796252884aeSStefan Eßer 		temp = i || !temp ? 0 : BC_BASE_DIGS - temp;
2797252884aeSStefan Eßer 
279878bc019dSStefan Eßer 		// NOLINTNEXTLINE
2799252884aeSStefan Eßer 		memset(buffer, 0, BC_BASE_DIGS * sizeof(size_t));
2800252884aeSStefan Eßer 
280144d4804dSStefan Eßer 		// Fill the buffer with individual digits.
280278bc019dSStefan Eßer 		for (j = 0; n9 && j < BC_BASE_DIGS; ++j)
280378bc019dSStefan Eßer 		{
2804d213476dSStefan Eßer 			buffer[j] = ((size_t) n9) % BC_BASE;
2805252884aeSStefan Eßer 			n9 /= BC_BASE;
2806252884aeSStefan Eßer 		}
2807252884aeSStefan Eßer 
280844d4804dSStefan Eßer 		// Print the digits in the buffer.
280978bc019dSStefan Eßer 		for (j = BC_BASE_DIGS - 1; j < BC_BASE_DIGS && j >= temp; --j)
281078bc019dSStefan Eßer 		{
281144d4804dSStefan Eßer 			// Figure out whether to print the decimal point.
2812252884aeSStefan Eßer 			bool print_rdx = (irdx & (j == BC_BASE_DIGS - 1));
281344d4804dSStefan Eßer 
281444d4804dSStefan Eßer 			// The zero variable helps us skip leading zero digits in the limb.
2815252884aeSStefan Eßer 			zero = (zero && buffer[j] == 0);
281644d4804dSStefan Eßer 
281778bc019dSStefan Eßer 			if (!zero)
281878bc019dSStefan Eßer 			{
281944d4804dSStefan Eßer 				// While the first three arguments should be self-explanatory,
282044d4804dSStefan Eßer 				// the last needs explaining. I don't want to print a newline
282144d4804dSStefan Eßer 				// when the last digit to be printed could take the place of the
282244d4804dSStefan Eßer 				// backslash rather than being pushed, as a single character, to
282344d4804dSStefan Eßer 				// the next line. That's what that last argument does for bc.
282444d4804dSStefan Eßer 				bc_num_printHex(buffer[j], 1, print_rdx,
282544d4804dSStefan Eßer 				                !newline || (j > temp || i != 0));
282644d4804dSStefan Eßer 			}
2827252884aeSStefan Eßer 		}
2828252884aeSStefan Eßer 	}
2829252884aeSStefan Eßer }
2830252884aeSStefan Eßer 
2831252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
2832252884aeSStefan Eßer 
283344d4804dSStefan Eßer /**
283444d4804dSStefan Eßer  * Prints a number in scientific or engineering format. When doing this, we are
283544d4804dSStefan Eßer  * always printing in decimal.
283644d4804dSStefan Eßer  * @param n        The number to print.
283744d4804dSStefan Eßer  * @param eng      True if we are in engineering mode.
283844d4804dSStefan Eßer  * @param newline  Whether to print backslash+newlines on long enough lines.
283944d4804dSStefan Eßer  */
284078bc019dSStefan Eßer static void
284178bc019dSStefan Eßer bc_num_printExponent(const BcNum* restrict n, bool eng, bool newline)
284244d4804dSStefan Eßer {
284350696a6eSStefan Eßer 	size_t places, mod, nrdx = BC_NUM_RDX_VAL(n);
284450696a6eSStefan Eßer 	bool neg = (n->len <= nrdx);
2845252884aeSStefan Eßer 	BcNum temp, exp;
2846252884aeSStefan Eßer 	BcDig digs[BC_NUM_BIGDIG_LOG10];
2847d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2848d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
2849d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2850252884aeSStefan Eßer 
2851252884aeSStefan Eßer 	BC_SIG_LOCK;
2852252884aeSStefan Eßer 
2853252884aeSStefan Eßer 	bc_num_createCopy(&temp, n);
2854252884aeSStefan Eßer 
2855d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, exit);
2856252884aeSStefan Eßer 
2857252884aeSStefan Eßer 	BC_SIG_UNLOCK;
2858252884aeSStefan Eßer 
285944d4804dSStefan Eßer 	// We need to calculate the exponents, and they change based on whether the
286044d4804dSStefan Eßer 	// number is all fractional or not, obviously.
286178bc019dSStefan Eßer 	if (neg)
286278bc019dSStefan Eßer 	{
286344d4804dSStefan Eßer 		// Figure out how many limbs after the decimal point is zero.
286444d4804dSStefan Eßer 		size_t i, idx = bc_num_nonZeroLen(n) - 1;
2865252884aeSStefan Eßer 
2866252884aeSStefan Eßer 		places = 1;
2867252884aeSStefan Eßer 
286844d4804dSStefan Eßer 		// Figure out how much in the last limb is zero.
286978bc019dSStefan Eßer 		for (i = BC_BASE_DIGS - 1; i < BC_BASE_DIGS; --i)
287078bc019dSStefan Eßer 		{
2871252884aeSStefan Eßer 			if (bc_num_pow10[i] > (BcBigDig) n->num[idx]) places += 1;
2872252884aeSStefan Eßer 			else break;
2873252884aeSStefan Eßer 		}
2874252884aeSStefan Eßer 
287544d4804dSStefan Eßer 		// Calculate the combination of zero limbs and zero digits in the last
287644d4804dSStefan Eßer 		// limb.
287750696a6eSStefan Eßer 		places += (nrdx - (idx + 1)) * BC_BASE_DIGS;
2878252884aeSStefan Eßer 		mod = places % 3;
2879252884aeSStefan Eßer 
288044d4804dSStefan Eßer 		// Calculate places if we are in engineering mode.
2881252884aeSStefan Eßer 		if (eng && mod != 0) places += 3 - mod;
288244d4804dSStefan Eßer 
288344d4804dSStefan Eßer 		// Shift the temp to the right place.
2884252884aeSStefan Eßer 		bc_num_shiftLeft(&temp, places);
2885252884aeSStefan Eßer 	}
288678bc019dSStefan Eßer 	else
288778bc019dSStefan Eßer 	{
288844d4804dSStefan Eßer 		// This is the number of digits that we are supposed to put behind the
288944d4804dSStefan Eßer 		// decimal point.
2890252884aeSStefan Eßer 		places = bc_num_intDigits(n) - 1;
289144d4804dSStefan Eßer 
289244d4804dSStefan Eßer 		// Calculate the true number based on whether engineering mode is
289344d4804dSStefan Eßer 		// activated.
2894252884aeSStefan Eßer 		mod = places % 3;
2895252884aeSStefan Eßer 		if (eng && mod != 0) places -= 3 - (3 - mod);
289644d4804dSStefan Eßer 
289744d4804dSStefan Eßer 		// Shift the temp to the right place.
2898252884aeSStefan Eßer 		bc_num_shiftRight(&temp, places);
2899252884aeSStefan Eßer 	}
2900252884aeSStefan Eßer 
290144d4804dSStefan Eßer 	// Print the shifted number.
290244d4804dSStefan Eßer 	bc_num_printDecimal(&temp, newline);
2903252884aeSStefan Eßer 
290444d4804dSStefan Eßer 	// Print the e.
290544d4804dSStefan Eßer 	bc_num_putchar('e', !newline);
290644d4804dSStefan Eßer 
290744d4804dSStefan Eßer 	// Need to explicitly print a zero exponent.
290878bc019dSStefan Eßer 	if (!places)
290978bc019dSStefan Eßer 	{
291044d4804dSStefan Eßer 		bc_num_printHex(0, 1, false, !newline);
2911252884aeSStefan Eßer 		goto exit;
2912252884aeSStefan Eßer 	}
2913252884aeSStefan Eßer 
291444d4804dSStefan Eßer 	// Need to print sign for the exponent.
291544d4804dSStefan Eßer 	if (neg) bc_num_putchar('-', true);
2916252884aeSStefan Eßer 
291744d4804dSStefan Eßer 	// Create a temporary for the exponent...
2918252884aeSStefan Eßer 	bc_num_setup(&exp, digs, BC_NUM_BIGDIG_LOG10);
2919252884aeSStefan Eßer 	bc_num_bigdig2num(&exp, (BcBigDig) places);
2920252884aeSStefan Eßer 
292144d4804dSStefan Eßer 	/// ..and print it.
292244d4804dSStefan Eßer 	bc_num_printDecimal(&exp, newline);
2923252884aeSStefan Eßer 
2924252884aeSStefan Eßer exit:
2925252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
2926252884aeSStefan Eßer 	bc_num_free(&temp);
2927d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
2928252884aeSStefan Eßer }
2929252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
2930252884aeSStefan Eßer 
293144d4804dSStefan Eßer /**
2932*aa339f1dSStefan Eßer  * Takes a number with limbs with base BC_BASE_POW and converts the limb at the
2933*aa339f1dSStefan Eßer  * given index to base @a pow, where @a pow is obase^N.
293444d4804dSStefan Eßer  * @param n    The number to convert.
293544d4804dSStefan Eßer  * @param rem  BC_BASE_POW - @a pow.
293644d4804dSStefan Eßer  * @param pow  The power of obase we will convert the number to.
293744d4804dSStefan Eßer  * @param idx  The index of the number to start converting at. Doing the
293844d4804dSStefan Eßer  *             conversion is O(n^2); we have to sweep through starting at the
2939*aa339f1dSStefan Eßer  *             least significant limb.
294044d4804dSStefan Eßer  */
294178bc019dSStefan Eßer static void
294278bc019dSStefan Eßer bc_num_printFixup(BcNum* restrict n, BcBigDig rem, BcBigDig pow, size_t idx)
2943252884aeSStefan Eßer {
2944252884aeSStefan Eßer 	size_t i, len = n->len - idx;
2945252884aeSStefan Eßer 	BcBigDig acc;
2946252884aeSStefan Eßer 	BcDig* a = n->num + idx;
2947252884aeSStefan Eßer 
294844d4804dSStefan Eßer 	// Ignore if there's just one limb left. This is the part that requires the
294944d4804dSStefan Eßer 	// extra loop after the one calling this function in bc_num_printPrepare().
2950252884aeSStefan Eßer 	if (len < 2) return;
2951252884aeSStefan Eßer 
295244d4804dSStefan Eßer 	// Loop through the remaining limbs and convert. We start at the second limb
295344d4804dSStefan Eßer 	// because we pull the value from the previous one as well.
295478bc019dSStefan Eßer 	for (i = len - 1; i > 0; --i)
295578bc019dSStefan Eßer 	{
295644d4804dSStefan Eßer 		// Get the limb and add it to the previous, along with multiplying by
295744d4804dSStefan Eßer 		// the remainder because that's the proper overflow. "acc" means
295844d4804dSStefan Eßer 		// "accumulator," by the way.
2959252884aeSStefan Eßer 		acc = ((BcBigDig) a[i]) * rem + ((BcBigDig) a[i - 1]);
296044d4804dSStefan Eßer 
296144d4804dSStefan Eßer 		// Store a value in base pow in the previous limb.
2962252884aeSStefan Eßer 		a[i - 1] = (BcDig) (acc % pow);
296344d4804dSStefan Eßer 
296444d4804dSStefan Eßer 		// Divide by the base and accumulate the remaining value in the limb.
2965252884aeSStefan Eßer 		acc /= pow;
2966252884aeSStefan Eßer 		acc += (BcBigDig) a[i];
2967252884aeSStefan Eßer 
296844d4804dSStefan Eßer 		// If the accumulator is greater than the base...
296978bc019dSStefan Eßer 		if (acc >= BC_BASE_POW)
297078bc019dSStefan Eßer 		{
297144d4804dSStefan Eßer 			// Do we need to grow?
297278bc019dSStefan Eßer 			if (i == len - 1)
297378bc019dSStefan Eßer 			{
297444d4804dSStefan Eßer 				// Grow.
2975252884aeSStefan Eßer 				len = bc_vm_growSize(len, 1);
2976252884aeSStefan Eßer 				bc_num_expand(n, bc_vm_growSize(len, idx));
297744d4804dSStefan Eßer 
297844d4804dSStefan Eßer 				// Update the pointer because it may have moved.
2979252884aeSStefan Eßer 				a = n->num + idx;
298044d4804dSStefan Eßer 
298144d4804dSStefan Eßer 				// Zero out the last limb.
2982252884aeSStefan Eßer 				a[len - 1] = 0;
2983252884aeSStefan Eßer 			}
2984252884aeSStefan Eßer 
298544d4804dSStefan Eßer 			// Overflow into the next limb since we are over the base.
2986252884aeSStefan Eßer 			a[i + 1] += acc / BC_BASE_POW;
2987252884aeSStefan Eßer 			acc %= BC_BASE_POW;
2988252884aeSStefan Eßer 		}
2989252884aeSStefan Eßer 
2990252884aeSStefan Eßer 		assert(acc < BC_BASE_POW);
299144d4804dSStefan Eßer 
299244d4804dSStefan Eßer 		// Set the limb.
2993252884aeSStefan Eßer 		a[i] = (BcDig) acc;
2994252884aeSStefan Eßer 	}
2995252884aeSStefan Eßer 
299644d4804dSStefan Eßer 	// We may have grown the number, so adjust the length.
2997252884aeSStefan Eßer 	n->len = len + idx;
2998252884aeSStefan Eßer }
2999252884aeSStefan Eßer 
300044d4804dSStefan Eßer /**
3001*aa339f1dSStefan Eßer  * Prepares a number for printing in a base that does not have BC_BASE_POW as a
3002*aa339f1dSStefan Eßer  * power. This basically converts the number from having limbs of base
300344d4804dSStefan Eßer  * BC_BASE_POW to limbs of pow, where pow is obase^N.
300444d4804dSStefan Eßer  * @param n    The number to prepare for printing.
300544d4804dSStefan Eßer  * @param rem  The remainder of BC_BASE_POW when divided by a power of the base.
300644d4804dSStefan Eßer  * @param pow  The power of the base.
300744d4804dSStefan Eßer  */
300878bc019dSStefan Eßer static void
300978bc019dSStefan Eßer bc_num_printPrepare(BcNum* restrict n, BcBigDig rem, BcBigDig pow)
301078bc019dSStefan Eßer {
3011252884aeSStefan Eßer 	size_t i;
3012252884aeSStefan Eßer 
301344d4804dSStefan Eßer 	// Loop from the least significant limb to the most significant limb and
301444d4804dSStefan Eßer 	// convert limbs in each pass.
301578bc019dSStefan Eßer 	for (i = 0; i < n->len; ++i)
301678bc019dSStefan Eßer 	{
301778bc019dSStefan Eßer 		bc_num_printFixup(n, rem, pow, i);
301878bc019dSStefan Eßer 	}
3019252884aeSStefan Eßer 
302044d4804dSStefan Eßer 	// bc_num_printFixup() does not do everything it is supposed to, so we do
302144d4804dSStefan Eßer 	// the last bit of cleanup here. That cleanup is to ensure that each limb
302244d4804dSStefan Eßer 	// is less than pow and to expand the number to fit new limbs as necessary.
302378bc019dSStefan Eßer 	for (i = 0; i < n->len; ++i)
302478bc019dSStefan Eßer 	{
3025252884aeSStefan Eßer 		assert(pow == ((BcBigDig) ((BcDig) pow)));
3026252884aeSStefan Eßer 
302744d4804dSStefan Eßer 		// If the limb needs fixing...
302878bc019dSStefan Eßer 		if (n->num[i] >= (BcDig) pow)
302978bc019dSStefan Eßer 		{
303044d4804dSStefan Eßer 			// Do we need to grow?
303178bc019dSStefan Eßer 			if (i + 1 == n->len)
303278bc019dSStefan Eßer 			{
303344d4804dSStefan Eßer 				// Grow the number.
3034252884aeSStefan Eßer 				n->len = bc_vm_growSize(n->len, 1);
3035252884aeSStefan Eßer 				bc_num_expand(n, n->len);
303644d4804dSStefan Eßer 
303744d4804dSStefan Eßer 				// Without this, we might use uninitialized data.
3038252884aeSStefan Eßer 				n->num[i + 1] = 0;
3039252884aeSStefan Eßer 			}
3040252884aeSStefan Eßer 
3041252884aeSStefan Eßer 			assert(pow < BC_BASE_POW);
304244d4804dSStefan Eßer 
304344d4804dSStefan Eßer 			// Overflow into the next limb.
3044252884aeSStefan Eßer 			n->num[i + 1] += n->num[i] / ((BcDig) pow);
3045252884aeSStefan Eßer 			n->num[i] %= (BcDig) pow;
3046252884aeSStefan Eßer 		}
3047252884aeSStefan Eßer 	}
3048252884aeSStefan Eßer }
3049252884aeSStefan Eßer 
305078bc019dSStefan Eßer static void
305178bc019dSStefan Eßer bc_num_printNum(BcNum* restrict n, BcBigDig base, size_t len,
305244d4804dSStefan Eßer                 BcNumDigitOp print, bool newline)
3053252884aeSStefan Eßer {
3054252884aeSStefan Eßer 	BcVec stack;
305578bc019dSStefan Eßer 	BcNum intp, fracp1, fracp2, digit, flen1, flen2;
305678bc019dSStefan Eßer 	BcNum* n1;
305778bc019dSStefan Eßer 	BcNum* n2;
305878bc019dSStefan Eßer 	BcNum* temp;
305978bc019dSStefan Eßer 	BcBigDig dig = 0, acc, exp;
306078bc019dSStefan Eßer 	BcBigDig* ptr;
306144d4804dSStefan Eßer 	size_t i, j, nrdx, idigits;
3062252884aeSStefan Eßer 	bool radix;
3063252884aeSStefan Eßer 	BcDig digit_digs[BC_NUM_BIGDIG_LOG10 + 1];
3064d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3065d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
3066d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3067252884aeSStefan Eßer 
3068252884aeSStefan Eßer 	assert(base > 1);
3069252884aeSStefan Eßer 
307044d4804dSStefan Eßer 	// Easy case. Even with scale, we just print this.
307178bc019dSStefan Eßer 	if (BC_NUM_ZERO(n))
307278bc019dSStefan Eßer 	{
307344d4804dSStefan Eßer 		print(0, len, false, !newline);
3074252884aeSStefan Eßer 		return;
3075252884aeSStefan Eßer 	}
3076252884aeSStefan Eßer 
3077252884aeSStefan Eßer 	// This function uses an algorithm that Stefan Esser <se@freebsd.org> came
3078252884aeSStefan Eßer 	// up with to print the integer part of a number. What it does is convert
3079252884aeSStefan Eßer 	// intp into a number of the specified base, but it does it directly,
3080252884aeSStefan Eßer 	// instead of just doing a series of divisions and printing the remainders
3081252884aeSStefan Eßer 	// in reverse order.
3082252884aeSStefan Eßer 	//
3083252884aeSStefan Eßer 	// Let me explain in a bit more detail:
3084252884aeSStefan Eßer 	//
308544d4804dSStefan Eßer 	// The algorithm takes the current least significant limb (after intp has
308644d4804dSStefan Eßer 	// been converted to an integer) and the next to least significant limb, and
308744d4804dSStefan Eßer 	// it converts the least significant limb into one of the specified base,
308844d4804dSStefan Eßer 	// putting any overflow into the next to least significant limb. It iterates
308944d4804dSStefan Eßer 	// through the whole number, from least significant to most significant,
309044d4804dSStefan Eßer 	// doing this conversion. At the end of that iteration, the least
309144d4804dSStefan Eßer 	// significant limb is converted, but the others are not, so it iterates
309244d4804dSStefan Eßer 	// again, starting at the next to least significant limb. It keeps doing
309344d4804dSStefan Eßer 	// that conversion, skipping one more limb than the last time, until all
309444d4804dSStefan Eßer 	// limbs have been converted. Then it prints them in reverse order.
3095252884aeSStefan Eßer 	//
3096252884aeSStefan Eßer 	// That is the gist of the algorithm. It leaves out several things, such as
309744d4804dSStefan Eßer 	// the fact that limbs are not always converted into the specified base, but
309844d4804dSStefan Eßer 	// into something close, basically a power of the specified base. In
3099252884aeSStefan Eßer 	// Stefan's words, "You could consider BcDigs to be of base 10^BC_BASE_DIGS
3100252884aeSStefan Eßer 	// in the normal case and obase^N for the largest value of N that satisfies
3101252884aeSStefan Eßer 	// obase^N <= 10^BC_BASE_DIGS. [This means that] the result is not in base
3102252884aeSStefan Eßer 	// "obase", but in base "obase^N", which happens to be printable as a number
3103252884aeSStefan Eßer 	// of base "obase" without consideration for neighbouring BcDigs." This fact
3104252884aeSStefan Eßer 	// is what necessitates the existence of the loop later in this function.
3105252884aeSStefan Eßer 	//
3106252884aeSStefan Eßer 	// The conversion happens in bc_num_printPrepare() where the outer loop
3107252884aeSStefan Eßer 	// happens and bc_num_printFixup() where the inner loop, or actual
310844d4804dSStefan Eßer 	// conversion, happens. In other words, bc_num_printPrepare() is where the
310944d4804dSStefan Eßer 	// loop that starts at the least significant limb and goes to the most
311044d4804dSStefan Eßer 	// significant limb. Then, on every iteration of its loop, it calls
311144d4804dSStefan Eßer 	// bc_num_printFixup(), which has the inner loop of actually converting
311244d4804dSStefan Eßer 	// the limbs it passes into limbs of base obase^N rather than base
311344d4804dSStefan Eßer 	// BC_BASE_POW.
3114252884aeSStefan Eßer 
311550696a6eSStefan Eßer 	nrdx = BC_NUM_RDX_VAL(n);
311650696a6eSStefan Eßer 
3117252884aeSStefan Eßer 	BC_SIG_LOCK;
3118252884aeSStefan Eßer 
311944d4804dSStefan Eßer 	// The stack is what allows us to reverse the digits for printing.
312044d4804dSStefan Eßer 	bc_vec_init(&stack, sizeof(BcBigDig), BC_DTOR_NONE);
312150696a6eSStefan Eßer 	bc_num_init(&fracp1, nrdx);
3122252884aeSStefan Eßer 
312344d4804dSStefan Eßer 	// intp will be the "integer part" of the number, so copy it.
3124252884aeSStefan Eßer 	bc_num_createCopy(&intp, n);
3125252884aeSStefan Eßer 
3126d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
3127252884aeSStefan Eßer 
3128252884aeSStefan Eßer 	BC_SIG_UNLOCK;
3129252884aeSStefan Eßer 
313044d4804dSStefan Eßer 	// Make intp an integer.
3131252884aeSStefan Eßer 	bc_num_truncate(&intp, intp.scale);
3132252884aeSStefan Eßer 
313344d4804dSStefan Eßer 	// Get the fractional part out.
3134252884aeSStefan Eßer 	bc_num_sub(n, &intp, &fracp1, 0);
3135252884aeSStefan Eßer 
313644d4804dSStefan Eßer 	// If the base is not the same as the last base used for printing, we need
313744d4804dSStefan Eßer 	// to update the cached exponent and power. Yes, we cache the values of the
313844d4804dSStefan Eßer 	// exponent and power. That is to prevent us from calculating them every
313944d4804dSStefan Eßer 	// time because printing will probably happen multiple times on the same
314044d4804dSStefan Eßer 	// base.
3141d101cdd6SStefan Eßer 	if (base != vm->last_base)
314278bc019dSStefan Eßer 	{
3143d101cdd6SStefan Eßer 		vm->last_pow = 1;
3144d101cdd6SStefan Eßer 		vm->last_exp = 0;
3145252884aeSStefan Eßer 
314644d4804dSStefan Eßer 		// Calculate the exponent and power.
3147d101cdd6SStefan Eßer 		while (vm->last_pow * base <= BC_BASE_POW)
314878bc019dSStefan Eßer 		{
3149d101cdd6SStefan Eßer 			vm->last_pow *= base;
3150d101cdd6SStefan Eßer 			vm->last_exp += 1;
3151252884aeSStefan Eßer 		}
3152252884aeSStefan Eßer 
315344d4804dSStefan Eßer 		// Also, the remainder and base itself.
3154d101cdd6SStefan Eßer 		vm->last_rem = BC_BASE_POW - vm->last_pow;
3155d101cdd6SStefan Eßer 		vm->last_base = base;
3156252884aeSStefan Eßer 	}
3157252884aeSStefan Eßer 
3158d101cdd6SStefan Eßer 	exp = vm->last_exp;
3159252884aeSStefan Eßer 
3160d101cdd6SStefan Eßer 	// If vm->last_rem is 0, then the base we are printing in is a divisor of
316144d4804dSStefan Eßer 	// BC_BASE_POW, which is the easy case because it means that BC_BASE_POW is
316244d4804dSStefan Eßer 	// a power of obase, and no conversion is needed. If it *is* 0, then we have
316344d4804dSStefan Eßer 	// the hard case, and we have to prepare the number for the base.
3164d101cdd6SStefan Eßer 	if (vm->last_rem != 0)
3165d101cdd6SStefan Eßer 	{
3166d101cdd6SStefan Eßer 		bc_num_printPrepare(&intp, vm->last_rem, vm->last_pow);
3167d101cdd6SStefan Eßer 	}
3168252884aeSStefan Eßer 
316944d4804dSStefan Eßer 	// After the conversion comes the surprisingly easy part. From here on out,
317044d4804dSStefan Eßer 	// this is basically naive code that I wrote, adjusted for the larger bases.
317144d4804dSStefan Eßer 
317244d4804dSStefan Eßer 	// Fill the stack of digits for the integer part.
317378bc019dSStefan Eßer 	for (i = 0; i < intp.len; ++i)
317478bc019dSStefan Eßer 	{
317544d4804dSStefan Eßer 		// Get the limb.
3176252884aeSStefan Eßer 		acc = (BcBigDig) intp.num[i];
3177252884aeSStefan Eßer 
317844d4804dSStefan Eßer 		// Turn the limb into digits of base obase.
3179252884aeSStefan Eßer 		for (j = 0; j < exp && (i < intp.len - 1 || acc != 0); ++j)
3180252884aeSStefan Eßer 		{
318144d4804dSStefan Eßer 			// This condition is true if we are not at the last digit.
318278bc019dSStefan Eßer 			if (j != exp - 1)
318378bc019dSStefan Eßer 			{
3184252884aeSStefan Eßer 				dig = acc % base;
3185252884aeSStefan Eßer 				acc /= base;
3186252884aeSStefan Eßer 			}
318778bc019dSStefan Eßer 			else
318878bc019dSStefan Eßer 			{
3189252884aeSStefan Eßer 				dig = acc;
3190252884aeSStefan Eßer 				acc = 0;
3191252884aeSStefan Eßer 			}
3192252884aeSStefan Eßer 
3193252884aeSStefan Eßer 			assert(dig < base);
3194252884aeSStefan Eßer 
319544d4804dSStefan Eßer 			// Push the digit onto the stack.
3196252884aeSStefan Eßer 			bc_vec_push(&stack, &dig);
3197252884aeSStefan Eßer 		}
3198252884aeSStefan Eßer 
3199252884aeSStefan Eßer 		assert(acc == 0);
3200252884aeSStefan Eßer 	}
3201252884aeSStefan Eßer 
320244d4804dSStefan Eßer 	// Go through the stack backwards and print each digit.
320378bc019dSStefan Eßer 	for (i = 0; i < stack.len; ++i)
320478bc019dSStefan Eßer 	{
3205252884aeSStefan Eßer 		ptr = bc_vec_item_rev(&stack, i);
320644d4804dSStefan Eßer 
3207252884aeSStefan Eßer 		assert(ptr != NULL);
320844d4804dSStefan Eßer 
320944d4804dSStefan Eßer 		// While the first three arguments should be self-explanatory, the last
321044d4804dSStefan Eßer 		// needs explaining. I don't want to print a newline when the last digit
321144d4804dSStefan Eßer 		// to be printed could take the place of the backslash rather than being
321244d4804dSStefan Eßer 		// pushed, as a single character, to the next line. That's what that
321344d4804dSStefan Eßer 		// last argument does for bc.
321478bc019dSStefan Eßer 		print(*ptr, len, false,
321578bc019dSStefan Eßer 		      !newline || (n->scale != 0 || i == stack.len - 1));
3216252884aeSStefan Eßer 	}
3217252884aeSStefan Eßer 
321844d4804dSStefan Eßer 	// We are done if there is no fractional part.
3219252884aeSStefan Eßer 	if (!n->scale) goto err;
3220252884aeSStefan Eßer 
3221252884aeSStefan Eßer 	BC_SIG_LOCK;
3222252884aeSStefan Eßer 
322344d4804dSStefan Eßer 	// Reset the jump because some locals are changing.
3224d101cdd6SStefan Eßer 	BC_UNSETJMP(vm);
3225252884aeSStefan Eßer 
322650696a6eSStefan Eßer 	bc_num_init(&fracp2, nrdx);
3227252884aeSStefan Eßer 	bc_num_setup(&digit, digit_digs, sizeof(digit_digs) / sizeof(BcDig));
3228252884aeSStefan Eßer 	bc_num_init(&flen1, BC_NUM_BIGDIG_LOG10);
3229252884aeSStefan Eßer 	bc_num_init(&flen2, BC_NUM_BIGDIG_LOG10);
3230252884aeSStefan Eßer 
3231d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, frac_err);
3232252884aeSStefan Eßer 
3233252884aeSStefan Eßer 	BC_SIG_UNLOCK;
3234252884aeSStefan Eßer 
3235252884aeSStefan Eßer 	bc_num_one(&flen1);
3236252884aeSStefan Eßer 
3237252884aeSStefan Eßer 	radix = true;
323844d4804dSStefan Eßer 
323944d4804dSStefan Eßer 	// Pointers for easy switching.
3240252884aeSStefan Eßer 	n1 = &flen1;
3241252884aeSStefan Eßer 	n2 = &flen2;
3242252884aeSStefan Eßer 
3243252884aeSStefan Eßer 	fracp2.scale = n->scale;
324450696a6eSStefan Eßer 	BC_NUM_RDX_SET_NP(fracp2, BC_NUM_RDX(fracp2.scale));
3245252884aeSStefan Eßer 
324644d4804dSStefan Eßer 	// As long as we have not reached the scale of the number, keep printing.
324778bc019dSStefan Eßer 	while ((idigits = bc_num_intDigits(n1)) <= n->scale)
324878bc019dSStefan Eßer 	{
324944d4804dSStefan Eßer 		// These numbers will keep growing.
3250252884aeSStefan Eßer 		bc_num_expand(&fracp2, fracp1.len + 1);
3251252884aeSStefan Eßer 		bc_num_mulArray(&fracp1, base, &fracp2);
325250696a6eSStefan Eßer 
325350696a6eSStefan Eßer 		nrdx = BC_NUM_RDX_VAL_NP(fracp2);
325450696a6eSStefan Eßer 
325544d4804dSStefan Eßer 		// Ensure an invariant.
325650696a6eSStefan Eßer 		if (fracp2.len < nrdx) fracp2.len = nrdx;
3257252884aeSStefan Eßer 
3258252884aeSStefan Eßer 		// fracp is guaranteed to be non-negative and small enough.
325944d4804dSStefan Eßer 		dig = bc_num_bigdig2(&fracp2);
3260252884aeSStefan Eßer 
326144d4804dSStefan Eßer 		// Convert the digit to a number and subtract it from the number.
3262252884aeSStefan Eßer 		bc_num_bigdig2num(&digit, dig);
3263252884aeSStefan Eßer 		bc_num_sub(&fracp2, &digit, &fracp1, 0);
3264252884aeSStefan Eßer 
326544d4804dSStefan Eßer 		// While the first three arguments should be self-explanatory, the last
326644d4804dSStefan Eßer 		// needs explaining. I don't want to print a newline when the last digit
326744d4804dSStefan Eßer 		// to be printed could take the place of the backslash rather than being
326844d4804dSStefan Eßer 		// pushed, as a single character, to the next line. That's what that
326944d4804dSStefan Eßer 		// last argument does for bc.
327044d4804dSStefan Eßer 		print(dig, len, radix, !newline || idigits != n->scale);
327144d4804dSStefan Eßer 
327244d4804dSStefan Eßer 		// Update the multipliers.
3273252884aeSStefan Eßer 		bc_num_mulArray(n1, base, n2);
3274252884aeSStefan Eßer 
3275252884aeSStefan Eßer 		radix = false;
327644d4804dSStefan Eßer 
327744d4804dSStefan Eßer 		// Switch.
3278252884aeSStefan Eßer 		temp = n1;
3279252884aeSStefan Eßer 		n1 = n2;
3280252884aeSStefan Eßer 		n2 = temp;
3281252884aeSStefan Eßer 	}
3282252884aeSStefan Eßer 
3283252884aeSStefan Eßer frac_err:
3284252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
3285252884aeSStefan Eßer 	bc_num_free(&flen2);
3286252884aeSStefan Eßer 	bc_num_free(&flen1);
3287252884aeSStefan Eßer 	bc_num_free(&fracp2);
3288252884aeSStefan Eßer err:
3289252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
3290252884aeSStefan Eßer 	bc_num_free(&fracp1);
3291252884aeSStefan Eßer 	bc_num_free(&intp);
3292252884aeSStefan Eßer 	bc_vec_free(&stack);
3293d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
3294252884aeSStefan Eßer }
3295252884aeSStefan Eßer 
329644d4804dSStefan Eßer /**
329744d4804dSStefan Eßer  * Prints a number in the specified base, or rather, figures out which function
329844d4804dSStefan Eßer  * to call to print the number in the specified base and calls it.
329944d4804dSStefan Eßer  * @param n        The number to print.
330044d4804dSStefan Eßer  * @param base     The base to print in.
330144d4804dSStefan Eßer  * @param newline  Whether to print backslash+newlines on long enough lines.
330244d4804dSStefan Eßer  */
330378bc019dSStefan Eßer static void
330478bc019dSStefan Eßer bc_num_printBase(BcNum* restrict n, BcBigDig base, bool newline)
330578bc019dSStefan Eßer {
3306252884aeSStefan Eßer 	size_t width;
3307252884aeSStefan Eßer 	BcNumDigitOp print;
330850696a6eSStefan Eßer 	bool neg = BC_NUM_NEG(n);
3309252884aeSStefan Eßer 
331044d4804dSStefan Eßer 	// Clear the sign because it makes the actual printing easier when we have
331144d4804dSStefan Eßer 	// to do math.
331250696a6eSStefan Eßer 	BC_NUM_NEG_CLR(n);
3313252884aeSStefan Eßer 
331444d4804dSStefan Eßer 	// Bases at hexadecimal and below are printed as one character, larger bases
331544d4804dSStefan Eßer 	// are printed as a series of digits separated by spaces.
331678bc019dSStefan Eßer 	if (base <= BC_NUM_MAX_POSIX_IBASE)
331778bc019dSStefan Eßer 	{
3318252884aeSStefan Eßer 		width = 1;
3319252884aeSStefan Eßer 		print = bc_num_printHex;
3320252884aeSStefan Eßer 	}
332178bc019dSStefan Eßer 	else
332278bc019dSStefan Eßer 	{
3323252884aeSStefan Eßer 		assert(base <= BC_BASE_POW);
3324252884aeSStefan Eßer 		width = bc_num_log10(base - 1);
3325252884aeSStefan Eßer 		print = bc_num_printDigits;
3326252884aeSStefan Eßer 	}
3327252884aeSStefan Eßer 
332844d4804dSStefan Eßer 	// Print.
332944d4804dSStefan Eßer 	bc_num_printNum(n, base, width, print, newline);
333044d4804dSStefan Eßer 
333144d4804dSStefan Eßer 	// Reset the sign.
333250696a6eSStefan Eßer 	n->rdx = BC_NUM_NEG_VAL(n, neg);
3333252884aeSStefan Eßer }
3334252884aeSStefan Eßer 
333544d4804dSStefan Eßer #if !BC_ENABLE_LIBRARY
333644d4804dSStefan Eßer 
333778bc019dSStefan Eßer void
333878bc019dSStefan Eßer bc_num_stream(BcNum* restrict n)
333978bc019dSStefan Eßer {
334044d4804dSStefan Eßer 	bc_num_printNum(n, BC_NUM_STREAM_BASE, 1, bc_num_printChar, false);
3341252884aeSStefan Eßer }
334244d4804dSStefan Eßer 
334344d4804dSStefan Eßer #endif // !BC_ENABLE_LIBRARY
3344252884aeSStefan Eßer 
334578bc019dSStefan Eßer void
334678bc019dSStefan Eßer bc_num_setup(BcNum* restrict n, BcDig* restrict num, size_t cap)
334778bc019dSStefan Eßer {
3348252884aeSStefan Eßer 	assert(n != NULL);
3349252884aeSStefan Eßer 	n->num = num;
3350252884aeSStefan Eßer 	n->cap = cap;
3351252884aeSStefan Eßer 	bc_num_zero(n);
3352252884aeSStefan Eßer }
3353252884aeSStefan Eßer 
335478bc019dSStefan Eßer void
335578bc019dSStefan Eßer bc_num_init(BcNum* restrict n, size_t req)
335678bc019dSStefan Eßer {
3357252884aeSStefan Eßer 	BcDig* num;
3358252884aeSStefan Eßer 
3359252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
3360252884aeSStefan Eßer 
3361252884aeSStefan Eßer 	assert(n != NULL);
3362252884aeSStefan Eßer 
336344d4804dSStefan Eßer 	// BC_NUM_DEF_SIZE is set to be about the smallest allocation size that
336444d4804dSStefan Eßer 	// malloc() returns in practice, so just use it.
3365252884aeSStefan Eßer 	req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
3366252884aeSStefan Eßer 
336744d4804dSStefan Eßer 	// If we can't use a temp, allocate.
3368d101cdd6SStefan Eßer 	if (req != BC_NUM_DEF_SIZE) num = bc_vm_malloc(BC_NUM_SIZE(req));
3369d101cdd6SStefan Eßer 	else
337078bc019dSStefan Eßer 	{
3371d101cdd6SStefan Eßer 		num = bc_vm_getTemp() == NULL ? bc_vm_malloc(BC_NUM_SIZE(req)) :
3372d101cdd6SStefan Eßer 		                                bc_vm_takeTemp();
337378bc019dSStefan Eßer 	}
3374252884aeSStefan Eßer 
3375252884aeSStefan Eßer 	bc_num_setup(n, num, req);
3376252884aeSStefan Eßer }
3377252884aeSStefan Eßer 
337878bc019dSStefan Eßer void
337978bc019dSStefan Eßer bc_num_clear(BcNum* restrict n)
338078bc019dSStefan Eßer {
3381252884aeSStefan Eßer 	n->num = NULL;
3382252884aeSStefan Eßer 	n->cap = 0;
3383252884aeSStefan Eßer }
3384252884aeSStefan Eßer 
338578bc019dSStefan Eßer void
338678bc019dSStefan Eßer bc_num_free(void* num)
338778bc019dSStefan Eßer {
3388252884aeSStefan Eßer 	BcNum* n = (BcNum*) num;
3389252884aeSStefan Eßer 
3390252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
3391252884aeSStefan Eßer 
3392252884aeSStefan Eßer 	assert(n != NULL);
3393252884aeSStefan Eßer 
339444d4804dSStefan Eßer 	if (n->cap == BC_NUM_DEF_SIZE) bc_vm_addTemp(n->num);
3395252884aeSStefan Eßer 	else free(n->num);
3396252884aeSStefan Eßer }
3397252884aeSStefan Eßer 
339878bc019dSStefan Eßer void
339978bc019dSStefan Eßer bc_num_copy(BcNum* d, const BcNum* s)
340078bc019dSStefan Eßer {
3401252884aeSStefan Eßer 	assert(d != NULL && s != NULL);
340244d4804dSStefan Eßer 
3403252884aeSStefan Eßer 	if (d == s) return;
340444d4804dSStefan Eßer 
3405252884aeSStefan Eßer 	bc_num_expand(d, s->len);
3406252884aeSStefan Eßer 	d->len = s->len;
340744d4804dSStefan Eßer 
340844d4804dSStefan Eßer 	// I can just copy directly here because the sign *and* rdx will be
340944d4804dSStefan Eßer 	// properly preserved.
3410252884aeSStefan Eßer 	d->rdx = s->rdx;
3411252884aeSStefan Eßer 	d->scale = s->scale;
341278bc019dSStefan Eßer 	// NOLINTNEXTLINE
3413252884aeSStefan Eßer 	memcpy(d->num, s->num, BC_NUM_SIZE(d->len));
3414252884aeSStefan Eßer }
3415252884aeSStefan Eßer 
341678bc019dSStefan Eßer void
341778bc019dSStefan Eßer bc_num_createCopy(BcNum* d, const BcNum* s)
341878bc019dSStefan Eßer {
3419252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
3420252884aeSStefan Eßer 	bc_num_init(d, s->len);
3421252884aeSStefan Eßer 	bc_num_copy(d, s);
3422252884aeSStefan Eßer }
3423252884aeSStefan Eßer 
342478bc019dSStefan Eßer void
342578bc019dSStefan Eßer bc_num_createFromBigdig(BcNum* restrict n, BcBigDig val)
342678bc019dSStefan Eßer {
3427252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
342850696a6eSStefan Eßer 	bc_num_init(n, BC_NUM_BIGDIG_LOG10);
3429252884aeSStefan Eßer 	bc_num_bigdig2num(n, val);
3430252884aeSStefan Eßer }
3431252884aeSStefan Eßer 
343278bc019dSStefan Eßer size_t
343378bc019dSStefan Eßer bc_num_scale(const BcNum* restrict n)
343478bc019dSStefan Eßer {
3435252884aeSStefan Eßer 	return n->scale;
3436252884aeSStefan Eßer }
3437252884aeSStefan Eßer 
343878bc019dSStefan Eßer size_t
343978bc019dSStefan Eßer bc_num_len(const BcNum* restrict n)
344078bc019dSStefan Eßer {
3441252884aeSStefan Eßer 	size_t len = n->len;
3442252884aeSStefan Eßer 
344344d4804dSStefan Eßer 	// Always return at least 1.
3444028616d0SStefan Eßer 	if (BC_NUM_ZERO(n)) return n->scale ? n->scale : 1;
3445252884aeSStefan Eßer 
344644d4804dSStefan Eßer 	// If this is true, there is no integer portion of the number.
344778bc019dSStefan Eßer 	if (BC_NUM_RDX_VAL(n) == len)
344878bc019dSStefan Eßer 	{
344944d4804dSStefan Eßer 		// We have to take into account the fact that some of the digits right
345044d4804dSStefan Eßer 		// after the decimal could be zero. If that is the case, we need to
345144d4804dSStefan Eßer 		// ignore them until we hit the first non-zero digit.
345244d4804dSStefan Eßer 
3453252884aeSStefan Eßer 		size_t zero, scale;
3454252884aeSStefan Eßer 
345544d4804dSStefan Eßer 		// The number of limbs with non-zero digits.
345644d4804dSStefan Eßer 		len = bc_num_nonZeroLen(n);
3457252884aeSStefan Eßer 
345844d4804dSStefan Eßer 		// Get the number of digits in the last limb.
3459252884aeSStefan Eßer 		scale = n->scale % BC_BASE_DIGS;
3460252884aeSStefan Eßer 		scale = scale ? scale : BC_BASE_DIGS;
3461252884aeSStefan Eßer 
346244d4804dSStefan Eßer 		// Get the number of zero digits.
3463252884aeSStefan Eßer 		zero = bc_num_zeroDigits(n->num + len - 1);
3464252884aeSStefan Eßer 
346544d4804dSStefan Eßer 		// Calculate the true length.
3466252884aeSStefan Eßer 		len = len * BC_BASE_DIGS - zero - (BC_BASE_DIGS - scale);
3467252884aeSStefan Eßer 	}
346844d4804dSStefan Eßer 	// Otherwise, count the number of int digits and return that plus the scale.
3469252884aeSStefan Eßer 	else len = bc_num_intDigits(n) + n->scale;
3470252884aeSStefan Eßer 
3471252884aeSStefan Eßer 	return len;
3472252884aeSStefan Eßer }
3473252884aeSStefan Eßer 
347478bc019dSStefan Eßer void
347578bc019dSStefan Eßer bc_num_parse(BcNum* restrict n, const char* restrict val, BcBigDig base)
347678bc019dSStefan Eßer {
3477103d7cdfSStefan Eßer #if BC_DEBUG
3478d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3479d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
3480d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3481103d7cdfSStefan Eßer #endif // BC_DEBUG
3482d101cdd6SStefan Eßer 
3483252884aeSStefan Eßer 	assert(n != NULL && val != NULL && base);
3484d101cdd6SStefan Eßer 	assert(base >= BC_NUM_MIN_BASE && base <= vm->maxes[BC_PROG_GLOBALS_IBASE]);
3485252884aeSStefan Eßer 	assert(bc_num_strValid(val));
3486252884aeSStefan Eßer 
348744d4804dSStefan Eßer 	// A one character number is *always* parsed as though the base was the
348844d4804dSStefan Eßer 	// maximum allowed ibase, per the bc spec.
348978bc019dSStefan Eßer 	if (!val[1])
349078bc019dSStefan Eßer 	{
3491252884aeSStefan Eßer 		BcBigDig dig = bc_num_parseChar(val[0], BC_NUM_MAX_LBASE);
3492252884aeSStefan Eßer 		bc_num_bigdig2num(n, dig);
3493252884aeSStefan Eßer 	}
3494252884aeSStefan Eßer 	else if (base == BC_BASE) bc_num_parseDecimal(n, val);
3495252884aeSStefan Eßer 	else bc_num_parseBase(n, val, base);
349650696a6eSStefan Eßer 
349750696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(n));
3498252884aeSStefan Eßer }
3499252884aeSStefan Eßer 
350078bc019dSStefan Eßer void
350178bc019dSStefan Eßer bc_num_print(BcNum* restrict n, BcBigDig base, bool newline)
350278bc019dSStefan Eßer {
3503252884aeSStefan Eßer 	assert(n != NULL);
3504252884aeSStefan Eßer 	assert(BC_ENABLE_EXTRA_MATH || base >= BC_NUM_MIN_BASE);
3505252884aeSStefan Eßer 
350644d4804dSStefan Eßer 	// We may need a newline, just to start.
3507252884aeSStefan Eßer 	bc_num_printNewline();
3508252884aeSStefan Eßer 
350978bc019dSStefan Eßer 	if (BC_NUM_NONZERO(n))
351078bc019dSStefan Eßer 	{
3511d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3512d101cdd6SStefan Eßer 		BcVm* vm = bcl_getspecific();
3513d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3514d101cdd6SStefan Eßer 
3515d43fa8efSStefan Eßer 		// Print the sign.
3516d43fa8efSStefan Eßer 		if (BC_NUM_NEG(n)) bc_num_putchar('-', true);
3517d43fa8efSStefan Eßer 
351876238846SStefan Eßer 		// Print the leading zero if necessary. We don't print when using
351976238846SStefan Eßer 		// scientific or engineering modes.
352076238846SStefan Eßer 		if (BC_Z && BC_NUM_RDX_VAL(n) == n->len && base != 0 && base != 1)
352178bc019dSStefan Eßer 		{
3522d43fa8efSStefan Eßer 			bc_num_printHex(0, 1, false, !newline);
3523d43fa8efSStefan Eßer 		}
352478bc019dSStefan Eßer 	}
3525d43fa8efSStefan Eßer 
352644d4804dSStefan Eßer 	// Short-circuit 0.
352744d4804dSStefan Eßer 	if (BC_NUM_ZERO(n)) bc_num_printHex(0, 1, false, !newline);
352844d4804dSStefan Eßer 	else if (base == BC_BASE) bc_num_printDecimal(n, newline);
3529252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
353044d4804dSStefan Eßer 	else if (base == 0 || base == 1)
353178bc019dSStefan Eßer 	{
353244d4804dSStefan Eßer 		bc_num_printExponent(n, base != 0, newline);
353378bc019dSStefan Eßer 	}
3534252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
353544d4804dSStefan Eßer 	else bc_num_printBase(n, base, newline);
3536252884aeSStefan Eßer 
353744d4804dSStefan Eßer 	if (newline) bc_num_putchar('\n', false);
3538252884aeSStefan Eßer }
3539252884aeSStefan Eßer 
354078bc019dSStefan Eßer BcBigDig
354178bc019dSStefan Eßer bc_num_bigdig2(const BcNum* restrict n)
354278bc019dSStefan Eßer {
3543103d7cdfSStefan Eßer #if BC_DEBUG
3544d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3545d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
3546d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3547103d7cdfSStefan Eßer #endif // BC_DEBUG
3548d101cdd6SStefan Eßer 
3549252884aeSStefan Eßer 	// This function returns no errors because it's guaranteed to succeed if
355044d4804dSStefan Eßer 	// its preconditions are met. Those preconditions include both n needs to
3551d101cdd6SStefan Eßer 	// be non-NULL, n being non-negative, and n being less than vm->max. If all
355244d4804dSStefan Eßer 	// of that is true, then we can just convert without worrying about negative
355344d4804dSStefan Eßer 	// errors or overflow.
3554252884aeSStefan Eßer 
3555252884aeSStefan Eßer 	BcBigDig r = 0;
355650696a6eSStefan Eßer 	size_t nrdx = BC_NUM_RDX_VAL(n);
3557252884aeSStefan Eßer 
355844d4804dSStefan Eßer 	assert(n != NULL);
355950696a6eSStefan Eßer 	assert(!BC_NUM_NEG(n));
3560d101cdd6SStefan Eßer 	assert(bc_num_cmp(n, &vm->max) < 0);
356150696a6eSStefan Eßer 	assert(n->len - nrdx <= 3);
3562252884aeSStefan Eßer 
3563252884aeSStefan Eßer 	// There is a small speed win from unrolling the loop here, and since it
3564252884aeSStefan Eßer 	// only adds 53 bytes, I decided that it was worth it.
356578bc019dSStefan Eßer 	switch (n->len - nrdx)
356678bc019dSStefan Eßer 	{
3567252884aeSStefan Eßer 		case 3:
356850696a6eSStefan Eßer 		{
356950696a6eSStefan Eßer 			r = (BcBigDig) n->num[nrdx + 2];
357078bc019dSStefan Eßer 
3571252884aeSStefan Eßer 			// Fallthrough.
357250696a6eSStefan Eßer 			BC_FALLTHROUGH
357378bc019dSStefan Eßer 		}
357450696a6eSStefan Eßer 
3575252884aeSStefan Eßer 		case 2:
357650696a6eSStefan Eßer 		{
357750696a6eSStefan Eßer 			r = r * BC_BASE_POW + (BcBigDig) n->num[nrdx + 1];
357878bc019dSStefan Eßer 
3579252884aeSStefan Eßer 			// Fallthrough.
358050696a6eSStefan Eßer 			BC_FALLTHROUGH
358178bc019dSStefan Eßer 		}
358250696a6eSStefan Eßer 
3583252884aeSStefan Eßer 		case 1:
358450696a6eSStefan Eßer 		{
358550696a6eSStefan Eßer 			r = r * BC_BASE_POW + (BcBigDig) n->num[nrdx];
358650696a6eSStefan Eßer 		}
3587252884aeSStefan Eßer 	}
3588252884aeSStefan Eßer 
358944d4804dSStefan Eßer 	return r;
3590252884aeSStefan Eßer }
3591252884aeSStefan Eßer 
359278bc019dSStefan Eßer BcBigDig
359378bc019dSStefan Eßer bc_num_bigdig(const BcNum* restrict n)
359478bc019dSStefan Eßer {
3595d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3596d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
3597d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3598d101cdd6SStefan Eßer 
359944d4804dSStefan Eßer 	assert(n != NULL);
3600252884aeSStefan Eßer 
360144d4804dSStefan Eßer 	// This error checking is extremely important, and if you do not have a
360244d4804dSStefan Eßer 	// guarantee that converting a number will always succeed in a particular
360344d4804dSStefan Eßer 	// case, you *must* call this function to get these error checks. This
360444d4804dSStefan Eßer 	// includes all instances of numbers inputted by the user or calculated by
360544d4804dSStefan Eßer 	// the user. Otherwise, you can call the faster bc_num_bigdig2().
360644d4804dSStefan Eßer 	if (BC_ERR(BC_NUM_NEG(n))) bc_err(BC_ERR_MATH_NEGATIVE);
3607d101cdd6SStefan Eßer 	if (BC_ERR(bc_num_cmp(n, &vm->max) >= 0)) bc_err(BC_ERR_MATH_OVERFLOW);
3608252884aeSStefan Eßer 
360944d4804dSStefan Eßer 	return bc_num_bigdig2(n);
3610252884aeSStefan Eßer }
3611252884aeSStefan Eßer 
361278bc019dSStefan Eßer void
361378bc019dSStefan Eßer bc_num_bigdig2num(BcNum* restrict n, BcBigDig val)
361478bc019dSStefan Eßer {
3615252884aeSStefan Eßer 	BcDig* ptr;
3616252884aeSStefan Eßer 	size_t i;
3617252884aeSStefan Eßer 
3618252884aeSStefan Eßer 	assert(n != NULL);
3619252884aeSStefan Eßer 
3620252884aeSStefan Eßer 	bc_num_zero(n);
3621252884aeSStefan Eßer 
362244d4804dSStefan Eßer 	// Already 0.
3623252884aeSStefan Eßer 	if (!val) return;
3624252884aeSStefan Eßer 
362544d4804dSStefan Eßer 	// Expand first. This is the only way this function can fail, and it's a
362644d4804dSStefan Eßer 	// fatal error.
3627252884aeSStefan Eßer 	bc_num_expand(n, BC_NUM_BIGDIG_LOG10);
3628252884aeSStefan Eßer 
362944d4804dSStefan Eßer 	// The conversion is easy because numbers are laid out in little-endian
363044d4804dSStefan Eßer 	// order.
3631252884aeSStefan Eßer 	for (ptr = n->num, i = 0; val; ++i, val /= BC_BASE_POW)
363278bc019dSStefan Eßer 	{
3633252884aeSStefan Eßer 		ptr[i] = val % BC_BASE_POW;
363478bc019dSStefan Eßer 	}
3635252884aeSStefan Eßer 
3636252884aeSStefan Eßer 	n->len = i;
3637252884aeSStefan Eßer }
3638252884aeSStefan Eßer 
363944d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
364044d4804dSStefan Eßer 
364178bc019dSStefan Eßer void
364278bc019dSStefan Eßer bc_num_rng(const BcNum* restrict n, BcRNG* rng)
364378bc019dSStefan Eßer {
364450696a6eSStefan Eßer 	BcNum temp, temp2, intn, frac;
3645252884aeSStefan Eßer 	BcRand state1, state2, inc1, inc2;
364650696a6eSStefan Eßer 	size_t nrdx = BC_NUM_RDX_VAL(n);
3647d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3648d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
3649d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3650252884aeSStefan Eßer 
365144d4804dSStefan Eßer 	// This function holds the secret of how I interpret a seed number for the
365244d4804dSStefan Eßer 	// PRNG. Well, it's actually in the development manual
365344d4804dSStefan Eßer 	// (manuals/development.md#pseudo-random-number-generator), so look there
365444d4804dSStefan Eßer 	// before you try to understand this.
365544d4804dSStefan Eßer 
3656252884aeSStefan Eßer 	BC_SIG_LOCK;
3657252884aeSStefan Eßer 
3658252884aeSStefan Eßer 	bc_num_init(&temp, n->len);
3659252884aeSStefan Eßer 	bc_num_init(&temp2, n->len);
366050696a6eSStefan Eßer 	bc_num_init(&frac, nrdx);
3661252884aeSStefan Eßer 	bc_num_init(&intn, bc_num_int(n));
3662252884aeSStefan Eßer 
3663d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
3664252884aeSStefan Eßer 
3665252884aeSStefan Eßer 	BC_SIG_UNLOCK;
3666252884aeSStefan Eßer 
3667d101cdd6SStefan Eßer 	assert(BC_NUM_RDX_VALID_NP(vm->max));
3668252884aeSStefan Eßer 
366978bc019dSStefan Eßer 	// NOLINTNEXTLINE
367050696a6eSStefan Eßer 	memcpy(frac.num, n->num, BC_NUM_SIZE(nrdx));
367150696a6eSStefan Eßer 	frac.len = nrdx;
367250696a6eSStefan Eßer 	BC_NUM_RDX_SET_NP(frac, nrdx);
3673252884aeSStefan Eßer 	frac.scale = n->scale;
3674252884aeSStefan Eßer 
367550696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID_NP(frac));
3676d101cdd6SStefan Eßer 	assert(BC_NUM_RDX_VALID_NP(vm->max2));
367750696a6eSStefan Eßer 
367844d4804dSStefan Eßer 	// Multiply the fraction and truncate so that it's an integer. The
367944d4804dSStefan Eßer 	// truncation is what clamps it, by the way.
3680d101cdd6SStefan Eßer 	bc_num_mul(&frac, &vm->max2, &temp, 0);
3681252884aeSStefan Eßer 	bc_num_truncate(&temp, temp.scale);
3682252884aeSStefan Eßer 	bc_num_copy(&frac, &temp);
3683252884aeSStefan Eßer 
368444d4804dSStefan Eßer 	// Get the integer.
368578bc019dSStefan Eßer 	// NOLINTNEXTLINE
368650696a6eSStefan Eßer 	memcpy(intn.num, n->num + nrdx, BC_NUM_SIZE(bc_num_int(n)));
3687252884aeSStefan Eßer 	intn.len = bc_num_int(n);
3688252884aeSStefan Eßer 
3689252884aeSStefan Eßer 	// This assert is here because it has to be true. It is also here to justify
369044d4804dSStefan Eßer 	// some optimizations.
3691d101cdd6SStefan Eßer 	assert(BC_NUM_NONZERO(&vm->max));
3692252884aeSStefan Eßer 
369344d4804dSStefan Eßer 	// If there *was* a fractional part...
369478bc019dSStefan Eßer 	if (BC_NUM_NONZERO(&frac))
369578bc019dSStefan Eßer 	{
369644d4804dSStefan Eßer 		// This divmod splits frac into the two state parts.
3697d101cdd6SStefan Eßer 		bc_num_divmod(&frac, &vm->max, &temp, &temp2, 0);
3698252884aeSStefan Eßer 
3699d101cdd6SStefan Eßer 		// frac is guaranteed to be smaller than vm->max * vm->max (pow).
3700d101cdd6SStefan Eßer 		// This means that when dividing frac by vm->max, as above, the
3701d101cdd6SStefan Eßer 		// quotient and remainder are both guaranteed to be less than vm->max,
3702252884aeSStefan Eßer 		// which means we can use bc_num_bigdig2() here and not worry about
3703252884aeSStefan Eßer 		// overflow.
370444d4804dSStefan Eßer 		state1 = (BcRand) bc_num_bigdig2(&temp2);
370544d4804dSStefan Eßer 		state2 = (BcRand) bc_num_bigdig2(&temp);
3706252884aeSStefan Eßer 	}
3707252884aeSStefan Eßer 	else state1 = state2 = 0;
3708252884aeSStefan Eßer 
370944d4804dSStefan Eßer 	// If there *was* an integer part...
371078bc019dSStefan Eßer 	if (BC_NUM_NONZERO(&intn))
371178bc019dSStefan Eßer 	{
371244d4804dSStefan Eßer 		// This divmod splits intn into the two inc parts.
3713d101cdd6SStefan Eßer 		bc_num_divmod(&intn, &vm->max, &temp, &temp2, 0);
3714252884aeSStefan Eßer 
3715d101cdd6SStefan Eßer 		// Because temp2 is the mod of vm->max, from above, it is guaranteed
3716252884aeSStefan Eßer 		// to be small enough to use bc_num_bigdig2().
371744d4804dSStefan Eßer 		inc1 = (BcRand) bc_num_bigdig2(&temp2);
3718252884aeSStefan Eßer 
371944d4804dSStefan Eßer 		// Clamp the second inc part.
3720d101cdd6SStefan Eßer 		if (bc_num_cmp(&temp, &vm->max) >= 0)
372178bc019dSStefan Eßer 		{
3722252884aeSStefan Eßer 			bc_num_copy(&temp2, &temp);
3723d101cdd6SStefan Eßer 			bc_num_mod(&temp2, &vm->max, &temp, 0);
3724252884aeSStefan Eßer 		}
3725252884aeSStefan Eßer 
3726d101cdd6SStefan Eßer 		// The if statement above ensures that temp is less than vm->max, which
3727252884aeSStefan Eßer 		// means that we can use bc_num_bigdig2() here.
372844d4804dSStefan Eßer 		inc2 = (BcRand) bc_num_bigdig2(&temp);
3729252884aeSStefan Eßer 	}
3730252884aeSStefan Eßer 	else inc1 = inc2 = 0;
3731252884aeSStefan Eßer 
3732252884aeSStefan Eßer 	bc_rand_seed(rng, state1, state2, inc1, inc2);
3733252884aeSStefan Eßer 
3734252884aeSStefan Eßer err:
3735252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
3736252884aeSStefan Eßer 	bc_num_free(&intn);
3737252884aeSStefan Eßer 	bc_num_free(&frac);
3738252884aeSStefan Eßer 	bc_num_free(&temp2);
3739252884aeSStefan Eßer 	bc_num_free(&temp);
3740d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
3741252884aeSStefan Eßer }
3742252884aeSStefan Eßer 
374378bc019dSStefan Eßer void
374478bc019dSStefan Eßer bc_num_createFromRNG(BcNum* restrict n, BcRNG* rng)
374578bc019dSStefan Eßer {
3746252884aeSStefan Eßer 	BcRand s1, s2, i1, i2;
374750696a6eSStefan Eßer 	BcNum conv, temp1, temp2, temp3;
3748252884aeSStefan Eßer 	BcDig temp1_num[BC_RAND_NUM_SIZE], temp2_num[BC_RAND_NUM_SIZE];
3749252884aeSStefan Eßer 	BcDig conv_num[BC_NUM_BIGDIG_LOG10];
3750d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3751d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
3752d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3753252884aeSStefan Eßer 
3754252884aeSStefan Eßer 	BC_SIG_LOCK;
3755252884aeSStefan Eßer 
3756252884aeSStefan Eßer 	bc_num_init(&temp3, 2 * BC_RAND_NUM_SIZE);
3757252884aeSStefan Eßer 
3758d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
3759252884aeSStefan Eßer 
3760252884aeSStefan Eßer 	BC_SIG_UNLOCK;
3761252884aeSStefan Eßer 
3762252884aeSStefan Eßer 	bc_num_setup(&temp1, temp1_num, sizeof(temp1_num) / sizeof(BcDig));
3763252884aeSStefan Eßer 	bc_num_setup(&temp2, temp2_num, sizeof(temp2_num) / sizeof(BcDig));
3764252884aeSStefan Eßer 	bc_num_setup(&conv, conv_num, sizeof(conv_num) / sizeof(BcDig));
3765252884aeSStefan Eßer 
3766252884aeSStefan Eßer 	// This assert is here because it has to be true. It is also here to justify
3767d101cdd6SStefan Eßer 	// the assumption that vm->max is not zero.
3768d101cdd6SStefan Eßer 	assert(BC_NUM_NONZERO(&vm->max));
3769252884aeSStefan Eßer 
377044d4804dSStefan Eßer 	// Because this is true, we can just ignore math errors that would happen
377144d4804dSStefan Eßer 	// otherwise.
3772d101cdd6SStefan Eßer 	assert(BC_NUM_NONZERO(&vm->max2));
3773252884aeSStefan Eßer 
3774252884aeSStefan Eßer 	bc_rand_getRands(rng, &s1, &s2, &i1, &i2);
3775252884aeSStefan Eßer 
377644d4804dSStefan Eßer 	// Put the second piece of state into a number.
3777252884aeSStefan Eßer 	bc_num_bigdig2num(&conv, (BcBigDig) s2);
3778252884aeSStefan Eßer 
377950696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID_NP(conv));
378050696a6eSStefan Eßer 
378144d4804dSStefan Eßer 	// Multiply by max to make room for the first piece of state.
3782d101cdd6SStefan Eßer 	bc_num_mul(&conv, &vm->max, &temp1, 0);
3783252884aeSStefan Eßer 
378444d4804dSStefan Eßer 	// Add in the first piece of state.
3785252884aeSStefan Eßer 	bc_num_bigdig2num(&conv, (BcBigDig) s1);
3786252884aeSStefan Eßer 	bc_num_add(&conv, &temp1, &temp2, 0);
3787252884aeSStefan Eßer 
378844d4804dSStefan Eßer 	// Divide to make it an entirely fractional part.
3789d101cdd6SStefan Eßer 	bc_num_div(&temp2, &vm->max2, &temp3, BC_RAND_STATE_BITS);
3790252884aeSStefan Eßer 
379144d4804dSStefan Eßer 	// Now start on the increment parts. It's the same process without the
379244d4804dSStefan Eßer 	// divide, so put the second piece of increment into a number.
3793252884aeSStefan Eßer 	bc_num_bigdig2num(&conv, (BcBigDig) i2);
3794252884aeSStefan Eßer 
379550696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID_NP(conv));
379650696a6eSStefan Eßer 
379744d4804dSStefan Eßer 	// Multiply by max to make room for the first piece of increment.
3798d101cdd6SStefan Eßer 	bc_num_mul(&conv, &vm->max, &temp1, 0);
3799252884aeSStefan Eßer 
380044d4804dSStefan Eßer 	// Add in the first piece of increment.
3801252884aeSStefan Eßer 	bc_num_bigdig2num(&conv, (BcBigDig) i1);
3802252884aeSStefan Eßer 	bc_num_add(&conv, &temp1, &temp2, 0);
3803252884aeSStefan Eßer 
380444d4804dSStefan Eßer 	// Now add the two together.
3805252884aeSStefan Eßer 	bc_num_add(&temp2, &temp3, n, 0);
3806252884aeSStefan Eßer 
380750696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(n));
380850696a6eSStefan Eßer 
3809252884aeSStefan Eßer err:
3810252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
3811252884aeSStefan Eßer 	bc_num_free(&temp3);
3812d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
3813252884aeSStefan Eßer }
3814252884aeSStefan Eßer 
381578bc019dSStefan Eßer void
381678bc019dSStefan Eßer bc_num_irand(BcNum* restrict a, BcNum* restrict b, BcRNG* restrict rng)
381778bc019dSStefan Eßer {
381844d4804dSStefan Eßer 	BcNum atemp;
381976238846SStefan Eßer 	size_t i;
3820252884aeSStefan Eßer 
3821252884aeSStefan Eßer 	assert(a != b);
3822252884aeSStefan Eßer 
382344d4804dSStefan Eßer 	if (BC_ERR(BC_NUM_NEG(a))) bc_err(BC_ERR_MATH_NEGATIVE);
382444d4804dSStefan Eßer 
382544d4804dSStefan Eßer 	// If either of these are true, then the numbers are integers.
3826252884aeSStefan Eßer 	if (BC_NUM_ZERO(a) || BC_NUM_ONE(a)) return;
3827252884aeSStefan Eßer 
3828d101cdd6SStefan Eßer #if BC_GCC
3829d101cdd6SStefan Eßer 	// This is here in GCC to quiet the "maybe-uninitialized" warning.
3830d101cdd6SStefan Eßer 	atemp.num = NULL;
3831d101cdd6SStefan Eßer 	atemp.len = 0;
3832d101cdd6SStefan Eßer #endif // BC_GCC
3833d101cdd6SStefan Eßer 
383444d4804dSStefan Eßer 	if (BC_ERR(bc_num_nonInt(a, &atemp))) bc_err(BC_ERR_MATH_NON_INTEGER);
3835252884aeSStefan Eßer 
3836d101cdd6SStefan Eßer 	assert(atemp.num != NULL);
383744d4804dSStefan Eßer 	assert(atemp.len);
3838252884aeSStefan Eßer 
383976238846SStefan Eßer 	if (atemp.len > 2)
384076238846SStefan Eßer 	{
384176238846SStefan Eßer 		size_t len;
384276238846SStefan Eßer 
384376238846SStefan Eßer 		len = atemp.len - 2;
3844252884aeSStefan Eßer 
384544d4804dSStefan Eßer 		// Just generate a random number for each limb.
384676238846SStefan Eßer 		for (i = 0; i < len; i += 2)
384778bc019dSStefan Eßer 		{
384876238846SStefan Eßer 			BcRand dig;
384976238846SStefan Eßer 
385076238846SStefan Eßer 			dig = bc_rand_bounded(rng, BC_BASE_RAND_POW);
385176238846SStefan Eßer 
385276238846SStefan Eßer 			b->num[i] = (BcDig) (dig % BC_BASE_POW);
385376238846SStefan Eßer 			b->num[i + 1] = (BcDig) (dig / BC_BASE_POW);
385476238846SStefan Eßer 		}
385576238846SStefan Eßer 	}
385676238846SStefan Eßer 	else
385776238846SStefan Eßer 	{
385876238846SStefan Eßer 		// We need this set.
385976238846SStefan Eßer 		i = 0;
386078bc019dSStefan Eßer 	}
3861252884aeSStefan Eßer 
386276238846SStefan Eßer 	// This will be true if there's one full limb after the two limb groups.
386376238846SStefan Eßer 	if (i == atemp.len - 2)
386476238846SStefan Eßer 	{
386576238846SStefan Eßer 		// Increment this for easy use.
386676238846SStefan Eßer 		i += 1;
386776238846SStefan Eßer 
386876238846SStefan Eßer 		// If the last digit is not one, we need to set a bound for it
386976238846SStefan Eßer 		// explicitly. Since there's still an empty limb, we need to fill that.
387076238846SStefan Eßer 		if (atemp.num[i] != 1)
387176238846SStefan Eßer 		{
387276238846SStefan Eßer 			BcRand dig;
387376238846SStefan Eßer 			BcRand bound;
387476238846SStefan Eßer 
387576238846SStefan Eßer 			// Set the bound to the bound of the last limb times the amount
387676238846SStefan Eßer 			// needed to fill the second-to-last limb as well.
387776238846SStefan Eßer 			bound = ((BcRand) atemp.num[i]) * BC_BASE_POW;
387876238846SStefan Eßer 
387976238846SStefan Eßer 			dig = bc_rand_bounded(rng, bound);
388076238846SStefan Eßer 
388176238846SStefan Eßer 			// Fill the last two.
388276238846SStefan Eßer 			b->num[i - 1] = (BcDig) (dig % BC_BASE_POW);
388376238846SStefan Eßer 			b->num[i] = (BcDig) (dig / BC_BASE_POW);
388476238846SStefan Eßer 
388576238846SStefan Eßer 			// Ensure that the length will be correct. If the last limb is zero,
388676238846SStefan Eßer 			// then the length needs to be one less than the bound.
388776238846SStefan Eßer 			b->len = atemp.len - (b->num[i] == 0);
388876238846SStefan Eßer 		}
388976238846SStefan Eßer 		// Here the last limb *is* one, which means the last limb does *not*
389076238846SStefan Eßer 		// need to be filled. Also, the length needs to be one less because the
389176238846SStefan Eßer 		// last limb is 0.
389276238846SStefan Eßer 		else
389376238846SStefan Eßer 		{
389476238846SStefan Eßer 			b->num[i - 1] = (BcDig) bc_rand_bounded(rng, BC_BASE_POW);
389576238846SStefan Eßer 			b->len = atemp.len - 1;
389676238846SStefan Eßer 		}
389776238846SStefan Eßer 	}
389876238846SStefan Eßer 	// Here, there is only one limb to fill.
389976238846SStefan Eßer 	else
390076238846SStefan Eßer 	{
390176238846SStefan Eßer 		// See above for how this works.
390278bc019dSStefan Eßer 		if (atemp.num[i] != 1)
390378bc019dSStefan Eßer 		{
390444d4804dSStefan Eßer 			b->num[i] = (BcDig) bc_rand_bounded(rng, (BcRand) atemp.num[i]);
390576238846SStefan Eßer 			b->len = atemp.len - (b->num[i] == 0);
3906252884aeSStefan Eßer 		}
390776238846SStefan Eßer 		else b->len = atemp.len - 1;
390876238846SStefan Eßer 	}
3909252884aeSStefan Eßer 
3910252884aeSStefan Eßer 	bc_num_clean(b);
3911252884aeSStefan Eßer 
391250696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
3913252884aeSStefan Eßer }
391444d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
3915252884aeSStefan Eßer 
391678bc019dSStefan Eßer size_t
391778bc019dSStefan Eßer bc_num_addReq(const BcNum* a, const BcNum* b, size_t scale)
391878bc019dSStefan Eßer {
3919252884aeSStefan Eßer 	size_t aint, bint, ardx, brdx;
3920252884aeSStefan Eßer 
392144d4804dSStefan Eßer 	// Addition and subtraction require the max of the length of the two numbers
392244d4804dSStefan Eßer 	// plus 1.
392344d4804dSStefan Eßer 
3924252884aeSStefan Eßer 	BC_UNUSED(scale);
3925252884aeSStefan Eßer 
392650696a6eSStefan Eßer 	ardx = BC_NUM_RDX_VAL(a);
3927252884aeSStefan Eßer 	aint = bc_num_int(a);
3928252884aeSStefan Eßer 	assert(aint <= a->len && ardx <= a->len);
3929252884aeSStefan Eßer 
393050696a6eSStefan Eßer 	brdx = BC_NUM_RDX_VAL(b);
3931252884aeSStefan Eßer 	bint = bc_num_int(b);
3932252884aeSStefan Eßer 	assert(bint <= b->len && brdx <= b->len);
3933252884aeSStefan Eßer 
3934252884aeSStefan Eßer 	ardx = BC_MAX(ardx, brdx);
3935252884aeSStefan Eßer 	aint = BC_MAX(aint, bint);
3936252884aeSStefan Eßer 
3937252884aeSStefan Eßer 	return bc_vm_growSize(bc_vm_growSize(ardx, aint), 1);
3938252884aeSStefan Eßer }
3939252884aeSStefan Eßer 
394078bc019dSStefan Eßer size_t
394178bc019dSStefan Eßer bc_num_mulReq(const BcNum* a, const BcNum* b, size_t scale)
394278bc019dSStefan Eßer {
3943252884aeSStefan Eßer 	size_t max, rdx;
394444d4804dSStefan Eßer 
394544d4804dSStefan Eßer 	// Multiplication requires the sum of the lengths of the numbers.
394644d4804dSStefan Eßer 
394750696a6eSStefan Eßer 	rdx = bc_vm_growSize(BC_NUM_RDX_VAL(a), BC_NUM_RDX_VAL(b));
394844d4804dSStefan Eßer 
3949252884aeSStefan Eßer 	max = BC_NUM_RDX(scale);
395044d4804dSStefan Eßer 
3951252884aeSStefan Eßer 	max = bc_vm_growSize(BC_MAX(max, rdx), 1);
3952252884aeSStefan Eßer 	rdx = bc_vm_growSize(bc_vm_growSize(bc_num_int(a), bc_num_int(b)), max);
395344d4804dSStefan Eßer 
3954252884aeSStefan Eßer 	return rdx;
3955252884aeSStefan Eßer }
3956252884aeSStefan Eßer 
395778bc019dSStefan Eßer size_t
395878bc019dSStefan Eßer bc_num_divReq(const BcNum* a, const BcNum* b, size_t scale)
395978bc019dSStefan Eßer {
396050696a6eSStefan Eßer 	size_t max, rdx;
396144d4804dSStefan Eßer 
396244d4804dSStefan Eßer 	// Division requires the length of the dividend plus the scale.
396344d4804dSStefan Eßer 
396450696a6eSStefan Eßer 	rdx = bc_vm_growSize(BC_NUM_RDX_VAL(a), BC_NUM_RDX_VAL(b));
396544d4804dSStefan Eßer 
396650696a6eSStefan Eßer 	max = BC_NUM_RDX(scale);
396744d4804dSStefan Eßer 
396850696a6eSStefan Eßer 	max = bc_vm_growSize(BC_MAX(max, rdx), 1);
396950696a6eSStefan Eßer 	rdx = bc_vm_growSize(bc_num_int(a), max);
397044d4804dSStefan Eßer 
397150696a6eSStefan Eßer 	return rdx;
397250696a6eSStefan Eßer }
397350696a6eSStefan Eßer 
397478bc019dSStefan Eßer size_t
397578bc019dSStefan Eßer bc_num_powReq(const BcNum* a, const BcNum* b, size_t scale)
397678bc019dSStefan Eßer {
3977252884aeSStefan Eßer 	BC_UNUSED(scale);
3978252884aeSStefan Eßer 	return bc_vm_growSize(bc_vm_growSize(a->len, b->len), 1);
3979252884aeSStefan Eßer }
3980252884aeSStefan Eßer 
3981252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
398278bc019dSStefan Eßer size_t
398378bc019dSStefan Eßer bc_num_placesReq(const BcNum* a, const BcNum* b, size_t scale)
398478bc019dSStefan Eßer {
3985252884aeSStefan Eßer 	BC_UNUSED(scale);
398650696a6eSStefan Eßer 	return a->len + b->len - BC_NUM_RDX_VAL(a) - BC_NUM_RDX_VAL(b);
3987252884aeSStefan Eßer }
3988252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
3989252884aeSStefan Eßer 
399078bc019dSStefan Eßer void
399178bc019dSStefan Eßer bc_num_add(BcNum* a, BcNum* b, BcNum* c, size_t scale)
399278bc019dSStefan Eßer {
399350696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
399450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
3995252884aeSStefan Eßer 	bc_num_binary(a, b, c, false, bc_num_as, bc_num_addReq(a, b, scale));
3996252884aeSStefan Eßer }
3997252884aeSStefan Eßer 
399878bc019dSStefan Eßer void
399978bc019dSStefan Eßer bc_num_sub(BcNum* a, BcNum* b, BcNum* c, size_t scale)
400078bc019dSStefan Eßer {
400150696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
400250696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
4003252884aeSStefan Eßer 	bc_num_binary(a, b, c, true, bc_num_as, bc_num_addReq(a, b, scale));
4004252884aeSStefan Eßer }
4005252884aeSStefan Eßer 
400678bc019dSStefan Eßer void
400778bc019dSStefan Eßer bc_num_mul(BcNum* a, BcNum* b, BcNum* c, size_t scale)
400878bc019dSStefan Eßer {
400950696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
401050696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
4011252884aeSStefan Eßer 	bc_num_binary(a, b, c, scale, bc_num_m, bc_num_mulReq(a, b, scale));
4012252884aeSStefan Eßer }
4013252884aeSStefan Eßer 
401478bc019dSStefan Eßer void
401578bc019dSStefan Eßer bc_num_div(BcNum* a, BcNum* b, BcNum* c, size_t scale)
401678bc019dSStefan Eßer {
401750696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
401850696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
401950696a6eSStefan Eßer 	bc_num_binary(a, b, c, scale, bc_num_d, bc_num_divReq(a, b, scale));
4020252884aeSStefan Eßer }
4021252884aeSStefan Eßer 
402278bc019dSStefan Eßer void
402378bc019dSStefan Eßer bc_num_mod(BcNum* a, BcNum* b, BcNum* c, size_t scale)
402478bc019dSStefan Eßer {
402550696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
402650696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
402750696a6eSStefan Eßer 	bc_num_binary(a, b, c, scale, bc_num_rem, bc_num_divReq(a, b, scale));
4028252884aeSStefan Eßer }
4029252884aeSStefan Eßer 
403078bc019dSStefan Eßer void
403178bc019dSStefan Eßer bc_num_pow(BcNum* a, BcNum* b, BcNum* c, size_t scale)
403278bc019dSStefan Eßer {
403350696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
403450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
4035252884aeSStefan Eßer 	bc_num_binary(a, b, c, scale, bc_num_p, bc_num_powReq(a, b, scale));
4036252884aeSStefan Eßer }
4037252884aeSStefan Eßer 
4038252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
403978bc019dSStefan Eßer void
404078bc019dSStefan Eßer bc_num_places(BcNum* a, BcNum* b, BcNum* c, size_t scale)
404178bc019dSStefan Eßer {
404250696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
404350696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
4044252884aeSStefan Eßer 	bc_num_binary(a, b, c, scale, bc_num_place, bc_num_placesReq(a, b, scale));
4045252884aeSStefan Eßer }
4046252884aeSStefan Eßer 
404778bc019dSStefan Eßer void
404878bc019dSStefan Eßer bc_num_lshift(BcNum* a, BcNum* b, BcNum* c, size_t scale)
404978bc019dSStefan Eßer {
405050696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
405150696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
4052252884aeSStefan Eßer 	bc_num_binary(a, b, c, scale, bc_num_left, bc_num_placesReq(a, b, scale));
4053252884aeSStefan Eßer }
4054252884aeSStefan Eßer 
405578bc019dSStefan Eßer void
405678bc019dSStefan Eßer bc_num_rshift(BcNum* a, BcNum* b, BcNum* c, size_t scale)
405778bc019dSStefan Eßer {
405850696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(a));
405950696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
4060252884aeSStefan Eßer 	bc_num_binary(a, b, c, scale, bc_num_right, bc_num_placesReq(a, b, scale));
4061252884aeSStefan Eßer }
4062252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
4063252884aeSStefan Eßer 
406478bc019dSStefan Eßer void
406578bc019dSStefan Eßer bc_num_sqrt(BcNum* restrict a, BcNum* restrict b, size_t scale)
406678bc019dSStefan Eßer {
406778bc019dSStefan Eßer 	BcNum num1, num2, half, f, fprime;
406878bc019dSStefan Eßer 	BcNum* x0;
406978bc019dSStefan Eßer 	BcNum* x1;
407078bc019dSStefan Eßer 	BcNum* temp;
4071d101cdd6SStefan Eßer 	// realscale is meant to quiet a warning on GCC about longjmp() clobbering.
4072d101cdd6SStefan Eßer 	// This one is real.
4073d101cdd6SStefan Eßer 	size_t pow, len, rdx, req, resscale, realscale;
4074252884aeSStefan Eßer 	BcDig half_digs[1];
4075d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
4076d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
4077d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
4078252884aeSStefan Eßer 
4079252884aeSStefan Eßer 	assert(a != NULL && b != NULL && a != b);
4080252884aeSStefan Eßer 
408144d4804dSStefan Eßer 	if (BC_ERR(BC_NUM_NEG(a))) bc_err(BC_ERR_MATH_NEGATIVE);
4082252884aeSStefan Eßer 
408344d4804dSStefan Eßer 	// We want to calculate to a's scale if it is bigger so that the result will
408444d4804dSStefan Eßer 	// truncate properly.
4085d101cdd6SStefan Eßer 	if (a->scale > scale) realscale = a->scale;
4086d101cdd6SStefan Eßer 	else realscale = scale;
4087252884aeSStefan Eßer 
408844d4804dSStefan Eßer 	// Set parameters for the result.
4089252884aeSStefan Eßer 	len = bc_vm_growSize(bc_num_intDigits(a), 1);
4090d101cdd6SStefan Eßer 	rdx = BC_NUM_RDX(realscale);
409144d4804dSStefan Eßer 
409244d4804dSStefan Eßer 	// Square root needs half of the length of the parameter.
409350696a6eSStefan Eßer 	req = bc_vm_growSize(BC_MAX(rdx, BC_NUM_RDX_VAL(a)), len >> 1);
4094252884aeSStefan Eßer 
4095252884aeSStefan Eßer 	BC_SIG_LOCK;
4096252884aeSStefan Eßer 
409744d4804dSStefan Eßer 	// Unlike the binary operators, this function is the only single parameter
409844d4804dSStefan Eßer 	// function and is expected to initialize the result. This means that it
409944d4804dSStefan Eßer 	// expects that b is *NOT* preallocated. We allocate it here.
4100252884aeSStefan Eßer 	bc_num_init(b, bc_vm_growSize(req, 1));
4101252884aeSStefan Eßer 
4102252884aeSStefan Eßer 	BC_SIG_UNLOCK;
4103252884aeSStefan Eßer 
410450696a6eSStefan Eßer 	assert(a != NULL && b != NULL && a != b);
410550696a6eSStefan Eßer 	assert(a->num != NULL && b->num != NULL);
410650696a6eSStefan Eßer 
410744d4804dSStefan Eßer 	// Easy case.
410878bc019dSStefan Eßer 	if (BC_NUM_ZERO(a))
410978bc019dSStefan Eßer 	{
4110d101cdd6SStefan Eßer 		bc_num_setToZero(b, realscale);
4111252884aeSStefan Eßer 		return;
4112252884aeSStefan Eßer 	}
411344d4804dSStefan Eßer 
411444d4804dSStefan Eßer 	// Another easy case.
411578bc019dSStefan Eßer 	if (BC_NUM_ONE(a))
411678bc019dSStefan Eßer 	{
4117252884aeSStefan Eßer 		bc_num_one(b);
4118d101cdd6SStefan Eßer 		bc_num_extend(b, realscale);
4119252884aeSStefan Eßer 		return;
4120252884aeSStefan Eßer 	}
4121252884aeSStefan Eßer 
412244d4804dSStefan Eßer 	// Set the parameters again.
4123d101cdd6SStefan Eßer 	rdx = BC_NUM_RDX(realscale);
412450696a6eSStefan Eßer 	rdx = BC_MAX(rdx, BC_NUM_RDX_VAL(a));
4125252884aeSStefan Eßer 	len = bc_vm_growSize(a->len, rdx);
4126252884aeSStefan Eßer 
4127252884aeSStefan Eßer 	BC_SIG_LOCK;
4128252884aeSStefan Eßer 
4129252884aeSStefan Eßer 	bc_num_init(&num1, len);
4130252884aeSStefan Eßer 	bc_num_init(&num2, len);
4131252884aeSStefan Eßer 	bc_num_setup(&half, half_digs, sizeof(half_digs) / sizeof(BcDig));
4132252884aeSStefan Eßer 
413344d4804dSStefan Eßer 	// There is a division by two in the formula. We setup a number that's 1/2
413444d4804dSStefan Eßer 	// so that we can use multiplication instead of heavy division.
4135252884aeSStefan Eßer 	bc_num_one(&half);
4136252884aeSStefan Eßer 	half.num[0] = BC_BASE_POW / 2;
4137252884aeSStefan Eßer 	half.len = 1;
413850696a6eSStefan Eßer 	BC_NUM_RDX_SET_NP(half, 1);
4139252884aeSStefan Eßer 	half.scale = 1;
4140252884aeSStefan Eßer 
4141252884aeSStefan Eßer 	bc_num_init(&f, len);
4142252884aeSStefan Eßer 	bc_num_init(&fprime, len);
4143252884aeSStefan Eßer 
4144d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
4145252884aeSStefan Eßer 
4146252884aeSStefan Eßer 	BC_SIG_UNLOCK;
4147252884aeSStefan Eßer 
414844d4804dSStefan Eßer 	// Pointers for easy switching.
4149252884aeSStefan Eßer 	x0 = &num1;
4150252884aeSStefan Eßer 	x1 = &num2;
4151252884aeSStefan Eßer 
415244d4804dSStefan Eßer 	// Start with 1.
4153252884aeSStefan Eßer 	bc_num_one(x0);
415444d4804dSStefan Eßer 
415544d4804dSStefan Eßer 	// The power of the operand is needed for the estimate.
4156252884aeSStefan Eßer 	pow = bc_num_intDigits(a);
4157252884aeSStefan Eßer 
415844d4804dSStefan Eßer 	// The code in this if statement calculates the initial estimate. First, if
415944d4804dSStefan Eßer 	// a is less than 0, then 0 is a good estimate. Otherwise, we want something
416044d4804dSStefan Eßer 	// in the same ballpark. That ballpark is pow.
416178bc019dSStefan Eßer 	if (pow)
416278bc019dSStefan Eßer 	{
416344d4804dSStefan Eßer 		// An odd number is served by starting with 2^((pow-1)/2), and an even
416444d4804dSStefan Eßer 		// number is served by starting with 6^((pow-2)/2). Why? Because math.
4165252884aeSStefan Eßer 		if (pow & 1) x0->num[0] = 2;
4166252884aeSStefan Eßer 		else x0->num[0] = 6;
4167252884aeSStefan Eßer 
4168252884aeSStefan Eßer 		pow -= 2 - (pow & 1);
4169252884aeSStefan Eßer 		bc_num_shiftLeft(x0, pow / 2);
4170252884aeSStefan Eßer 	}
4171252884aeSStefan Eßer 
417250696a6eSStefan Eßer 	// I can set the rdx here directly because neg should be false.
417310328f8bSStefan Eßer 	x0->scale = x0->rdx = 0;
4174d101cdd6SStefan Eßer 	resscale = (realscale + BC_BASE_DIGS) + 2;
4175252884aeSStefan Eßer 
417644d4804dSStefan Eßer 	// This is the calculation loop. This compare goes to 0 eventually as the
417744d4804dSStefan Eßer 	// difference between the two numbers gets smaller than resscale.
417878bc019dSStefan Eßer 	while (bc_num_cmp(x1, x0))
417978bc019dSStefan Eßer 	{
4180252884aeSStefan Eßer 		assert(BC_NUM_NONZERO(x0));
4181252884aeSStefan Eßer 
418244d4804dSStefan Eßer 		// This loop directly corresponds to the iteration in Newton's method.
418344d4804dSStefan Eßer 		// If you know the formula, this loop makes sense. Go study the formula.
418444d4804dSStefan Eßer 
4185252884aeSStefan Eßer 		bc_num_div(a, x0, &f, resscale);
4186252884aeSStefan Eßer 		bc_num_add(x0, &f, &fprime, resscale);
418750696a6eSStefan Eßer 
418850696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(fprime));
418950696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(half));
419050696a6eSStefan Eßer 
4191252884aeSStefan Eßer 		bc_num_mul(&fprime, &half, x1, resscale);
4192252884aeSStefan Eßer 
419344d4804dSStefan Eßer 		// Switch.
4194252884aeSStefan Eßer 		temp = x0;
4195252884aeSStefan Eßer 		x0 = x1;
4196252884aeSStefan Eßer 		x1 = temp;
4197252884aeSStefan Eßer 	}
4198252884aeSStefan Eßer 
419944d4804dSStefan Eßer 	// Copy to the result and truncate.
4200252884aeSStefan Eßer 	bc_num_copy(b, x0);
4201d101cdd6SStefan Eßer 	if (b->scale > realscale) bc_num_truncate(b, b->scale - realscale);
4202252884aeSStefan Eßer 
420350696a6eSStefan Eßer 	assert(!BC_NUM_NEG(b) || BC_NUM_NONZERO(b));
420450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(b));
420550696a6eSStefan Eßer 	assert(BC_NUM_RDX_VAL(b) <= b->len || !b->len);
420650696a6eSStefan Eßer 	assert(!b->len || b->num[b->len - 1] || BC_NUM_RDX_VAL(b) == b->len);
4207252884aeSStefan Eßer 
4208252884aeSStefan Eßer err:
4209252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
4210252884aeSStefan Eßer 	bc_num_free(&fprime);
4211252884aeSStefan Eßer 	bc_num_free(&f);
4212252884aeSStefan Eßer 	bc_num_free(&num2);
4213252884aeSStefan Eßer 	bc_num_free(&num1);
4214d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
4215252884aeSStefan Eßer }
4216252884aeSStefan Eßer 
421778bc019dSStefan Eßer void
421878bc019dSStefan Eßer bc_num_divmod(BcNum* a, BcNum* b, BcNum* c, BcNum* d, size_t scale)
421978bc019dSStefan Eßer {
4220252884aeSStefan Eßer 	size_t ts, len;
422150696a6eSStefan Eßer 	BcNum *ptr_a, num2;
4222d101cdd6SStefan Eßer 	// This is volatile to quiet a warning on GCC about clobbering with
4223d101cdd6SStefan Eßer 	// longjmp().
4224d101cdd6SStefan Eßer 	volatile bool init = false;
4225d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
4226d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
4227d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
4228252884aeSStefan Eßer 
422944d4804dSStefan Eßer 	// The bulk of this function is just doing what bc_num_binary() does for the
423044d4804dSStefan Eßer 	// binary operators. However, it assumes that only c and a can be equal.
423144d4804dSStefan Eßer 
423244d4804dSStefan Eßer 	// Set up the parameters.
4233252884aeSStefan Eßer 	ts = BC_MAX(scale + b->scale, a->scale);
4234252884aeSStefan Eßer 	len = bc_num_mulReq(a, b, ts);
4235252884aeSStefan Eßer 
4236252884aeSStefan Eßer 	assert(a != NULL && b != NULL && c != NULL && d != NULL);
4237252884aeSStefan Eßer 	assert(c != d && a != d && b != d && b != c);
4238252884aeSStefan Eßer 
423944d4804dSStefan Eßer 	// Initialize or expand as necessary.
424078bc019dSStefan Eßer 	if (c == a)
424178bc019dSStefan Eßer 	{
424278bc019dSStefan Eßer 		// NOLINTNEXTLINE
4243252884aeSStefan Eßer 		memcpy(&num2, c, sizeof(BcNum));
4244252884aeSStefan Eßer 		ptr_a = &num2;
4245252884aeSStefan Eßer 
4246252884aeSStefan Eßer 		BC_SIG_LOCK;
4247252884aeSStefan Eßer 
4248252884aeSStefan Eßer 		bc_num_init(c, len);
4249252884aeSStefan Eßer 
4250252884aeSStefan Eßer 		init = true;
4251252884aeSStefan Eßer 
4252d101cdd6SStefan Eßer 		BC_SETJMP_LOCKED(vm, err);
4253252884aeSStefan Eßer 
4254252884aeSStefan Eßer 		BC_SIG_UNLOCK;
4255252884aeSStefan Eßer 	}
425678bc019dSStefan Eßer 	else
425778bc019dSStefan Eßer 	{
4258252884aeSStefan Eßer 		ptr_a = a;
4259252884aeSStefan Eßer 		bc_num_expand(c, len);
4260252884aeSStefan Eßer 	}
4261252884aeSStefan Eßer 
426244d4804dSStefan Eßer 	// Do the quick version if possible.
426378bc019dSStefan Eßer 	if (BC_NUM_NONZERO(a) && !BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b) &&
426478bc019dSStefan Eßer 	    b->len == 1 && !scale)
426550696a6eSStefan Eßer 	{
4266252884aeSStefan Eßer 		BcBigDig rem;
4267252884aeSStefan Eßer 
4268252884aeSStefan Eßer 		bc_num_divArray(ptr_a, (BcBigDig) b->num[0], c, &rem);
4269252884aeSStefan Eßer 
4270252884aeSStefan Eßer 		assert(rem < BC_BASE_POW);
4271252884aeSStefan Eßer 
4272252884aeSStefan Eßer 		d->num[0] = (BcDig) rem;
4273252884aeSStefan Eßer 		d->len = (rem != 0);
4274252884aeSStefan Eßer 	}
427544d4804dSStefan Eßer 	// Do the slow method.
4276252884aeSStefan Eßer 	else bc_num_r(ptr_a, b, c, d, scale, ts);
4277252884aeSStefan Eßer 
427850696a6eSStefan Eßer 	assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c));
427950696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(c));
428050696a6eSStefan Eßer 	assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len);
428150696a6eSStefan Eßer 	assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len);
428250696a6eSStefan Eßer 	assert(!BC_NUM_NEG(d) || BC_NUM_NONZERO(d));
428350696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(d));
428450696a6eSStefan Eßer 	assert(BC_NUM_RDX_VAL(d) <= d->len || !d->len);
428550696a6eSStefan Eßer 	assert(!d->len || d->num[d->len - 1] || BC_NUM_RDX_VAL(d) == d->len);
4286252884aeSStefan Eßer 
4287252884aeSStefan Eßer err:
428844d4804dSStefan Eßer 	// Only cleanup if we initialized.
428978bc019dSStefan Eßer 	if (init)
429078bc019dSStefan Eßer 	{
4291252884aeSStefan Eßer 		BC_SIG_MAYLOCK;
4292252884aeSStefan Eßer 		bc_num_free(&num2);
4293d101cdd6SStefan Eßer 		BC_LONGJMP_CONT(vm);
4294252884aeSStefan Eßer 	}
4295252884aeSStefan Eßer }
4296252884aeSStefan Eßer 
429778bc019dSStefan Eßer void
429878bc019dSStefan Eßer bc_num_modexp(BcNum* a, BcNum* b, BcNum* c, BcNum* restrict d)
429978bc019dSStefan Eßer {
430044d4804dSStefan Eßer 	BcNum base, exp, two, temp, atemp, btemp, ctemp;
4301252884aeSStefan Eßer 	BcDig two_digs[2];
4302d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
4303d101cdd6SStefan Eßer 	BcVm* vm = bcl_getspecific();
4304d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
4305252884aeSStefan Eßer 
4306252884aeSStefan Eßer 	assert(a != NULL && b != NULL && c != NULL && d != NULL);
4307252884aeSStefan Eßer 	assert(a != d && b != d && c != d);
4308252884aeSStefan Eßer 
430944d4804dSStefan Eßer 	if (BC_ERR(BC_NUM_ZERO(c))) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO);
431044d4804dSStefan Eßer 	if (BC_ERR(BC_NUM_NEG(b))) bc_err(BC_ERR_MATH_NEGATIVE);
431144d4804dSStefan Eßer 
4312103d7cdfSStefan Eßer #if BC_DEBUG || BC_GCC
431344d4804dSStefan Eßer 	// This is entirely for quieting a useless scan-build error.
431444d4804dSStefan Eßer 	btemp.len = 0;
431544d4804dSStefan Eßer 	ctemp.len = 0;
4316103d7cdfSStefan Eßer #endif // BC_DEBUG || BC_GCC
431744d4804dSStefan Eßer 
431844d4804dSStefan Eßer 	// Eliminate fractional parts that are zero or error if they are not zero.
431944d4804dSStefan Eßer 	if (BC_ERR(bc_num_nonInt(a, &atemp) || bc_num_nonInt(b, &btemp) ||
432044d4804dSStefan Eßer 	           bc_num_nonInt(c, &ctemp)))
432144d4804dSStefan Eßer 	{
432244d4804dSStefan Eßer 		bc_err(BC_ERR_MATH_NON_INTEGER);
432344d4804dSStefan Eßer 	}
432444d4804dSStefan Eßer 
432544d4804dSStefan Eßer 	bc_num_expand(d, ctemp.len);
4326252884aeSStefan Eßer 
4327252884aeSStefan Eßer 	BC_SIG_LOCK;
4328252884aeSStefan Eßer 
432944d4804dSStefan Eßer 	bc_num_init(&base, ctemp.len);
4330252884aeSStefan Eßer 	bc_num_setup(&two, two_digs, sizeof(two_digs) / sizeof(BcDig));
433144d4804dSStefan Eßer 	bc_num_init(&temp, btemp.len + 1);
433244d4804dSStefan Eßer 	bc_num_createCopy(&exp, &btemp);
4333252884aeSStefan Eßer 
4334d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
4335252884aeSStefan Eßer 
4336252884aeSStefan Eßer 	BC_SIG_UNLOCK;
4337252884aeSStefan Eßer 
4338252884aeSStefan Eßer 	bc_num_one(&two);
4339252884aeSStefan Eßer 	two.num[0] = 2;
4340252884aeSStefan Eßer 	bc_num_one(d);
4341252884aeSStefan Eßer 
4342252884aeSStefan Eßer 	// We already checked for 0.
434344d4804dSStefan Eßer 	bc_num_rem(&atemp, &ctemp, &base, 0);
4344252884aeSStefan Eßer 
434544d4804dSStefan Eßer 	// If you know the algorithm I used, the memory-efficient method, then this
434644d4804dSStefan Eßer 	// loop should be self-explanatory because it is the calculation loop.
434778bc019dSStefan Eßer 	while (BC_NUM_NONZERO(&exp))
434878bc019dSStefan Eßer 	{
4349252884aeSStefan Eßer 		// Num two cannot be 0, so no errors.
4350252884aeSStefan Eßer 		bc_num_divmod(&exp, &two, &exp, &temp, 0);
4351252884aeSStefan Eßer 
435278bc019dSStefan Eßer 		if (BC_NUM_ONE(&temp) && !BC_NUM_NEG_NP(temp))
435378bc019dSStefan Eßer 		{
435450696a6eSStefan Eßer 			assert(BC_NUM_RDX_VALID(d));
435550696a6eSStefan Eßer 			assert(BC_NUM_RDX_VALID_NP(base));
4356252884aeSStefan Eßer 
4357252884aeSStefan Eßer 			bc_num_mul(d, &base, &temp, 0);
4358252884aeSStefan Eßer 
4359252884aeSStefan Eßer 			// We already checked for 0.
436044d4804dSStefan Eßer 			bc_num_rem(&temp, &ctemp, d, 0);
4361252884aeSStefan Eßer 		}
4362252884aeSStefan Eßer 
436350696a6eSStefan Eßer 		assert(BC_NUM_RDX_VALID_NP(base));
436450696a6eSStefan Eßer 
4365252884aeSStefan Eßer 		bc_num_mul(&base, &base, &temp, 0);
4366252884aeSStefan Eßer 
4367252884aeSStefan Eßer 		// We already checked for 0.
436844d4804dSStefan Eßer 		bc_num_rem(&temp, &ctemp, &base, 0);
4369252884aeSStefan Eßer 	}
4370252884aeSStefan Eßer 
4371252884aeSStefan Eßer err:
4372252884aeSStefan Eßer 	BC_SIG_MAYLOCK;
4373252884aeSStefan Eßer 	bc_num_free(&exp);
4374252884aeSStefan Eßer 	bc_num_free(&temp);
4375252884aeSStefan Eßer 	bc_num_free(&base);
4376d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
437750696a6eSStefan Eßer 	assert(!BC_NUM_NEG(d) || d->len);
437850696a6eSStefan Eßer 	assert(BC_NUM_RDX_VALID(d));
437950696a6eSStefan Eßer 	assert(!d->len || d->num[d->len - 1] || BC_NUM_RDX_VAL(d) == d->len);
4380252884aeSStefan Eßer }
4381252884aeSStefan Eßer 
4382252884aeSStefan Eßer #if BC_DEBUG_CODE
438378bc019dSStefan Eßer void
438478bc019dSStefan Eßer bc_num_printDebug(const BcNum* n, const char* name, bool emptyline)
438578bc019dSStefan Eßer {
4386d101cdd6SStefan Eßer 	bc_file_puts(&vm->fout, bc_flush_none, name);
4387d101cdd6SStefan Eßer 	bc_file_puts(&vm->fout, bc_flush_none, ": ");
438844d4804dSStefan Eßer 	bc_num_printDecimal(n, true);
4389d101cdd6SStefan Eßer 	bc_file_putchar(&vm->fout, bc_flush_err, '\n');
4390d101cdd6SStefan Eßer 	if (emptyline) bc_file_putchar(&vm->fout, bc_flush_err, '\n');
4391d101cdd6SStefan Eßer 	vm->nchars = 0;
4392252884aeSStefan Eßer }
4393252884aeSStefan Eßer 
439478bc019dSStefan Eßer void
439578bc019dSStefan Eßer bc_num_printDigs(const BcDig* n, size_t len, bool emptyline)
439678bc019dSStefan Eßer {
4397252884aeSStefan Eßer 	size_t i;
4398252884aeSStefan Eßer 
4399252884aeSStefan Eßer 	for (i = len - 1; i < len; --i)
440078bc019dSStefan Eßer 	{
4401d101cdd6SStefan Eßer 		bc_file_printf(&vm->fout, " %lu", (unsigned long) n[i]);
440278bc019dSStefan Eßer 	}
4403252884aeSStefan Eßer 
4404d101cdd6SStefan Eßer 	bc_file_putchar(&vm->fout, bc_flush_err, '\n');
4405d101cdd6SStefan Eßer 	if (emptyline) bc_file_putchar(&vm->fout, bc_flush_err, '\n');
4406d101cdd6SStefan Eßer 	vm->nchars = 0;
4407252884aeSStefan Eßer }
4408252884aeSStefan Eßer 
440978bc019dSStefan Eßer void
441078bc019dSStefan Eßer bc_num_printWithDigs(const BcNum* n, const char* name, bool emptyline)
441178bc019dSStefan Eßer {
4412d101cdd6SStefan Eßer 	bc_file_puts(&vm->fout, bc_flush_none, name);
4413d101cdd6SStefan Eßer 	bc_file_printf(&vm->fout, " len: %zu, rdx: %zu, scale: %zu\n", name, n->len,
441478bc019dSStefan Eßer 	               BC_NUM_RDX_VAL(n), n->scale);
4415252884aeSStefan Eßer 	bc_num_printDigs(n->num, n->len, emptyline);
4416252884aeSStefan Eßer }
4417252884aeSStefan Eßer 
441878bc019dSStefan Eßer void
441978bc019dSStefan Eßer bc_num_dump(const char* varname, const BcNum* n)
442078bc019dSStefan Eßer {
4421252884aeSStefan Eßer 	ulong i, scale = n->scale;
4422252884aeSStefan Eßer 
4423d101cdd6SStefan Eßer 	bc_file_printf(&vm->ferr, "\n%s = %s", varname,
442450696a6eSStefan Eßer 	               n->len ? (BC_NUM_NEG(n) ? "-" : "+") : "0 ");
4425252884aeSStefan Eßer 
442678bc019dSStefan Eßer 	for (i = n->len - 1; i < n->len; --i)
442778bc019dSStefan Eßer 	{
44287e5c51e5SStefan Eßer 		if (i + 1 == BC_NUM_RDX_VAL(n))
442978bc019dSStefan Eßer 		{
4430d101cdd6SStefan Eßer 			bc_file_puts(&vm->ferr, bc_flush_none, ". ");
443178bc019dSStefan Eßer 		}
4432252884aeSStefan Eßer 
443350696a6eSStefan Eßer 		if (scale / BC_BASE_DIGS != BC_NUM_RDX_VAL(n) - i - 1)
443478bc019dSStefan Eßer 		{
4435d101cdd6SStefan Eßer 			bc_file_printf(&vm->ferr, "%lu ", (unsigned long) n->num[i]);
443678bc019dSStefan Eßer 		}
443778bc019dSStefan Eßer 		else
443878bc019dSStefan Eßer 		{
4439252884aeSStefan Eßer 			int mod = scale % BC_BASE_DIGS;
4440252884aeSStefan Eßer 			int d = BC_BASE_DIGS - mod;
4441252884aeSStefan Eßer 			BcDig div;
4442252884aeSStefan Eßer 
444378bc019dSStefan Eßer 			if (mod != 0)
444478bc019dSStefan Eßer 			{
4445252884aeSStefan Eßer 				div = n->num[i] / ((BcDig) bc_num_pow10[(ulong) d]);
4446d101cdd6SStefan Eßer 				bc_file_printf(&vm->ferr, "%lu", (unsigned long) div);
4447252884aeSStefan Eßer 			}
4448252884aeSStefan Eßer 
4449252884aeSStefan Eßer 			div = n->num[i] % ((BcDig) bc_num_pow10[(ulong) d]);
4450d101cdd6SStefan Eßer 			bc_file_printf(&vm->ferr, " ' %lu ", (unsigned long) div);
4451252884aeSStefan Eßer 		}
4452252884aeSStefan Eßer 	}
4453252884aeSStefan Eßer 
4454d101cdd6SStefan Eßer 	bc_file_printf(&vm->ferr, "(%zu | %zu.%zu / %zu) %lu\n", n->scale, n->len,
445578bc019dSStefan Eßer 	               BC_NUM_RDX_VAL(n), n->cap, (unsigned long) (void*) n->num);
44567e5c51e5SStefan Eßer 
4457d101cdd6SStefan Eßer 	bc_file_flush(&vm->ferr, bc_flush_err);
4458252884aeSStefan Eßer }
4459252884aeSStefan Eßer #endif // BC_DEBUG_CODE
4460