1252884aeSStefan Eßer /*
2252884aeSStefan Eßer * *****************************************************************************
3252884aeSStefan Eßer *
43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer *
6a970610aSStefan Eßer * Copyright (c) 2018-2024 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
bc_num_mulOverflow(size_t a,size_t b)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
bc_num_neg(size_t n,bool neg)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
bc_num_cmpZero(const BcNum * n)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
bc_num_int(const BcNum * n)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
bc_num_expand(BcNum * restrict n,size_t req)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
bc_num_setToZero(BcNum * restrict n,size_t scale)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
bc_num_zero(BcNum * restrict n)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
bc_num_one(BcNum * restrict n)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
bc_num_clean(BcNum * restrict n)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
bc_num_log10(size_t i)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
bc_num_zeroDigits(const BcDig * n)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 /**
218a970610aSStefan Eßer * Returns the power of 10 that the least significant limb should be multiplied
219a970610aSStefan Eßer * by to put its digits in the right place. For example, if the scale only
220a970610aSStefan Eßer * reaches 8 places into the limb, this will return 1 (because it should be
221a970610aSStefan Eßer * multiplied by 10^1) to put the number in the correct place.
222a970610aSStefan Eßer * @param scale The scale.
223a970610aSStefan Eßer * @return The power of 10 that the least significant limb should be
224a970610aSStefan Eßer * multiplied by
225a970610aSStefan Eßer */
226a970610aSStefan Eßer static inline size_t
bc_num_leastSigPow(size_t scale)227a970610aSStefan Eßer bc_num_leastSigPow(size_t scale)
228a970610aSStefan Eßer {
229a970610aSStefan Eßer size_t digs;
230a970610aSStefan Eßer
231a970610aSStefan Eßer digs = scale % BC_BASE_DIGS;
232a970610aSStefan Eßer digs = digs != 0 ? BC_BASE_DIGS - digs : 0;
233a970610aSStefan Eßer
234a970610aSStefan Eßer return bc_num_pow10[digs];
235a970610aSStefan Eßer }
236a970610aSStefan Eßer
237a970610aSStefan Eßer /**
23844d4804dSStefan Eßer * Return the total number of integer digits in a number. This is the opposite
23944d4804dSStefan Eßer * of scale, like bc_num_int() is the opposite of rdx.
24044d4804dSStefan Eßer * @param n The number.
24144d4804dSStefan Eßer * @return The number of integer digits in @a n.
24244d4804dSStefan Eßer */
24378bc019dSStefan Eßer static size_t
bc_num_intDigits(const BcNum * n)24478bc019dSStefan Eßer bc_num_intDigits(const BcNum* n)
24578bc019dSStefan Eßer {
246252884aeSStefan Eßer size_t digits = bc_num_int(n) * BC_BASE_DIGS;
247252884aeSStefan Eßer if (digits > 0) digits -= bc_num_zeroDigits(n->num + n->len - 1);
248252884aeSStefan Eßer return digits;
249252884aeSStefan Eßer }
250252884aeSStefan Eßer
25144d4804dSStefan Eßer /**
25244d4804dSStefan Eßer * Returns the number of limbs of a number that are non-zero starting at the
25344d4804dSStefan Eßer * most significant limbs. This expects that there are *no* integer limbs in the
25444d4804dSStefan Eßer * number because it is specifically to figure out how many zero limbs after the
25544d4804dSStefan Eßer * decimal place to ignore. If there are zero limbs after non-zero limbs, they
25644d4804dSStefan Eßer * are counted as non-zero limbs.
25744d4804dSStefan Eßer * @param n The number.
25844d4804dSStefan Eßer * @return The number of non-zero limbs after the decimal point.
25944d4804dSStefan Eßer */
26078bc019dSStefan Eßer static size_t
bc_num_nonZeroLen(const BcNum * restrict n)26178bc019dSStefan Eßer bc_num_nonZeroLen(const BcNum* restrict n)
26278bc019dSStefan Eßer {
263252884aeSStefan Eßer size_t i, len = n->len;
26478bc019dSStefan Eßer
26550696a6eSStefan Eßer assert(len == BC_NUM_RDX_VAL(n));
26678bc019dSStefan Eßer
26778bc019dSStefan Eßer for (i = len - 1; i < len && !n->num[i]; --i)
26878bc019dSStefan Eßer {
26978bc019dSStefan Eßer continue;
27078bc019dSStefan Eßer }
27178bc019dSStefan Eßer
272252884aeSStefan Eßer assert(i + 1 > 0);
27378bc019dSStefan Eßer
274252884aeSStefan Eßer return i + 1;
275252884aeSStefan Eßer }
276252884aeSStefan Eßer
277*12e0d316SStefan Eßer #if BC_ENABLE_EXTRA_MATH
278*12e0d316SStefan Eßer
27944d4804dSStefan Eßer /**
280a970610aSStefan Eßer * Returns the power of 10 that a number with an absolute value less than 1
281a970610aSStefan Eßer * needs to be multiplied by in order to be greater than 1 or less than -1.
282a970610aSStefan Eßer * @param n The number.
283a970610aSStefan Eßer * @return The power of 10 that a number greater than 1 and less than -1 must
284a970610aSStefan Eßer * be multiplied by to be greater than 1 or less than -1.
285a970610aSStefan Eßer */
286a970610aSStefan Eßer static size_t
bc_num_negPow10(const BcNum * restrict n)287a970610aSStefan Eßer bc_num_negPow10(const BcNum* restrict n)
288a970610aSStefan Eßer {
289a970610aSStefan Eßer // Figure out how many limbs after the decimal point is zero.
290a970610aSStefan Eßer size_t i, places, idx = bc_num_nonZeroLen(n) - 1;
291a970610aSStefan Eßer
292a970610aSStefan Eßer places = 1;
293a970610aSStefan Eßer
294a970610aSStefan Eßer // Figure out how much in the last limb is zero.
295a970610aSStefan Eßer for (i = BC_BASE_DIGS - 1; i < BC_BASE_DIGS; --i)
296a970610aSStefan Eßer {
297a970610aSStefan Eßer if (bc_num_pow10[i] > (BcBigDig) n->num[idx]) places += 1;
298a970610aSStefan Eßer else break;
299a970610aSStefan Eßer }
300a970610aSStefan Eßer
301a970610aSStefan Eßer // Calculate the combination of zero limbs and zero digits in the last
302a970610aSStefan Eßer // limb.
303a970610aSStefan Eßer return places + (BC_NUM_RDX_VAL(n) - (idx + 1)) * BC_BASE_DIGS;
304a970610aSStefan Eßer }
305a970610aSStefan Eßer
306*12e0d316SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
307*12e0d316SStefan Eßer
308a970610aSStefan Eßer /**
30944d4804dSStefan Eßer * Performs a one-limb add with a carry.
31044d4804dSStefan Eßer * @param a The first limb.
31144d4804dSStefan Eßer * @param b The second limb.
31244d4804dSStefan Eßer * @param carry An in/out parameter; the carry in from the previous add and the
31344d4804dSStefan Eßer * carry out from this add.
31444d4804dSStefan Eßer * @return The resulting limb sum.
31544d4804dSStefan Eßer */
31678bc019dSStefan Eßer static BcDig
bc_num_addDigits(BcDig a,BcDig b,bool * carry)31778bc019dSStefan Eßer bc_num_addDigits(BcDig a, BcDig b, bool* carry)
31878bc019dSStefan Eßer {
319252884aeSStefan Eßer assert(((BcBigDig) BC_BASE_POW) * 2 == ((BcDig) BC_BASE_POW) * 2);
320d101cdd6SStefan Eßer assert(a < BC_BASE_POW && a >= 0);
321d101cdd6SStefan Eßer assert(b < BC_BASE_POW && b >= 0);
322252884aeSStefan Eßer
323252884aeSStefan Eßer a += b + *carry;
324252884aeSStefan Eßer *carry = (a >= BC_BASE_POW);
325252884aeSStefan Eßer if (*carry) a -= BC_BASE_POW;
326252884aeSStefan Eßer
327252884aeSStefan Eßer assert(a >= 0);
328252884aeSStefan Eßer assert(a < BC_BASE_POW);
329252884aeSStefan Eßer
330252884aeSStefan Eßer return a;
331252884aeSStefan Eßer }
332252884aeSStefan Eßer
33344d4804dSStefan Eßer /**
33444d4804dSStefan Eßer * Performs a one-limb subtract with a carry.
33544d4804dSStefan Eßer * @param a The first limb.
33644d4804dSStefan Eßer * @param b The second limb.
33744d4804dSStefan Eßer * @param carry An in/out parameter; the carry in from the previous subtract
33844d4804dSStefan Eßer * and the carry out from this subtract.
33944d4804dSStefan Eßer * @return The resulting limb difference.
34044d4804dSStefan Eßer */
34178bc019dSStefan Eßer static BcDig
bc_num_subDigits(BcDig a,BcDig b,bool * carry)34278bc019dSStefan Eßer bc_num_subDigits(BcDig a, BcDig b, bool* carry)
34378bc019dSStefan Eßer {
344d101cdd6SStefan Eßer assert(a < BC_BASE_POW && a >= 0);
345d101cdd6SStefan Eßer assert(b < BC_BASE_POW && b >= 0);
346252884aeSStefan Eßer
347252884aeSStefan Eßer b += *carry;
348252884aeSStefan Eßer *carry = (a < b);
349252884aeSStefan Eßer if (*carry) a += BC_BASE_POW;
350252884aeSStefan Eßer
351252884aeSStefan Eßer assert(a - b >= 0);
352252884aeSStefan Eßer assert(a - b < BC_BASE_POW);
353252884aeSStefan Eßer
354252884aeSStefan Eßer return a - b;
355252884aeSStefan Eßer }
356252884aeSStefan Eßer
35744d4804dSStefan Eßer /**
35844d4804dSStefan Eßer * Add two BcDig arrays and store the result in the first array.
35944d4804dSStefan Eßer * @param a The first operand and out array.
36044d4804dSStefan Eßer * @param b The second operand.
36144d4804dSStefan Eßer * @param len The length of @a b.
36244d4804dSStefan Eßer */
36378bc019dSStefan Eßer static void
bc_num_addArrays(BcDig * restrict a,const BcDig * restrict b,size_t len)36478bc019dSStefan Eßer bc_num_addArrays(BcDig* restrict a, const BcDig* restrict b, size_t len)
365252884aeSStefan Eßer {
366252884aeSStefan Eßer size_t i;
367252884aeSStefan Eßer bool carry = false;
368252884aeSStefan Eßer
36978bc019dSStefan Eßer for (i = 0; i < len; ++i)
37078bc019dSStefan Eßer {
37178bc019dSStefan Eßer a[i] = bc_num_addDigits(a[i], b[i], &carry);
37278bc019dSStefan Eßer }
373252884aeSStefan Eßer
37444d4804dSStefan Eßer // Take care of the extra limbs in the bigger array.
37578bc019dSStefan Eßer for (; carry; ++i)
37678bc019dSStefan Eßer {
37778bc019dSStefan Eßer a[i] = bc_num_addDigits(a[i], 0, &carry);
37878bc019dSStefan Eßer }
379252884aeSStefan Eßer }
380252884aeSStefan Eßer
38144d4804dSStefan Eßer /**
38244d4804dSStefan Eßer * Subtract two BcDig arrays and store the result in the first array.
38344d4804dSStefan Eßer * @param a The first operand and out array.
38444d4804dSStefan Eßer * @param b The second operand.
38544d4804dSStefan Eßer * @param len The length of @a b.
38644d4804dSStefan Eßer */
38778bc019dSStefan Eßer static void
bc_num_subArrays(BcDig * restrict a,const BcDig * restrict b,size_t len)38878bc019dSStefan Eßer bc_num_subArrays(BcDig* restrict a, const BcDig* restrict b, size_t len)
389252884aeSStefan Eßer {
390252884aeSStefan Eßer size_t i;
391252884aeSStefan Eßer bool carry = false;
392252884aeSStefan Eßer
39378bc019dSStefan Eßer for (i = 0; i < len; ++i)
39478bc019dSStefan Eßer {
39578bc019dSStefan Eßer a[i] = bc_num_subDigits(a[i], b[i], &carry);
39678bc019dSStefan Eßer }
397252884aeSStefan Eßer
39844d4804dSStefan Eßer // Take care of the extra limbs in the bigger array.
39978bc019dSStefan Eßer for (; carry; ++i)
40078bc019dSStefan Eßer {
40178bc019dSStefan Eßer a[i] = bc_num_subDigits(a[i], 0, &carry);
40278bc019dSStefan Eßer }
403252884aeSStefan Eßer }
404252884aeSStefan Eßer
40544d4804dSStefan Eßer /**
40644d4804dSStefan Eßer * Multiply a BcNum array by a one-limb number. This is a faster version of
40744d4804dSStefan Eßer * multiplication for when we can use it.
40844d4804dSStefan Eßer * @param a The BcNum to multiply by the one-limb number.
40944d4804dSStefan Eßer * @param b The one limb of the one-limb number.
41044d4804dSStefan Eßer * @param c The return parameter.
41144d4804dSStefan Eßer */
41278bc019dSStefan Eßer static void
bc_num_mulArray(const BcNum * restrict a,BcBigDig b,BcNum * restrict c)41378bc019dSStefan Eßer bc_num_mulArray(const BcNum* restrict a, BcBigDig b, BcNum* restrict c)
414252884aeSStefan Eßer {
415252884aeSStefan Eßer size_t i;
416252884aeSStefan Eßer BcBigDig carry = 0;
417252884aeSStefan Eßer
418252884aeSStefan Eßer assert(b <= BC_BASE_POW);
419252884aeSStefan Eßer
42044d4804dSStefan Eßer // Make sure the return parameter is big enough.
421252884aeSStefan Eßer if (a->len + 1 > c->cap) bc_num_expand(c, a->len + 1);
422252884aeSStefan Eßer
42344d4804dSStefan Eßer // We want the entire return parameter to be zero for cleaning later.
42478bc019dSStefan Eßer // NOLINTNEXTLINE
425252884aeSStefan Eßer memset(c->num, 0, BC_NUM_SIZE(c->cap));
426252884aeSStefan Eßer
42744d4804dSStefan Eßer // Actual multiplication loop.
42878bc019dSStefan Eßer for (i = 0; i < a->len; ++i)
42978bc019dSStefan Eßer {
430252884aeSStefan Eßer BcBigDig in = ((BcBigDig) a->num[i]) * b + carry;
431252884aeSStefan Eßer c->num[i] = in % BC_BASE_POW;
432252884aeSStefan Eßer carry = in / BC_BASE_POW;
433252884aeSStefan Eßer }
434252884aeSStefan Eßer
435252884aeSStefan Eßer assert(carry < BC_BASE_POW);
43644d4804dSStefan Eßer
43744d4804dSStefan Eßer // Finishing touches.
438252884aeSStefan Eßer c->num[i] = (BcDig) carry;
439d101cdd6SStefan Eßer assert(c->num[i] >= 0 && c->num[i] < BC_BASE_POW);
440252884aeSStefan Eßer c->len = a->len;
441252884aeSStefan Eßer c->len += (carry != 0);
442252884aeSStefan Eßer
443252884aeSStefan Eßer bc_num_clean(c);
444252884aeSStefan Eßer
44544d4804dSStefan Eßer // Postconditions.
44650696a6eSStefan Eßer assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c));
44750696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len);
44850696a6eSStefan Eßer assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len);
449252884aeSStefan Eßer }
450252884aeSStefan Eßer
45144d4804dSStefan Eßer /**
45244d4804dSStefan Eßer * Divide a BcNum array by a one-limb number. This is a faster version of divide
45344d4804dSStefan Eßer * for when we can use it.
45444d4804dSStefan Eßer * @param a The BcNum to multiply by the one-limb number.
45544d4804dSStefan Eßer * @param b The one limb of the one-limb number.
45644d4804dSStefan Eßer * @param c The return parameter for the quotient.
45744d4804dSStefan Eßer * @param rem The return parameter for the remainder.
45844d4804dSStefan Eßer */
45978bc019dSStefan Eßer static void
bc_num_divArray(const BcNum * restrict a,BcBigDig b,BcNum * restrict c,BcBigDig * rem)46078bc019dSStefan Eßer bc_num_divArray(const BcNum* restrict a, BcBigDig b, BcNum* restrict c,
46178bc019dSStefan Eßer BcBigDig* rem)
462252884aeSStefan Eßer {
463252884aeSStefan Eßer size_t i;
464252884aeSStefan Eßer BcBigDig carry = 0;
465252884aeSStefan Eßer
466252884aeSStefan Eßer assert(c->cap >= a->len);
467252884aeSStefan Eßer
46844d4804dSStefan Eßer // Actual division loop.
46978bc019dSStefan Eßer for (i = a->len - 1; i < a->len; --i)
47078bc019dSStefan Eßer {
471252884aeSStefan Eßer BcBigDig in = ((BcBigDig) a->num[i]) + carry * BC_BASE_POW;
472252884aeSStefan Eßer assert(in / b < BC_BASE_POW);
473252884aeSStefan Eßer c->num[i] = (BcDig) (in / b);
474d101cdd6SStefan Eßer assert(c->num[i] >= 0 && c->num[i] < BC_BASE_POW);
475252884aeSStefan Eßer carry = in % b;
476252884aeSStefan Eßer }
477252884aeSStefan Eßer
47844d4804dSStefan Eßer // Finishing touches.
479252884aeSStefan Eßer c->len = a->len;
480252884aeSStefan Eßer bc_num_clean(c);
481252884aeSStefan Eßer *rem = carry;
482252884aeSStefan Eßer
48344d4804dSStefan Eßer // Postconditions.
48450696a6eSStefan Eßer assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c));
48550696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len);
48650696a6eSStefan Eßer assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len);
487252884aeSStefan Eßer }
488252884aeSStefan Eßer
48944d4804dSStefan Eßer /**
49044d4804dSStefan Eßer * Compare two BcDig arrays and return >0 if @a b is greater, <0 if @a b is
49144d4804dSStefan Eßer * less, and 0 if equal. Both @a a and @a b must have the same length.
49244d4804dSStefan Eßer * @param a The first array.
49344d4804dSStefan Eßer * @param b The second array.
49444d4804dSStefan Eßer * @param len The minimum length of the arrays.
49544d4804dSStefan Eßer */
49678bc019dSStefan Eßer static ssize_t
bc_num_compare(const BcDig * restrict a,const BcDig * restrict b,size_t len)49778bc019dSStefan Eßer bc_num_compare(const BcDig* restrict a, const BcDig* restrict b, size_t len)
498252884aeSStefan Eßer {
499252884aeSStefan Eßer size_t i;
500252884aeSStefan Eßer BcDig c = 0;
50178bc019dSStefan Eßer for (i = len - 1; i < len && !(c = a[i] - b[i]); --i)
50278bc019dSStefan Eßer {
50378bc019dSStefan Eßer continue;
50478bc019dSStefan Eßer }
505252884aeSStefan Eßer return bc_num_neg(i + 1, c < 0);
506252884aeSStefan Eßer }
507252884aeSStefan Eßer
50878bc019dSStefan Eßer ssize_t
bc_num_cmp(const BcNum * a,const BcNum * b)50978bc019dSStefan Eßer bc_num_cmp(const BcNum* a, const BcNum* b)
51078bc019dSStefan Eßer {
51150696a6eSStefan Eßer size_t i, min, a_int, b_int, diff, ardx, brdx;
51278bc019dSStefan Eßer BcDig* max_num;
51378bc019dSStefan Eßer BcDig* min_num;
514252884aeSStefan Eßer bool a_max, neg = false;
515252884aeSStefan Eßer ssize_t cmp;
516252884aeSStefan Eßer
517252884aeSStefan Eßer assert(a != NULL && b != NULL);
518252884aeSStefan Eßer
51944d4804dSStefan Eßer // Same num? Equal.
520252884aeSStefan Eßer if (a == b) return 0;
52144d4804dSStefan Eßer
52244d4804dSStefan Eßer // Easy cases.
52350696a6eSStefan Eßer if (BC_NUM_ZERO(a)) return bc_num_neg(b->len != 0, !BC_NUM_NEG(b));
524252884aeSStefan Eßer if (BC_NUM_ZERO(b)) return bc_num_cmpZero(a);
52578bc019dSStefan Eßer if (BC_NUM_NEG(a))
52678bc019dSStefan Eßer {
52750696a6eSStefan Eßer if (BC_NUM_NEG(b)) neg = true;
528252884aeSStefan Eßer else return -1;
529252884aeSStefan Eßer }
53050696a6eSStefan Eßer else if (BC_NUM_NEG(b)) return 1;
531252884aeSStefan Eßer
53244d4804dSStefan Eßer // Get the number of int limbs in each number and get the difference.
533252884aeSStefan Eßer a_int = bc_num_int(a);
534252884aeSStefan Eßer b_int = bc_num_int(b);
535252884aeSStefan Eßer a_int -= b_int;
536252884aeSStefan Eßer
53744d4804dSStefan Eßer // If there's a difference, then just return the comparison.
538252884aeSStefan Eßer if (a_int) return neg ? -((ssize_t) a_int) : (ssize_t) a_int;
539252884aeSStefan Eßer
54044d4804dSStefan Eßer // Get the rdx's and figure out the max.
54150696a6eSStefan Eßer ardx = BC_NUM_RDX_VAL(a);
54250696a6eSStefan Eßer brdx = BC_NUM_RDX_VAL(b);
54350696a6eSStefan Eßer a_max = (ardx > brdx);
544252884aeSStefan Eßer
54544d4804dSStefan Eßer // Set variables based on the above.
54678bc019dSStefan Eßer if (a_max)
54778bc019dSStefan Eßer {
54850696a6eSStefan Eßer min = brdx;
54950696a6eSStefan Eßer diff = ardx - brdx;
550252884aeSStefan Eßer max_num = a->num + diff;
551252884aeSStefan Eßer min_num = b->num;
552252884aeSStefan Eßer }
55378bc019dSStefan Eßer else
55478bc019dSStefan Eßer {
55550696a6eSStefan Eßer min = ardx;
55650696a6eSStefan Eßer diff = brdx - ardx;
557252884aeSStefan Eßer max_num = b->num + diff;
558252884aeSStefan Eßer min_num = a->num;
559252884aeSStefan Eßer }
560252884aeSStefan Eßer
56144d4804dSStefan Eßer // Do a full limb-by-limb comparison.
562252884aeSStefan Eßer cmp = bc_num_compare(max_num, min_num, b_int + min);
563252884aeSStefan Eßer
56444d4804dSStefan Eßer // If we found a difference, return it based on state.
565252884aeSStefan Eßer if (cmp) return bc_num_neg((size_t) cmp, !a_max == !neg);
566252884aeSStefan Eßer
56744d4804dSStefan Eßer // If there was no difference, then the final step is to check which number
56844d4804dSStefan Eßer // has greater or lesser limbs beyond the other's.
56978bc019dSStefan Eßer for (max_num -= diff, i = diff - 1; i < diff; --i)
57078bc019dSStefan Eßer {
571252884aeSStefan Eßer if (max_num[i]) return bc_num_neg(1, !a_max == !neg);
572252884aeSStefan Eßer }
573252884aeSStefan Eßer
574252884aeSStefan Eßer return 0;
575252884aeSStefan Eßer }
576252884aeSStefan Eßer
57778bc019dSStefan Eßer void
bc_num_truncate(BcNum * restrict n,size_t places)57878bc019dSStefan Eßer bc_num_truncate(BcNum* restrict n, size_t places)
57978bc019dSStefan Eßer {
58050696a6eSStefan Eßer size_t nrdx, places_rdx;
581252884aeSStefan Eßer
582252884aeSStefan Eßer if (!places) return;
583252884aeSStefan Eßer
58444d4804dSStefan Eßer // Grab these needed values; places_rdx is the rdx equivalent to places like
58544d4804dSStefan Eßer // rdx is to scale.
58650696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL(n);
58750696a6eSStefan Eßer places_rdx = nrdx ? nrdx - BC_NUM_RDX(n->scale - places) : 0;
58844d4804dSStefan Eßer
58944d4804dSStefan Eßer // We cannot truncate more places than we have.
590252884aeSStefan Eßer assert(places <= n->scale && (BC_NUM_ZERO(n) || places_rdx <= n->len));
591252884aeSStefan Eßer
592252884aeSStefan Eßer n->scale -= places;
59350696a6eSStefan Eßer BC_NUM_RDX_SET(n, nrdx - places_rdx);
594252884aeSStefan Eßer
59544d4804dSStefan Eßer // Only when the number is nonzero do we need to do the hard stuff.
59678bc019dSStefan Eßer if (BC_NUM_NONZERO(n))
59778bc019dSStefan Eßer {
598252884aeSStefan Eßer size_t pow;
599252884aeSStefan Eßer
60044d4804dSStefan Eßer // This calculates how many decimal digits are in the least significant
601a970610aSStefan Eßer // limb, then gets the power for that.
602a970610aSStefan Eßer pow = bc_num_leastSigPow(n->scale);
603252884aeSStefan Eßer
604252884aeSStefan Eßer n->len -= places_rdx;
60544d4804dSStefan Eßer
60644d4804dSStefan Eßer // We have to move limbs to maintain invariants. The limbs must begin at
60744d4804dSStefan Eßer // the beginning of the BcNum array.
60878bc019dSStefan Eßer // NOLINTNEXTLINE
609252884aeSStefan Eßer memmove(n->num, n->num + places_rdx, BC_NUM_SIZE(n->len));
610252884aeSStefan Eßer
611252884aeSStefan Eßer // Clear the lower part of the last digit.
612252884aeSStefan Eßer if (BC_NUM_NONZERO(n)) n->num[0] -= n->num[0] % (BcDig) pow;
613252884aeSStefan Eßer
614252884aeSStefan Eßer bc_num_clean(n);
615252884aeSStefan Eßer }
616252884aeSStefan Eßer }
617252884aeSStefan Eßer
61878bc019dSStefan Eßer void
bc_num_extend(BcNum * restrict n,size_t places)61978bc019dSStefan Eßer bc_num_extend(BcNum* restrict n, size_t places)
62078bc019dSStefan Eßer {
62150696a6eSStefan Eßer size_t nrdx, places_rdx;
622252884aeSStefan Eßer
623252884aeSStefan Eßer if (!places) return;
62444d4804dSStefan Eßer
62544d4804dSStefan Eßer // Easy case with zero; set the scale.
62678bc019dSStefan Eßer if (BC_NUM_ZERO(n))
62778bc019dSStefan Eßer {
628252884aeSStefan Eßer n->scale += places;
629252884aeSStefan Eßer return;
630252884aeSStefan Eßer }
631252884aeSStefan Eßer
63244d4804dSStefan Eßer // Grab these needed values; places_rdx is the rdx equivalent to places like
63344d4804dSStefan Eßer // rdx is to scale.
63450696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL(n);
63550696a6eSStefan Eßer places_rdx = BC_NUM_RDX(places + n->scale) - nrdx;
636252884aeSStefan Eßer
63744d4804dSStefan Eßer // This is the hard case. We need to expand the number, move the limbs, and
63844d4804dSStefan Eßer // set the limbs that were just cleared.
63978bc019dSStefan Eßer if (places_rdx)
64078bc019dSStefan Eßer {
641252884aeSStefan Eßer bc_num_expand(n, bc_vm_growSize(n->len, places_rdx));
64278bc019dSStefan Eßer // NOLINTNEXTLINE
643252884aeSStefan Eßer memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len));
64478bc019dSStefan Eßer // NOLINTNEXTLINE
645252884aeSStefan Eßer memset(n->num, 0, BC_NUM_SIZE(places_rdx));
646252884aeSStefan Eßer }
647252884aeSStefan Eßer
64844d4804dSStefan Eßer // Finally, set scale and rdx.
64950696a6eSStefan Eßer BC_NUM_RDX_SET(n, nrdx + places_rdx);
650252884aeSStefan Eßer n->scale += places;
651252884aeSStefan Eßer n->len += places_rdx;
652252884aeSStefan Eßer
65350696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(n) == BC_NUM_RDX(n->scale));
654252884aeSStefan Eßer }
655252884aeSStefan Eßer
65644d4804dSStefan Eßer /**
65744d4804dSStefan Eßer * Retires (finishes) a multiplication or division operation.
65844d4804dSStefan Eßer */
65978bc019dSStefan Eßer static void
bc_num_retireMul(BcNum * restrict n,size_t scale,bool neg1,bool neg2)66078bc019dSStefan Eßer bc_num_retireMul(BcNum* restrict n, size_t scale, bool neg1, bool neg2)
661252884aeSStefan Eßer {
66244d4804dSStefan Eßer // Make sure scale is correct.
663252884aeSStefan Eßer if (n->scale < scale) bc_num_extend(n, scale - n->scale);
664252884aeSStefan Eßer else bc_num_truncate(n, n->scale - scale);
665252884aeSStefan Eßer
666252884aeSStefan Eßer bc_num_clean(n);
66744d4804dSStefan Eßer
66844d4804dSStefan Eßer // We need to ensure rdx is correct.
66950696a6eSStefan Eßer if (BC_NUM_NONZERO(n)) n->rdx = BC_NUM_NEG_VAL(n, !neg1 != !neg2);
670252884aeSStefan Eßer }
671252884aeSStefan Eßer
67244d4804dSStefan Eßer /**
67344d4804dSStefan Eßer * Splits a number into two BcNum's. This is used in Karatsuba.
67444d4804dSStefan Eßer * @param n The number to split.
67544d4804dSStefan Eßer * @param idx The index to split at.
67644d4804dSStefan Eßer * @param a An out parameter; the low part of @a n.
67744d4804dSStefan Eßer * @param b An out parameter; the high part of @a n.
67844d4804dSStefan Eßer */
67978bc019dSStefan Eßer static void
bc_num_split(const BcNum * restrict n,size_t idx,BcNum * restrict a,BcNum * restrict b)68078bc019dSStefan Eßer bc_num_split(const BcNum* restrict n, size_t idx, BcNum* restrict a,
68178bc019dSStefan Eßer BcNum* restrict b)
682252884aeSStefan Eßer {
68344d4804dSStefan Eßer // We want a and b to be clear.
684252884aeSStefan Eßer assert(BC_NUM_ZERO(a));
685252884aeSStefan Eßer assert(BC_NUM_ZERO(b));
686252884aeSStefan Eßer
68744d4804dSStefan Eßer // The usual case.
68878bc019dSStefan Eßer if (idx < n->len)
68978bc019dSStefan Eßer {
69044d4804dSStefan Eßer // Set the fields first.
691252884aeSStefan Eßer b->len = n->len - idx;
692252884aeSStefan Eßer a->len = idx;
69350696a6eSStefan Eßer a->scale = b->scale = 0;
69450696a6eSStefan Eßer BC_NUM_RDX_SET(a, 0);
69550696a6eSStefan Eßer BC_NUM_RDX_SET(b, 0);
696252884aeSStefan Eßer
697252884aeSStefan Eßer assert(a->cap >= a->len);
698252884aeSStefan Eßer assert(b->cap >= b->len);
699252884aeSStefan Eßer
70044d4804dSStefan Eßer // Copy the arrays. This is not necessary for safety, but it is faster,
70144d4804dSStefan Eßer // for some reason.
70278bc019dSStefan Eßer // NOLINTNEXTLINE
703252884aeSStefan Eßer memcpy(b->num, n->num + idx, BC_NUM_SIZE(b->len));
70478bc019dSStefan Eßer // NOLINTNEXTLINE
705252884aeSStefan Eßer memcpy(a->num, n->num, BC_NUM_SIZE(idx));
706252884aeSStefan Eßer
707252884aeSStefan Eßer bc_num_clean(b);
708252884aeSStefan Eßer }
70944d4804dSStefan Eßer // If the index is weird, just skip the split.
710252884aeSStefan Eßer else bc_num_copy(a, n);
711252884aeSStefan Eßer
712252884aeSStefan Eßer bc_num_clean(a);
713252884aeSStefan Eßer }
714252884aeSStefan Eßer
71544d4804dSStefan Eßer /**
71644d4804dSStefan Eßer * Copies a number into another, but shifts the rdx so that the result number
71744d4804dSStefan Eßer * only sees the integer part of the source number.
71844d4804dSStefan Eßer * @param n The number to copy.
71944d4804dSStefan Eßer * @param r The result number with a shifted rdx, len, and num.
72044d4804dSStefan Eßer */
72178bc019dSStefan Eßer static void
bc_num_shiftRdx(const BcNum * restrict n,BcNum * restrict r)72278bc019dSStefan Eßer bc_num_shiftRdx(const BcNum* restrict n, BcNum* restrict r)
72378bc019dSStefan Eßer {
72444d4804dSStefan Eßer size_t rdx = BC_NUM_RDX_VAL(n);
72544d4804dSStefan Eßer
72644d4804dSStefan Eßer r->len = n->len - rdx;
72744d4804dSStefan Eßer r->cap = n->cap - rdx;
72844d4804dSStefan Eßer r->num = n->num + rdx;
72944d4804dSStefan Eßer
73044d4804dSStefan Eßer BC_NUM_RDX_SET_NEG(r, 0, BC_NUM_NEG(n));
73144d4804dSStefan Eßer r->scale = 0;
73244d4804dSStefan Eßer }
73344d4804dSStefan Eßer
73444d4804dSStefan Eßer /**
73544d4804dSStefan Eßer * Shifts a number so that all of the least significant limbs of the number are
73644d4804dSStefan Eßer * skipped. This must be undone by bc_num_unshiftZero().
73744d4804dSStefan Eßer * @param n The number to shift.
73844d4804dSStefan Eßer */
73978bc019dSStefan Eßer static size_t
bc_num_shiftZero(BcNum * restrict n)74078bc019dSStefan Eßer bc_num_shiftZero(BcNum* restrict n)
74178bc019dSStefan Eßer {
742d101cdd6SStefan Eßer // This is volatile to quiet a GCC warning about longjmp() clobbering.
743d101cdd6SStefan Eßer volatile size_t i;
744252884aeSStefan Eßer
74544d4804dSStefan Eßer // If we don't have an integer, that is a problem, but it's also a bug
74644d4804dSStefan Eßer // because the caller should have set everything up right.
74750696a6eSStefan Eßer assert(!BC_NUM_RDX_VAL(n) || BC_NUM_ZERO(n));
748252884aeSStefan Eßer
74978bc019dSStefan Eßer for (i = 0; i < n->len && !n->num[i]; ++i)
75078bc019dSStefan Eßer {
75178bc019dSStefan Eßer continue;
75278bc019dSStefan Eßer }
753252884aeSStefan Eßer
754252884aeSStefan Eßer n->len -= i;
755252884aeSStefan Eßer n->num += i;
756252884aeSStefan Eßer
757252884aeSStefan Eßer return i;
758252884aeSStefan Eßer }
759252884aeSStefan Eßer
76044d4804dSStefan Eßer /**
76144d4804dSStefan Eßer * Undo the damage done by bc_num_unshiftZero(). This must be called like all
76244d4804dSStefan Eßer * cleanup functions: after a label used by setjmp() and longjmp().
76344d4804dSStefan Eßer * @param n The number to unshift.
76444d4804dSStefan Eßer * @param places_rdx The amount the number was originally shift.
76544d4804dSStefan Eßer */
76678bc019dSStefan Eßer static void
bc_num_unshiftZero(BcNum * restrict n,size_t places_rdx)76778bc019dSStefan Eßer bc_num_unshiftZero(BcNum* restrict n, size_t places_rdx)
76878bc019dSStefan Eßer {
769252884aeSStefan Eßer n->len += places_rdx;
770252884aeSStefan Eßer n->num -= places_rdx;
771252884aeSStefan Eßer }
772252884aeSStefan Eßer
77344d4804dSStefan Eßer /**
77444d4804dSStefan Eßer * Shifts the digits right within a number by no more than BC_BASE_DIGS - 1.
77544d4804dSStefan Eßer * This is the final step on shifting numbers with the shift operators. It
77644d4804dSStefan Eßer * depends on the caller to shift the limbs properly because all it does is
77744d4804dSStefan Eßer * ensure that the rdx point is realigned to be between limbs.
77844d4804dSStefan Eßer * @param n The number to shift digits in.
77944d4804dSStefan Eßer * @param dig The number of places to shift right.
78044d4804dSStefan Eßer */
78178bc019dSStefan Eßer static void
bc_num_shift(BcNum * restrict n,BcBigDig dig)78278bc019dSStefan Eßer bc_num_shift(BcNum* restrict n, BcBigDig dig)
78378bc019dSStefan Eßer {
784252884aeSStefan Eßer size_t i, len = n->len;
785252884aeSStefan Eßer BcBigDig carry = 0, pow;
786252884aeSStefan Eßer BcDig* ptr = n->num;
787252884aeSStefan Eßer
788252884aeSStefan Eßer assert(dig < BC_BASE_DIGS);
789252884aeSStefan Eßer
79044d4804dSStefan Eßer // Figure out the parameters for division.
791252884aeSStefan Eßer pow = bc_num_pow10[dig];
792252884aeSStefan Eßer dig = bc_num_pow10[BC_BASE_DIGS - dig];
793252884aeSStefan Eßer
79444d4804dSStefan Eßer // Run a series of divisions and mods with carries across the entire number
79544d4804dSStefan Eßer // array. This effectively shifts everything over.
79678bc019dSStefan Eßer for (i = len - 1; i < len; --i)
79778bc019dSStefan Eßer {
798252884aeSStefan Eßer BcBigDig in, temp;
799252884aeSStefan Eßer in = ((BcBigDig) ptr[i]);
800252884aeSStefan Eßer temp = carry * dig;
801252884aeSStefan Eßer carry = in % pow;
802252884aeSStefan Eßer ptr[i] = ((BcDig) (in / pow)) + (BcDig) temp;
803d101cdd6SStefan Eßer assert(ptr[i] >= 0 && ptr[i] < BC_BASE_POW);
804252884aeSStefan Eßer }
805252884aeSStefan Eßer
806252884aeSStefan Eßer assert(!carry);
807252884aeSStefan Eßer }
808252884aeSStefan Eßer
80944d4804dSStefan Eßer /**
81044d4804dSStefan Eßer * Shift a number left by a certain number of places. This is the workhorse of
81144d4804dSStefan Eßer * the left shift operator.
81244d4804dSStefan Eßer * @param n The number to shift left.
81344d4804dSStefan Eßer * @param places The amount of places to shift @a n left by.
81444d4804dSStefan Eßer */
81578bc019dSStefan Eßer static void
bc_num_shiftLeft(BcNum * restrict n,size_t places)81678bc019dSStefan Eßer bc_num_shiftLeft(BcNum* restrict n, size_t places)
81778bc019dSStefan Eßer {
818252884aeSStefan Eßer BcBigDig dig;
819252884aeSStefan Eßer size_t places_rdx;
820252884aeSStefan Eßer bool shift;
821252884aeSStefan Eßer
822252884aeSStefan Eßer if (!places) return;
82344d4804dSStefan Eßer
82444d4804dSStefan Eßer // Make sure to grow the number if necessary.
82578bc019dSStefan Eßer if (places > n->scale)
82678bc019dSStefan Eßer {
827252884aeSStefan Eßer size_t size = bc_vm_growSize(BC_NUM_RDX(places - n->scale), n->len);
82844d4804dSStefan Eßer if (size > SIZE_MAX - 1) bc_err(BC_ERR_MATH_OVERFLOW);
829252884aeSStefan Eßer }
83044d4804dSStefan Eßer
83144d4804dSStefan Eßer // If zero, we can just set the scale and bail.
83278bc019dSStefan Eßer if (BC_NUM_ZERO(n))
83378bc019dSStefan Eßer {
834252884aeSStefan Eßer if (n->scale >= places) n->scale -= places;
835252884aeSStefan Eßer else n->scale = 0;
836252884aeSStefan Eßer return;
837252884aeSStefan Eßer }
838252884aeSStefan Eßer
83944d4804dSStefan Eßer // When I changed bc to have multiple digits per limb, this was the hardest
84044d4804dSStefan Eßer // code to change. This and shift right. Make sure you understand this
84144d4804dSStefan Eßer // before attempting anything.
84244d4804dSStefan Eßer
84344d4804dSStefan Eßer // This is how many limbs we will shift.
844252884aeSStefan Eßer dig = (BcBigDig) (places % BC_BASE_DIGS);
845252884aeSStefan Eßer shift = (dig != 0);
84644d4804dSStefan Eßer
84744d4804dSStefan Eßer // Convert places to a rdx value.
848252884aeSStefan Eßer places_rdx = BC_NUM_RDX(places);
849252884aeSStefan Eßer
85044d4804dSStefan Eßer // If the number is not an integer, we need special care. The reason an
85144d4804dSStefan Eßer // integer doesn't is because left shift would only extend the integer,
85244d4804dSStefan Eßer // whereas a non-integer might have its fractional part eliminated or only
85344d4804dSStefan Eßer // partially eliminated.
85478bc019dSStefan Eßer if (n->scale)
85578bc019dSStefan Eßer {
85650696a6eSStefan Eßer size_t nrdx = BC_NUM_RDX_VAL(n);
85750696a6eSStefan Eßer
85844d4804dSStefan Eßer // If the number's rdx is bigger, that's the hard case.
85978bc019dSStefan Eßer if (nrdx >= places_rdx)
86078bc019dSStefan Eßer {
861252884aeSStefan Eßer size_t mod = n->scale % BC_BASE_DIGS, revdig;
862252884aeSStefan Eßer
86344d4804dSStefan Eßer // We want mod to be in the range [1, BC_BASE_DIGS], not
86444d4804dSStefan Eßer // [0, BC_BASE_DIGS).
865252884aeSStefan Eßer mod = mod ? mod : BC_BASE_DIGS;
86644d4804dSStefan Eßer
86744d4804dSStefan Eßer // We need to reverse dig to get the actual number of digits.
868252884aeSStefan Eßer revdig = dig ? BC_BASE_DIGS - dig : 0;
869252884aeSStefan Eßer
87044d4804dSStefan Eßer // If the two overflow BC_BASE_DIGS, we need to move an extra place.
871252884aeSStefan Eßer if (mod + revdig > BC_BASE_DIGS) places_rdx = 1;
872252884aeSStefan Eßer else places_rdx = 0;
873252884aeSStefan Eßer }
87450696a6eSStefan Eßer else places_rdx -= nrdx;
875252884aeSStefan Eßer }
876252884aeSStefan Eßer
87744d4804dSStefan Eßer // If this is non-zero, we need an extra place, so expand, move, and set.
87878bc019dSStefan Eßer if (places_rdx)
87978bc019dSStefan Eßer {
880252884aeSStefan Eßer bc_num_expand(n, bc_vm_growSize(n->len, places_rdx));
88178bc019dSStefan Eßer // NOLINTNEXTLINE
882252884aeSStefan Eßer memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len));
88378bc019dSStefan Eßer // NOLINTNEXTLINE
884252884aeSStefan Eßer memset(n->num, 0, BC_NUM_SIZE(places_rdx));
885252884aeSStefan Eßer n->len += places_rdx;
886252884aeSStefan Eßer }
887252884aeSStefan Eßer
88844d4804dSStefan Eßer // Set the scale appropriately.
88978bc019dSStefan Eßer if (places > n->scale)
89078bc019dSStefan Eßer {
89150696a6eSStefan Eßer n->scale = 0;
89250696a6eSStefan Eßer BC_NUM_RDX_SET(n, 0);
89350696a6eSStefan Eßer }
89478bc019dSStefan Eßer else
89578bc019dSStefan Eßer {
896252884aeSStefan Eßer n->scale -= places;
89750696a6eSStefan Eßer BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale));
898252884aeSStefan Eßer }
899252884aeSStefan Eßer
90044d4804dSStefan Eßer // Finally, shift within limbs.
901252884aeSStefan Eßer if (shift) bc_num_shift(n, BC_BASE_DIGS - dig);
902252884aeSStefan Eßer
903252884aeSStefan Eßer bc_num_clean(n);
904252884aeSStefan Eßer }
905252884aeSStefan Eßer
90678bc019dSStefan Eßer void
bc_num_shiftRight(BcNum * restrict n,size_t places)90778bc019dSStefan Eßer bc_num_shiftRight(BcNum* restrict n, size_t places)
90878bc019dSStefan Eßer {
909252884aeSStefan Eßer BcBigDig dig;
910252884aeSStefan Eßer size_t places_rdx, scale, scale_mod, int_len, expand;
911252884aeSStefan Eßer bool shift;
912252884aeSStefan Eßer
913252884aeSStefan Eßer if (!places) return;
91444d4804dSStefan Eßer
91544d4804dSStefan Eßer // If zero, we can just set the scale and bail.
91678bc019dSStefan Eßer if (BC_NUM_ZERO(n))
91778bc019dSStefan Eßer {
918252884aeSStefan Eßer n->scale += places;
919252884aeSStefan Eßer bc_num_expand(n, BC_NUM_RDX(n->scale));
920252884aeSStefan Eßer return;
921252884aeSStefan Eßer }
922252884aeSStefan Eßer
92344d4804dSStefan Eßer // Amount within a limb we have to shift by.
924252884aeSStefan Eßer dig = (BcBigDig) (places % BC_BASE_DIGS);
925252884aeSStefan Eßer shift = (dig != 0);
92644d4804dSStefan Eßer
927252884aeSStefan Eßer scale = n->scale;
92844d4804dSStefan Eßer
92944d4804dSStefan Eßer // Figure out how the scale is affected.
930252884aeSStefan Eßer scale_mod = scale % BC_BASE_DIGS;
931252884aeSStefan Eßer scale_mod = scale_mod ? scale_mod : BC_BASE_DIGS;
93244d4804dSStefan Eßer
93344d4804dSStefan Eßer // We need to know the int length and rdx for places.
934252884aeSStefan Eßer int_len = bc_num_int(n);
935252884aeSStefan Eßer places_rdx = BC_NUM_RDX(places);
936252884aeSStefan Eßer
93744d4804dSStefan Eßer // If we are going to shift past a limb boundary or not, set accordingly.
93878bc019dSStefan Eßer if (scale_mod + dig > BC_BASE_DIGS)
93978bc019dSStefan Eßer {
940252884aeSStefan Eßer expand = places_rdx - 1;
941252884aeSStefan Eßer places_rdx = 1;
942252884aeSStefan Eßer }
94378bc019dSStefan Eßer else
94478bc019dSStefan Eßer {
945252884aeSStefan Eßer expand = places_rdx;
946252884aeSStefan Eßer places_rdx = 0;
947252884aeSStefan Eßer }
948252884aeSStefan Eßer
94944d4804dSStefan Eßer // Clamp expanding.
950252884aeSStefan Eßer if (expand > int_len) expand -= int_len;
951252884aeSStefan Eßer else expand = 0;
952252884aeSStefan Eßer
95344d4804dSStefan Eßer // Extend, expand, and zero.
954252884aeSStefan Eßer bc_num_extend(n, places_rdx * BC_BASE_DIGS);
955252884aeSStefan Eßer bc_num_expand(n, bc_vm_growSize(expand, n->len));
95678bc019dSStefan Eßer // NOLINTNEXTLINE
957252884aeSStefan Eßer memset(n->num + n->len, 0, BC_NUM_SIZE(expand));
95844d4804dSStefan Eßer
95944d4804dSStefan Eßer // Set the fields.
960252884aeSStefan Eßer n->len += expand;
96150696a6eSStefan Eßer n->scale = 0;
96250696a6eSStefan Eßer BC_NUM_RDX_SET(n, 0);
963252884aeSStefan Eßer
96444d4804dSStefan Eßer // Finally, shift within limbs.
965252884aeSStefan Eßer if (shift) bc_num_shift(n, dig);
966252884aeSStefan Eßer
967252884aeSStefan Eßer n->scale = scale + places;
96850696a6eSStefan Eßer BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale));
969252884aeSStefan Eßer
970252884aeSStefan Eßer bc_num_clean(n);
971252884aeSStefan Eßer
97250696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(n) <= n->len && n->len <= n->cap);
97350696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(n) == BC_NUM_RDX(n->scale));
974252884aeSStefan Eßer }
975252884aeSStefan Eßer
97644d4804dSStefan Eßer /**
97744d4804dSStefan Eßer * Tests if a number is a integer with scale or not. Returns true if the number
97844d4804dSStefan Eßer * is not an integer. If it is, its integer shifted form is copied into the
97944d4804dSStefan Eßer * result parameter for use where only integers are allowed.
98044d4804dSStefan Eßer * @param n The integer to test and shift.
98144d4804dSStefan Eßer * @param r The number to store the shifted result into. This number should
98244d4804dSStefan Eßer * *not* be allocated.
98344d4804dSStefan Eßer * @return True if the number is a non-integer, false otherwise.
98444d4804dSStefan Eßer */
98578bc019dSStefan Eßer static bool
bc_num_nonInt(const BcNum * restrict n,BcNum * restrict r)98678bc019dSStefan Eßer bc_num_nonInt(const BcNum* restrict n, BcNum* restrict r)
98778bc019dSStefan Eßer {
98844d4804dSStefan Eßer bool zero;
98944d4804dSStefan Eßer size_t i, rdx = BC_NUM_RDX_VAL(n);
99044d4804dSStefan Eßer
99178bc019dSStefan Eßer if (!rdx)
99278bc019dSStefan Eßer {
99378bc019dSStefan Eßer // NOLINTNEXTLINE
99444d4804dSStefan Eßer memcpy(r, n, sizeof(BcNum));
99544d4804dSStefan Eßer return false;
99644d4804dSStefan Eßer }
99744d4804dSStefan Eßer
99844d4804dSStefan Eßer zero = true;
99944d4804dSStefan Eßer
100078bc019dSStefan Eßer for (i = 0; zero && i < rdx; ++i)
100178bc019dSStefan Eßer {
100278bc019dSStefan Eßer zero = (n->num[i] == 0);
100378bc019dSStefan Eßer }
100444d4804dSStefan Eßer
100544d4804dSStefan Eßer if (BC_ERR(!zero)) return true;
100644d4804dSStefan Eßer
100744d4804dSStefan Eßer bc_num_shiftRdx(n, r);
100844d4804dSStefan Eßer
100944d4804dSStefan Eßer return false;
1010252884aeSStefan Eßer }
1011252884aeSStefan Eßer
1012252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
101344d4804dSStefan Eßer
101444d4804dSStefan Eßer /**
101544d4804dSStefan Eßer * Execute common code for an operater that needs an integer for the second
101644d4804dSStefan Eßer * operand and return the integer operand as a BcBigDig.
101744d4804dSStefan Eßer * @param a The first operand.
101844d4804dSStefan Eßer * @param b The second operand.
101944d4804dSStefan Eßer * @param c The result operand.
102044d4804dSStefan Eßer * @return The second operand as a hardware integer.
102144d4804dSStefan Eßer */
102278bc019dSStefan Eßer static BcBigDig
bc_num_intop(const BcNum * a,const BcNum * b,BcNum * restrict c)102378bc019dSStefan Eßer bc_num_intop(const BcNum* a, const BcNum* b, BcNum* restrict c)
1024252884aeSStefan Eßer {
102544d4804dSStefan Eßer BcNum temp;
102644d4804dSStefan Eßer
1027d101cdd6SStefan Eßer #if BC_GCC
1028d101cdd6SStefan Eßer temp.len = 0;
1029d101cdd6SStefan Eßer temp.rdx = 0;
1030d101cdd6SStefan Eßer temp.num = NULL;
1031d101cdd6SStefan Eßer #endif // BC_GCC
1032d101cdd6SStefan Eßer
103344d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(b, &temp))) bc_err(BC_ERR_MATH_NON_INTEGER);
103444d4804dSStefan Eßer
1035252884aeSStefan Eßer bc_num_copy(c, a);
103644d4804dSStefan Eßer
103744d4804dSStefan Eßer return bc_num_bigdig(&temp);
1038252884aeSStefan Eßer }
1039252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
1040252884aeSStefan Eßer
104144d4804dSStefan Eßer /**
104244d4804dSStefan Eßer * This is the actual implementation of add *and* subtract. Since this function
104344d4804dSStefan Eßer * doesn't need to use scale (per the bc spec), I am hijacking it to say whether
104444d4804dSStefan Eßer * it's doing an add or a subtract. And then I convert substraction to addition
104544d4804dSStefan Eßer * of negative second operand. This is a BcNumBinOp function.
104644d4804dSStefan Eßer * @param a The first operand.
104744d4804dSStefan Eßer * @param b The second operand.
104844d4804dSStefan Eßer * @param c The return parameter.
104944d4804dSStefan Eßer * @param sub Non-zero for a subtract, zero for an add.
105044d4804dSStefan Eßer */
105178bc019dSStefan Eßer static void
bc_num_as(BcNum * a,BcNum * b,BcNum * restrict c,size_t sub)105278bc019dSStefan Eßer bc_num_as(BcNum* a, BcNum* b, BcNum* restrict c, size_t sub)
105378bc019dSStefan Eßer {
105478bc019dSStefan Eßer BcDig* ptr_c;
105578bc019dSStefan Eßer BcDig* ptr_l;
105678bc019dSStefan Eßer BcDig* ptr_r;
1057252884aeSStefan Eßer size_t i, min_rdx, max_rdx, diff, a_int, b_int, min_len, max_len, max_int;
105850696a6eSStefan Eßer size_t len_l, len_r, ardx, brdx;
105950696a6eSStefan Eßer bool b_neg, do_sub, do_rev_sub, carry, c_neg;
1060252884aeSStefan Eßer
106178bc019dSStefan Eßer if (BC_NUM_ZERO(b))
106278bc019dSStefan Eßer {
1063252884aeSStefan Eßer bc_num_copy(c, a);
1064252884aeSStefan Eßer return;
1065252884aeSStefan Eßer }
106644d4804dSStefan Eßer
106778bc019dSStefan Eßer if (BC_NUM_ZERO(a))
106878bc019dSStefan Eßer {
1069252884aeSStefan Eßer bc_num_copy(c, b);
107050696a6eSStefan Eßer c->rdx = BC_NUM_NEG_VAL(c, BC_NUM_NEG(b) != sub);
1071252884aeSStefan Eßer return;
1072252884aeSStefan Eßer }
1073252884aeSStefan Eßer
1074252884aeSStefan Eßer // Invert sign of b if it is to be subtracted. This operation must
107544d4804dSStefan Eßer // precede the tests for any of the operands being zero.
107650696a6eSStefan Eßer b_neg = (BC_NUM_NEG(b) != sub);
1077252884aeSStefan Eßer
107844d4804dSStefan Eßer // Figure out if we will actually add the numbers if their signs are equal
107944d4804dSStefan Eßer // or subtract.
108050696a6eSStefan Eßer do_sub = (BC_NUM_NEG(a) != b_neg);
1081252884aeSStefan Eßer
1082252884aeSStefan Eßer a_int = bc_num_int(a);
1083252884aeSStefan Eßer b_int = bc_num_int(b);
1084252884aeSStefan Eßer max_int = BC_MAX(a_int, b_int);
1085252884aeSStefan Eßer
108644d4804dSStefan Eßer // Figure out which number will have its last limbs copied (for addition) or
108744d4804dSStefan Eßer // subtracted (for subtraction).
108850696a6eSStefan Eßer ardx = BC_NUM_RDX_VAL(a);
108950696a6eSStefan Eßer brdx = BC_NUM_RDX_VAL(b);
109050696a6eSStefan Eßer min_rdx = BC_MIN(ardx, brdx);
109150696a6eSStefan Eßer max_rdx = BC_MAX(ardx, brdx);
1092252884aeSStefan Eßer diff = max_rdx - min_rdx;
1093252884aeSStefan Eßer
1094252884aeSStefan Eßer max_len = max_int + max_rdx;
1095252884aeSStefan Eßer
109678bc019dSStefan Eßer if (do_sub)
109778bc019dSStefan Eßer {
1098252884aeSStefan Eßer // Check whether b has to be subtracted from a or a from b.
1099252884aeSStefan Eßer if (a_int != b_int) do_rev_sub = (a_int < b_int);
110050696a6eSStefan Eßer else if (ardx > brdx)
110178bc019dSStefan Eßer {
1102252884aeSStefan Eßer do_rev_sub = (bc_num_compare(a->num + diff, b->num, b->len) < 0);
1103252884aeSStefan Eßer }
110478bc019dSStefan Eßer else do_rev_sub = (bc_num_compare(a->num, b->num + diff, a->len) <= 0);
110578bc019dSStefan Eßer }
110678bc019dSStefan Eßer else
110778bc019dSStefan Eßer {
1108252884aeSStefan Eßer // The result array of the addition might come out one element
1109252884aeSStefan Eßer // longer than the bigger of the operand arrays.
1110252884aeSStefan Eßer max_len += 1;
1111252884aeSStefan Eßer do_rev_sub = (a_int < b_int);
1112252884aeSStefan Eßer }
1113252884aeSStefan Eßer
1114252884aeSStefan Eßer assert(max_len <= c->cap);
1115252884aeSStefan Eßer
111644d4804dSStefan Eßer // Cache values for simple code later.
111778bc019dSStefan Eßer if (do_rev_sub)
111878bc019dSStefan Eßer {
1119252884aeSStefan Eßer ptr_l = b->num;
1120252884aeSStefan Eßer ptr_r = a->num;
1121252884aeSStefan Eßer len_l = b->len;
1122252884aeSStefan Eßer len_r = a->len;
1123252884aeSStefan Eßer }
112478bc019dSStefan Eßer else
112578bc019dSStefan Eßer {
1126252884aeSStefan Eßer ptr_l = a->num;
1127252884aeSStefan Eßer ptr_r = b->num;
1128252884aeSStefan Eßer len_l = a->len;
1129252884aeSStefan Eßer len_r = b->len;
1130252884aeSStefan Eßer }
1131252884aeSStefan Eßer
1132252884aeSStefan Eßer ptr_c = c->num;
1133252884aeSStefan Eßer carry = false;
1134252884aeSStefan Eßer
113544d4804dSStefan Eßer // This is true if the numbers have a different number of limbs after the
113644d4804dSStefan Eßer // decimal point.
113778bc019dSStefan Eßer if (diff)
113878bc019dSStefan Eßer {
1139252884aeSStefan Eßer // If the rdx values of the operands do not match, the result will
1140252884aeSStefan Eßer // have low end elements that are the positive or negative trailing
1141252884aeSStefan Eßer // elements of the operand with higher rdx value.
114278bc019dSStefan Eßer if ((ardx > brdx) != do_rev_sub)
114378bc019dSStefan Eßer {
114450696a6eSStefan Eßer // !do_rev_sub && ardx > brdx || do_rev_sub && brdx > ardx
1145252884aeSStefan Eßer // The left operand has BcDig values that need to be copied,
1146252884aeSStefan Eßer // either from a or from b (in case of a reversed subtraction).
114778bc019dSStefan Eßer // NOLINTNEXTLINE
1148252884aeSStefan Eßer memcpy(ptr_c, ptr_l, BC_NUM_SIZE(diff));
1149252884aeSStefan Eßer ptr_l += diff;
1150252884aeSStefan Eßer len_l -= diff;
1151252884aeSStefan Eßer }
115278bc019dSStefan Eßer else
115378bc019dSStefan Eßer {
1154252884aeSStefan Eßer // The right operand has BcDig values that need to be copied
1155252884aeSStefan Eßer // or subtracted from zero (in case of a subtraction).
115678bc019dSStefan Eßer if (do_sub)
115778bc019dSStefan Eßer {
115850696a6eSStefan Eßer // do_sub (do_rev_sub && ardx > brdx ||
115950696a6eSStefan Eßer // !do_rev_sub && brdx > ardx)
1160252884aeSStefan Eßer for (i = 0; i < diff; i++)
116178bc019dSStefan Eßer {
1162252884aeSStefan Eßer ptr_c[i] = bc_num_subDigits(0, ptr_r[i], &carry);
1163252884aeSStefan Eßer }
116478bc019dSStefan Eßer }
116578bc019dSStefan Eßer else
116678bc019dSStefan Eßer {
116750696a6eSStefan Eßer // !do_sub && brdx > ardx
116878bc019dSStefan Eßer // NOLINTNEXTLINE
1169252884aeSStefan Eßer memcpy(ptr_c, ptr_r, BC_NUM_SIZE(diff));
1170252884aeSStefan Eßer }
1171252884aeSStefan Eßer
117244d4804dSStefan Eßer // Future code needs to ignore the limbs we just did.
1173252884aeSStefan Eßer ptr_r += diff;
1174252884aeSStefan Eßer len_r -= diff;
1175252884aeSStefan Eßer }
1176252884aeSStefan Eßer
117744d4804dSStefan Eßer // The return value pointer needs to ignore what we just did.
1178252884aeSStefan Eßer ptr_c += diff;
1179252884aeSStefan Eßer }
1180252884aeSStefan Eßer
118144d4804dSStefan Eßer // This is the length that can be directly added/subtracted.
1182252884aeSStefan Eßer min_len = BC_MIN(len_l, len_r);
1183252884aeSStefan Eßer
1184252884aeSStefan Eßer // After dealing with possible low array elements that depend on only one
118544d4804dSStefan Eßer // operand above, the actual add or subtract can be performed as if the rdx
118644d4804dSStefan Eßer // of both operands was the same.
118744d4804dSStefan Eßer //
1188252884aeSStefan Eßer // Inlining takes care of eliminating constant zero arguments to
1189252884aeSStefan Eßer // addDigit/subDigit (checked in disassembly of resulting bc binary
1190252884aeSStefan Eßer // compiled with gcc and clang).
119178bc019dSStefan Eßer if (do_sub)
119278bc019dSStefan Eßer {
119344d4804dSStefan Eßer // Actual subtraction.
1194252884aeSStefan Eßer for (i = 0; i < min_len; ++i)
119578bc019dSStefan Eßer {
1196252884aeSStefan Eßer ptr_c[i] = bc_num_subDigits(ptr_l[i], ptr_r[i], &carry);
119778bc019dSStefan Eßer }
119844d4804dSStefan Eßer
119944d4804dSStefan Eßer // Finishing the limbs beyond the direct subtraction.
120078bc019dSStefan Eßer for (; i < len_l; ++i)
120178bc019dSStefan Eßer {
120278bc019dSStefan Eßer ptr_c[i] = bc_num_subDigits(ptr_l[i], 0, &carry);
1203252884aeSStefan Eßer }
120478bc019dSStefan Eßer }
120578bc019dSStefan Eßer else
120678bc019dSStefan Eßer {
120744d4804dSStefan Eßer // Actual addition.
1208252884aeSStefan Eßer for (i = 0; i < min_len; ++i)
120978bc019dSStefan Eßer {
1210252884aeSStefan Eßer ptr_c[i] = bc_num_addDigits(ptr_l[i], ptr_r[i], &carry);
121178bc019dSStefan Eßer }
121244d4804dSStefan Eßer
121344d4804dSStefan Eßer // Finishing the limbs beyond the direct addition.
121478bc019dSStefan Eßer for (; i < len_l; ++i)
121578bc019dSStefan Eßer {
121678bc019dSStefan Eßer ptr_c[i] = bc_num_addDigits(ptr_l[i], 0, &carry);
121778bc019dSStefan Eßer }
121844d4804dSStefan Eßer
121944d4804dSStefan Eßer // Addition can create an extra limb. We take care of that here.
1220252884aeSStefan Eßer ptr_c[i] = bc_num_addDigits(0, 0, &carry);
1221252884aeSStefan Eßer }
1222252884aeSStefan Eßer
1223252884aeSStefan Eßer assert(carry == false);
1224252884aeSStefan Eßer
1225252884aeSStefan Eßer // The result has the same sign as a, unless the operation was a
1226252884aeSStefan Eßer // reverse subtraction (b - a).
122750696a6eSStefan Eßer c_neg = BC_NUM_NEG(a) != (do_sub && do_rev_sub);
122850696a6eSStefan Eßer BC_NUM_RDX_SET_NEG(c, max_rdx, c_neg);
1229252884aeSStefan Eßer c->len = max_len;
1230252884aeSStefan Eßer c->scale = BC_MAX(a->scale, b->scale);
1231252884aeSStefan Eßer
1232252884aeSStefan Eßer bc_num_clean(c);
1233252884aeSStefan Eßer }
1234252884aeSStefan Eßer
123544d4804dSStefan Eßer /**
123644d4804dSStefan Eßer * The simple multiplication that karatsuba dishes out to when the length of the
123744d4804dSStefan Eßer * numbers gets low enough. This doesn't use scale because it treats the
123844d4804dSStefan Eßer * operands as though they are integers.
123944d4804dSStefan Eßer * @param a The first operand.
124044d4804dSStefan Eßer * @param b The second operand.
124144d4804dSStefan Eßer * @param c The return parameter.
124244d4804dSStefan Eßer */
124378bc019dSStefan Eßer static void
bc_num_m_simp(const BcNum * a,const BcNum * b,BcNum * restrict c)124478bc019dSStefan Eßer bc_num_m_simp(const BcNum* a, const BcNum* b, BcNum* restrict c)
124578bc019dSStefan Eßer {
1246252884aeSStefan Eßer size_t i, alen = a->len, blen = b->len, clen;
124778bc019dSStefan Eßer BcDig* ptr_a = a->num;
124878bc019dSStefan Eßer BcDig* ptr_b = b->num;
124978bc019dSStefan Eßer BcDig* ptr_c;
1250252884aeSStefan Eßer BcBigDig sum = 0, carry = 0;
1251252884aeSStefan Eßer
1252252884aeSStefan Eßer assert(sizeof(sum) >= sizeof(BcDig) * 2);
125350696a6eSStefan Eßer assert(!BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b));
1254252884aeSStefan Eßer
125544d4804dSStefan Eßer // Make sure c is big enough.
1256252884aeSStefan Eßer clen = bc_vm_growSize(alen, blen);
1257252884aeSStefan Eßer bc_num_expand(c, bc_vm_growSize(clen, 1));
1258252884aeSStefan Eßer
125944d4804dSStefan Eßer // If we don't memset, then we might have uninitialized data use later.
1260252884aeSStefan Eßer ptr_c = c->num;
126178bc019dSStefan Eßer // NOLINTNEXTLINE
1262252884aeSStefan Eßer memset(ptr_c, 0, BC_NUM_SIZE(c->cap));
1263252884aeSStefan Eßer
126444d4804dSStefan Eßer // This is the actual multiplication loop. It uses the lattice form of long
126544d4804dSStefan Eßer // multiplication (see the explanation on the web page at
126644d4804dSStefan Eßer // https://knilt.arcc.albany.edu/What_is_Lattice_Multiplication or the
126744d4804dSStefan Eßer // explanation at Wikipedia).
126878bc019dSStefan Eßer for (i = 0; i < clen; ++i)
126978bc019dSStefan Eßer {
1270252884aeSStefan Eßer ssize_t sidx = (ssize_t) (i - blen + 1);
127144d4804dSStefan Eßer size_t j, k;
1272252884aeSStefan Eßer
127344d4804dSStefan Eßer // These are the start indices.
127444d4804dSStefan Eßer j = (size_t) BC_MAX(0, sidx);
127544d4804dSStefan Eßer k = BC_MIN(i, blen - 1);
127644d4804dSStefan Eßer
127744d4804dSStefan Eßer // On every iteration of this loop, a multiplication happens, then the
127844d4804dSStefan Eßer // sum is automatically calculated.
127978bc019dSStefan Eßer for (; j < alen && k < blen; ++j, --k)
128078bc019dSStefan Eßer {
1281252884aeSStefan Eßer sum += ((BcBigDig) ptr_a[j]) * ((BcBigDig) ptr_b[k]);
1282252884aeSStefan Eßer
128378bc019dSStefan Eßer if (sum >= ((BcBigDig) BC_BASE_POW) * BC_BASE_POW)
128478bc019dSStefan Eßer {
1285252884aeSStefan Eßer carry += sum / BC_BASE_POW;
1286252884aeSStefan Eßer sum %= BC_BASE_POW;
1287252884aeSStefan Eßer }
1288252884aeSStefan Eßer }
1289252884aeSStefan Eßer
129044d4804dSStefan Eßer // Calculate the carry.
129178bc019dSStefan Eßer if (sum >= BC_BASE_POW)
129278bc019dSStefan Eßer {
1293252884aeSStefan Eßer carry += sum / BC_BASE_POW;
1294252884aeSStefan Eßer sum %= BC_BASE_POW;
1295252884aeSStefan Eßer }
1296252884aeSStefan Eßer
129744d4804dSStefan Eßer // Store and set up for next iteration.
1298252884aeSStefan Eßer ptr_c[i] = (BcDig) sum;
1299252884aeSStefan Eßer assert(ptr_c[i] < BC_BASE_POW);
1300252884aeSStefan Eßer sum = carry;
1301252884aeSStefan Eßer carry = 0;
1302252884aeSStefan Eßer }
1303252884aeSStefan Eßer
1304252884aeSStefan Eßer // This should always be true because there should be no carry on the last
1305252884aeSStefan Eßer // digit; multiplication never goes above the sum of both lengths.
1306252884aeSStefan Eßer assert(!sum);
1307252884aeSStefan Eßer
1308252884aeSStefan Eßer c->len = clen;
1309252884aeSStefan Eßer }
1310252884aeSStefan Eßer
131144d4804dSStefan Eßer /**
131244d4804dSStefan Eßer * Does a shifted add or subtract for Karatsuba below. This calls either
131344d4804dSStefan Eßer * bc_num_addArrays() or bc_num_subArrays().
131444d4804dSStefan Eßer * @param n An in/out parameter; the first operand and return parameter.
131544d4804dSStefan Eßer * @param a The second operand.
131644d4804dSStefan Eßer * @param shift The amount to shift @a n by when adding/subtracting.
131744d4804dSStefan Eßer * @param op The function to call, either bc_num_addArrays() or
131844d4804dSStefan Eßer * bc_num_subArrays().
131944d4804dSStefan Eßer */
132078bc019dSStefan Eßer static void
bc_num_shiftAddSub(BcNum * restrict n,const BcNum * restrict a,size_t shift,BcNumShiftAddOp op)132178bc019dSStefan Eßer bc_num_shiftAddSub(BcNum* restrict n, const BcNum* restrict a, size_t shift,
132278bc019dSStefan Eßer BcNumShiftAddOp op)
1323252884aeSStefan Eßer {
1324252884aeSStefan Eßer assert(n->len >= shift + a->len);
132550696a6eSStefan Eßer assert(!BC_NUM_RDX_VAL(n) && !BC_NUM_RDX_VAL(a));
1326252884aeSStefan Eßer op(n->num + shift, a->num, a->len);
1327252884aeSStefan Eßer }
1328252884aeSStefan Eßer
132944d4804dSStefan Eßer /**
133044d4804dSStefan Eßer * Implements the Karatsuba algorithm.
133144d4804dSStefan Eßer */
133278bc019dSStefan Eßer static void
bc_num_k(const BcNum * a,const BcNum * b,BcNum * restrict c)133378bc019dSStefan Eßer bc_num_k(const BcNum* a, const BcNum* b, BcNum* restrict c)
133478bc019dSStefan Eßer {
1335252884aeSStefan Eßer size_t max, max2, total;
1336252884aeSStefan Eßer BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
133778bc019dSStefan Eßer BcDig* digs;
133878bc019dSStefan Eßer BcDig* dig_ptr;
1339252884aeSStefan Eßer BcNumShiftAddOp op;
1340252884aeSStefan Eßer bool aone = BC_NUM_ONE(a);
1341d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
1342d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
1343d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
1344252884aeSStefan Eßer
1345252884aeSStefan Eßer assert(BC_NUM_ZERO(c));
1346252884aeSStefan Eßer
1347252884aeSStefan Eßer if (BC_NUM_ZERO(a) || BC_NUM_ZERO(b)) return;
134844d4804dSStefan Eßer
134978bc019dSStefan Eßer if (aone || BC_NUM_ONE(b))
135078bc019dSStefan Eßer {
1351252884aeSStefan Eßer bc_num_copy(c, aone ? b : a);
135250696a6eSStefan Eßer if ((aone && BC_NUM_NEG(a)) || BC_NUM_NEG(b)) BC_NUM_NEG_TGL(c);
1353252884aeSStefan Eßer return;
1354252884aeSStefan Eßer }
135544d4804dSStefan Eßer
135644d4804dSStefan Eßer // Shell out to the simple algorithm with certain conditions.
135778bc019dSStefan Eßer if (a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
135878bc019dSStefan Eßer {
1359252884aeSStefan Eßer bc_num_m_simp(a, b, c);
1360252884aeSStefan Eßer return;
1361252884aeSStefan Eßer }
1362252884aeSStefan Eßer
136344d4804dSStefan Eßer // We need to calculate the max size of the numbers that can result from the
136444d4804dSStefan Eßer // operations.
1365252884aeSStefan Eßer max = BC_MAX(a->len, b->len);
1366252884aeSStefan Eßer max = BC_MAX(max, BC_NUM_DEF_SIZE);
1367252884aeSStefan Eßer max2 = (max + 1) / 2;
1368252884aeSStefan Eßer
136944d4804dSStefan Eßer // Calculate the space needed for all of the temporary allocations. We do
137044d4804dSStefan Eßer // this to just allocate once.
1371252884aeSStefan Eßer total = bc_vm_arraySize(BC_NUM_KARATSUBA_ALLOCS, max);
1372252884aeSStefan Eßer
1373252884aeSStefan Eßer BC_SIG_LOCK;
1374252884aeSStefan Eßer
137544d4804dSStefan Eßer // Allocate space for all of the temporaries.
1376252884aeSStefan Eßer digs = dig_ptr = bc_vm_malloc(BC_NUM_SIZE(total));
1377252884aeSStefan Eßer
137844d4804dSStefan Eßer // Set up the temporaries.
1379252884aeSStefan Eßer bc_num_setup(&l1, dig_ptr, max);
1380252884aeSStefan Eßer dig_ptr += max;
1381252884aeSStefan Eßer bc_num_setup(&h1, dig_ptr, max);
1382252884aeSStefan Eßer dig_ptr += max;
1383252884aeSStefan Eßer bc_num_setup(&l2, dig_ptr, max);
1384252884aeSStefan Eßer dig_ptr += max;
1385252884aeSStefan Eßer bc_num_setup(&h2, dig_ptr, max);
1386252884aeSStefan Eßer dig_ptr += max;
1387252884aeSStefan Eßer bc_num_setup(&m1, dig_ptr, max);
1388252884aeSStefan Eßer dig_ptr += max;
1389252884aeSStefan Eßer bc_num_setup(&m2, dig_ptr, max);
139044d4804dSStefan Eßer
139144d4804dSStefan Eßer // Some temporaries need the ability to grow, so we allocate them
139244d4804dSStefan Eßer // separately.
1393252884aeSStefan Eßer max = bc_vm_growSize(max, 1);
1394252884aeSStefan Eßer bc_num_init(&z0, max);
1395252884aeSStefan Eßer bc_num_init(&z1, max);
1396252884aeSStefan Eßer bc_num_init(&z2, max);
1397252884aeSStefan Eßer max = bc_vm_growSize(max, max) + 1;
1398252884aeSStefan Eßer bc_num_init(&temp, max);
1399252884aeSStefan Eßer
1400d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
1401252884aeSStefan Eßer
1402252884aeSStefan Eßer BC_SIG_UNLOCK;
1403252884aeSStefan Eßer
140444d4804dSStefan Eßer // First, set up c.
1405252884aeSStefan Eßer bc_num_expand(c, max);
1406252884aeSStefan Eßer c->len = max;
140778bc019dSStefan Eßer // NOLINTNEXTLINE
1408252884aeSStefan Eßer memset(c->num, 0, BC_NUM_SIZE(c->len));
1409252884aeSStefan Eßer
141044d4804dSStefan Eßer // Split the parameters.
141144d4804dSStefan Eßer bc_num_split(a, max2, &l1, &h1);
141244d4804dSStefan Eßer bc_num_split(b, max2, &l2, &h2);
141344d4804dSStefan Eßer
141444d4804dSStefan Eßer // Do the subtraction.
1415252884aeSStefan Eßer bc_num_sub(&h1, &l1, &m1, 0);
1416252884aeSStefan Eßer bc_num_sub(&l2, &h2, &m2, 0);
1417252884aeSStefan Eßer
141844d4804dSStefan Eßer // The if statements below are there for efficiency reasons. The best way to
141944d4804dSStefan Eßer // understand them is to understand the Karatsuba algorithm because now that
142044d4804dSStefan Eßer // the ollocations and splits are done, the algorithm is pretty
142144d4804dSStefan Eßer // straightforward.
142244d4804dSStefan Eßer
142378bc019dSStefan Eßer if (BC_NUM_NONZERO(&h1) && BC_NUM_NONZERO(&h2))
142478bc019dSStefan Eßer {
142550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(h1));
142650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(h2));
142750696a6eSStefan Eßer
1428252884aeSStefan Eßer bc_num_m(&h1, &h2, &z2, 0);
1429252884aeSStefan Eßer bc_num_clean(&z2);
1430252884aeSStefan Eßer
1431252884aeSStefan Eßer bc_num_shiftAddSub(c, &z2, max2 * 2, bc_num_addArrays);
1432252884aeSStefan Eßer bc_num_shiftAddSub(c, &z2, max2, bc_num_addArrays);
1433252884aeSStefan Eßer }
1434252884aeSStefan Eßer
143578bc019dSStefan Eßer if (BC_NUM_NONZERO(&l1) && BC_NUM_NONZERO(&l2))
143678bc019dSStefan Eßer {
143750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(l1));
143850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(l2));
143950696a6eSStefan Eßer
1440252884aeSStefan Eßer bc_num_m(&l1, &l2, &z0, 0);
1441252884aeSStefan Eßer bc_num_clean(&z0);
1442252884aeSStefan Eßer
1443252884aeSStefan Eßer bc_num_shiftAddSub(c, &z0, max2, bc_num_addArrays);
1444252884aeSStefan Eßer bc_num_shiftAddSub(c, &z0, 0, bc_num_addArrays);
1445252884aeSStefan Eßer }
1446252884aeSStefan Eßer
144778bc019dSStefan Eßer if (BC_NUM_NONZERO(&m1) && BC_NUM_NONZERO(&m2))
144878bc019dSStefan Eßer {
144950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(m1));
145050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(m1));
145150696a6eSStefan Eßer
1452252884aeSStefan Eßer bc_num_m(&m1, &m2, &z1, 0);
1453252884aeSStefan Eßer bc_num_clean(&z1);
1454252884aeSStefan Eßer
145550696a6eSStefan Eßer op = (BC_NUM_NEG_NP(m1) != BC_NUM_NEG_NP(m2)) ?
145678bc019dSStefan Eßer bc_num_subArrays :
145778bc019dSStefan Eßer bc_num_addArrays;
1458252884aeSStefan Eßer bc_num_shiftAddSub(c, &z1, max2, op);
1459252884aeSStefan Eßer }
1460252884aeSStefan Eßer
1461252884aeSStefan Eßer err:
1462252884aeSStefan Eßer BC_SIG_MAYLOCK;
1463252884aeSStefan Eßer free(digs);
1464252884aeSStefan Eßer bc_num_free(&temp);
1465252884aeSStefan Eßer bc_num_free(&z2);
1466252884aeSStefan Eßer bc_num_free(&z1);
1467252884aeSStefan Eßer bc_num_free(&z0);
1468d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
1469252884aeSStefan Eßer }
1470252884aeSStefan Eßer
147144d4804dSStefan Eßer /**
147244d4804dSStefan Eßer * Does checks for Karatsuba. It also changes things to ensure that the
147344d4804dSStefan Eßer * Karatsuba and simple multiplication can treat the numbers as integers. This
147444d4804dSStefan Eßer * is a BcNumBinOp function.
147544d4804dSStefan Eßer * @param a The first operand.
147644d4804dSStefan Eßer * @param b The second operand.
147744d4804dSStefan Eßer * @param c The return parameter.
147844d4804dSStefan Eßer * @param scale The current scale.
147944d4804dSStefan Eßer */
148078bc019dSStefan Eßer static void
bc_num_m(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)148178bc019dSStefan Eßer bc_num_m(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
148278bc019dSStefan Eßer {
1483252884aeSStefan Eßer BcNum cpa, cpb;
1484d101cdd6SStefan Eßer size_t ascale, bscale, ardx, brdx, zero, len, rscale;
1485d101cdd6SStefan Eßer // These are meant to quiet warnings on GCC about longjmp() clobbering.
1486d101cdd6SStefan Eßer // The problem is real here.
1487d101cdd6SStefan Eßer size_t scale1, scale2, realscale;
1488d101cdd6SStefan Eßer // These are meant to quiet the GCC longjmp() clobbering, even though it
1489d101cdd6SStefan Eßer // does not apply here.
1490d101cdd6SStefan Eßer volatile size_t azero;
1491d101cdd6SStefan Eßer volatile size_t bzero;
1492d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
1493d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
1494d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
1495252884aeSStefan Eßer
149650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
149750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
149850696a6eSStefan Eßer
1499252884aeSStefan Eßer bc_num_zero(c);
150044d4804dSStefan Eßer
1501252884aeSStefan Eßer ascale = a->scale;
1502252884aeSStefan Eßer bscale = b->scale;
150344d4804dSStefan Eßer
150444d4804dSStefan Eßer // This sets the final scale according to the bc spec.
1505d101cdd6SStefan Eßer scale1 = BC_MAX(scale, ascale);
1506d101cdd6SStefan Eßer scale2 = BC_MAX(scale1, bscale);
1507252884aeSStefan Eßer rscale = ascale + bscale;
1508d101cdd6SStefan Eßer realscale = BC_MIN(rscale, scale2);
1509252884aeSStefan Eßer
151044d4804dSStefan Eßer // If this condition is true, we can use bc_num_mulArray(), which would be
151144d4804dSStefan Eßer // much faster.
151278bc019dSStefan Eßer if ((a->len == 1 || b->len == 1) && !a->rdx && !b->rdx)
151378bc019dSStefan Eßer {
1514252884aeSStefan Eßer BcNum* operand;
1515252884aeSStefan Eßer BcBigDig dig;
1516252884aeSStefan Eßer
151744d4804dSStefan Eßer // Set the correct operands.
151878bc019dSStefan Eßer if (a->len == 1)
151978bc019dSStefan Eßer {
1520252884aeSStefan Eßer dig = (BcBigDig) a->num[0];
1521252884aeSStefan Eßer operand = b;
1522252884aeSStefan Eßer }
152378bc019dSStefan Eßer else
152478bc019dSStefan Eßer {
1525252884aeSStefan Eßer dig = (BcBigDig) b->num[0];
1526252884aeSStefan Eßer operand = a;
1527252884aeSStefan Eßer }
1528252884aeSStefan Eßer
1529252884aeSStefan Eßer bc_num_mulArray(operand, dig, c);
1530252884aeSStefan Eßer
153144d4804dSStefan Eßer // Need to make sure the sign is correct.
153250696a6eSStefan Eßer if (BC_NUM_NONZERO(c))
153378bc019dSStefan Eßer {
153450696a6eSStefan Eßer c->rdx = BC_NUM_NEG_VAL(c, BC_NUM_NEG(a) != BC_NUM_NEG(b));
153578bc019dSStefan Eßer }
1536252884aeSStefan Eßer
1537252884aeSStefan Eßer return;
1538252884aeSStefan Eßer }
1539252884aeSStefan Eßer
154050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
154150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
154250696a6eSStefan Eßer
1543252884aeSStefan Eßer BC_SIG_LOCK;
1544252884aeSStefan Eßer
154544d4804dSStefan Eßer // We need copies because of all of the mutation needed to make Karatsuba
154644d4804dSStefan Eßer // think the numbers are integers.
154750696a6eSStefan Eßer bc_num_init(&cpa, a->len + BC_NUM_RDX_VAL(a));
154850696a6eSStefan Eßer bc_num_init(&cpb, b->len + BC_NUM_RDX_VAL(b));
1549252884aeSStefan Eßer
1550d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, init_err);
1551252884aeSStefan Eßer
1552252884aeSStefan Eßer BC_SIG_UNLOCK;
1553252884aeSStefan Eßer
1554252884aeSStefan Eßer bc_num_copy(&cpa, a);
1555252884aeSStefan Eßer bc_num_copy(&cpb, b);
1556252884aeSStefan Eßer
155750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(cpa));
155850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(cpb));
1559252884aeSStefan Eßer
156050696a6eSStefan Eßer BC_NUM_NEG_CLR_NP(cpa);
156150696a6eSStefan Eßer BC_NUM_NEG_CLR_NP(cpb);
156250696a6eSStefan Eßer
156350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(cpa));
156450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(cpb));
156550696a6eSStefan Eßer
156644d4804dSStefan Eßer // These are what makes them appear like integers.
156750696a6eSStefan Eßer ardx = BC_NUM_RDX_VAL_NP(cpa) * BC_BASE_DIGS;
1568252884aeSStefan Eßer bc_num_shiftLeft(&cpa, ardx);
1569252884aeSStefan Eßer
157050696a6eSStefan Eßer brdx = BC_NUM_RDX_VAL_NP(cpb) * BC_BASE_DIGS;
1571252884aeSStefan Eßer bc_num_shiftLeft(&cpb, brdx);
1572252884aeSStefan Eßer
1573252884aeSStefan Eßer // We need to reset the jump here because azero and bzero are used in the
1574252884aeSStefan Eßer // cleanup, and local variables are not guaranteed to be the same after a
1575252884aeSStefan Eßer // jump.
1576252884aeSStefan Eßer BC_SIG_LOCK;
1577252884aeSStefan Eßer
1578d101cdd6SStefan Eßer BC_UNSETJMP(vm);
1579252884aeSStefan Eßer
158044d4804dSStefan Eßer // We want to ignore zero limbs.
1581252884aeSStefan Eßer azero = bc_num_shiftZero(&cpa);
1582252884aeSStefan Eßer bzero = bc_num_shiftZero(&cpb);
1583252884aeSStefan Eßer
1584d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
1585252884aeSStefan Eßer
1586252884aeSStefan Eßer BC_SIG_UNLOCK;
1587252884aeSStefan Eßer
1588252884aeSStefan Eßer bc_num_clean(&cpa);
1589252884aeSStefan Eßer bc_num_clean(&cpb);
1590252884aeSStefan Eßer
1591252884aeSStefan Eßer bc_num_k(&cpa, &cpb, c);
1592252884aeSStefan Eßer
159344d4804dSStefan Eßer // The return parameter needs to have its scale set. This is the start. It
159444d4804dSStefan Eßer // also needs to be shifted by the same amount as a and b have limbs after
159544d4804dSStefan Eßer // the decimal point.
1596252884aeSStefan Eßer zero = bc_vm_growSize(azero, bzero);
1597252884aeSStefan Eßer len = bc_vm_growSize(c->len, zero);
1598252884aeSStefan Eßer
1599252884aeSStefan Eßer bc_num_expand(c, len);
160044d4804dSStefan Eßer
160144d4804dSStefan Eßer // Shift c based on the limbs after the decimal point in a and b.
1602252884aeSStefan Eßer bc_num_shiftLeft(c, (len - c->len) * BC_BASE_DIGS);
1603252884aeSStefan Eßer bc_num_shiftRight(c, ardx + brdx);
1604252884aeSStefan Eßer
1605d101cdd6SStefan Eßer bc_num_retireMul(c, realscale, BC_NUM_NEG(a), BC_NUM_NEG(b));
1606252884aeSStefan Eßer
1607252884aeSStefan Eßer err:
1608252884aeSStefan Eßer BC_SIG_MAYLOCK;
1609252884aeSStefan Eßer bc_num_unshiftZero(&cpb, bzero);
1610252884aeSStefan Eßer bc_num_unshiftZero(&cpa, azero);
1611d101cdd6SStefan Eßer init_err:
1612d101cdd6SStefan Eßer BC_SIG_MAYLOCK;
1613d101cdd6SStefan Eßer bc_num_free(&cpb);
1614252884aeSStefan Eßer bc_num_free(&cpa);
1615d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
1616252884aeSStefan Eßer }
1617252884aeSStefan Eßer
161844d4804dSStefan Eßer /**
161944d4804dSStefan Eßer * Returns true if the BcDig array has non-zero limbs, false otherwise.
162044d4804dSStefan Eßer * @param a The array to test.
162144d4804dSStefan Eßer * @param len The length of the array.
162244d4804dSStefan Eßer * @return True if @a has any non-zero limbs, false otherwise.
162344d4804dSStefan Eßer */
162478bc019dSStefan Eßer static bool
bc_num_nonZeroDig(BcDig * restrict a,size_t len)162578bc019dSStefan Eßer bc_num_nonZeroDig(BcDig* restrict a, size_t len)
162678bc019dSStefan Eßer {
1627252884aeSStefan Eßer size_t i;
162878bc019dSStefan Eßer
1629d101cdd6SStefan Eßer for (i = len - 1; i < len; --i)
163078bc019dSStefan Eßer {
1631d101cdd6SStefan Eßer if (a[i] != 0) return true;
163278bc019dSStefan Eßer }
163378bc019dSStefan Eßer
1634d101cdd6SStefan Eßer return false;
1635252884aeSStefan Eßer }
1636252884aeSStefan Eßer
163744d4804dSStefan Eßer /**
163844d4804dSStefan Eßer * Compares a BcDig array against a BcNum. This is especially suited for
163944d4804dSStefan Eßer * division. Returns >0 if @a a is greater than @a b, <0 if it is less, and =0
164044d4804dSStefan Eßer * if they are equal.
164144d4804dSStefan Eßer * @param a The array.
164244d4804dSStefan Eßer * @param b The number.
164344d4804dSStefan Eßer * @param len The length to assume the arrays are. This is always less than the
164444d4804dSStefan Eßer * actual length because of how this is implemented.
164544d4804dSStefan Eßer */
164678bc019dSStefan Eßer static ssize_t
bc_num_divCmp(const BcDig * a,const BcNum * b,size_t len)164778bc019dSStefan Eßer bc_num_divCmp(const BcDig* a, const BcNum* b, size_t len)
164878bc019dSStefan Eßer {
1649252884aeSStefan Eßer ssize_t cmp;
1650252884aeSStefan Eßer
1651252884aeSStefan Eßer if (b->len > len && a[len]) cmp = bc_num_compare(a, b->num, len + 1);
165278bc019dSStefan Eßer else if (b->len <= len)
165378bc019dSStefan Eßer {
1654252884aeSStefan Eßer if (a[len]) cmp = 1;
1655252884aeSStefan Eßer else cmp = bc_num_compare(a, b->num, len);
1656252884aeSStefan Eßer }
1657252884aeSStefan Eßer else cmp = -1;
1658252884aeSStefan Eßer
1659252884aeSStefan Eßer return cmp;
1660252884aeSStefan Eßer }
1661252884aeSStefan Eßer
166244d4804dSStefan Eßer /**
166344d4804dSStefan Eßer * Extends the two operands of a division by BC_BASE_DIGS minus the number of
166444d4804dSStefan Eßer * digits in the divisor estimate. In other words, it is shifting the numbers in
166544d4804dSStefan Eßer * order to force the divisor estimate to fill the limb.
166644d4804dSStefan Eßer * @param a The first operand.
166744d4804dSStefan Eßer * @param b The second operand.
166844d4804dSStefan Eßer * @param divisor The divisor estimate.
166944d4804dSStefan Eßer */
167078bc019dSStefan Eßer static void
bc_num_divExtend(BcNum * restrict a,BcNum * restrict b,BcBigDig divisor)167178bc019dSStefan Eßer bc_num_divExtend(BcNum* restrict a, BcNum* restrict b, BcBigDig divisor)
1672252884aeSStefan Eßer {
1673252884aeSStefan Eßer size_t pow;
1674252884aeSStefan Eßer
1675252884aeSStefan Eßer assert(divisor < BC_BASE_POW);
1676252884aeSStefan Eßer
1677252884aeSStefan Eßer pow = BC_BASE_DIGS - bc_num_log10((size_t) divisor);
1678252884aeSStefan Eßer
1679252884aeSStefan Eßer bc_num_shiftLeft(a, pow);
1680252884aeSStefan Eßer bc_num_shiftLeft(b, pow);
1681252884aeSStefan Eßer }
1682252884aeSStefan Eßer
168344d4804dSStefan Eßer /**
168444d4804dSStefan Eßer * Actually does division. This is a rewrite of my original code by Stefan Esser
168544d4804dSStefan Eßer * from FreeBSD.
168644d4804dSStefan Eßer * @param a The first operand.
168744d4804dSStefan Eßer * @param b The second operand.
168844d4804dSStefan Eßer * @param c The return parameter.
168944d4804dSStefan Eßer * @param scale The current scale.
169044d4804dSStefan Eßer */
169178bc019dSStefan Eßer static void
bc_num_d_long(BcNum * restrict a,BcNum * restrict b,BcNum * restrict c,size_t scale)169278bc019dSStefan Eßer bc_num_d_long(BcNum* restrict a, BcNum* restrict b, BcNum* restrict c,
169378bc019dSStefan Eßer size_t scale)
1694252884aeSStefan Eßer {
1695252884aeSStefan Eßer BcBigDig divisor;
1696d101cdd6SStefan Eßer size_t i, rdx;
1697d101cdd6SStefan Eßer // This is volatile and len 2 and reallen exist to quiet the GCC warning
1698d101cdd6SStefan Eßer // about clobbering on longjmp(). This one is possible, I think.
1699d101cdd6SStefan Eßer volatile size_t len;
1700d101cdd6SStefan Eßer size_t len2, reallen;
1701d101cdd6SStefan Eßer // This is volatile and realend exists to quiet the GCC warning about
1702d101cdd6SStefan Eßer // clobbering on longjmp(). This one is possible, I think.
1703d101cdd6SStefan Eßer volatile size_t end;
1704d101cdd6SStefan Eßer size_t realend;
1705252884aeSStefan Eßer BcNum cpb;
1706d101cdd6SStefan Eßer // This is volatile and realnonzero exists to quiet the GCC warning about
1707d101cdd6SStefan Eßer // clobbering on longjmp(). This one is possible, I think.
1708d101cdd6SStefan Eßer volatile bool nonzero;
1709d101cdd6SStefan Eßer bool realnonzero;
1710d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
1711d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
1712d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
1713252884aeSStefan Eßer
1714252884aeSStefan Eßer assert(b->len < a->len);
171544d4804dSStefan Eßer
1716252884aeSStefan Eßer len = b->len;
1717252884aeSStefan Eßer end = a->len - len;
171844d4804dSStefan Eßer
1719252884aeSStefan Eßer assert(len >= 1);
1720252884aeSStefan Eßer
172144d4804dSStefan Eßer // This is a final time to make sure c is big enough and that its array is
172244d4804dSStefan Eßer // properly zeroed.
1723252884aeSStefan Eßer bc_num_expand(c, a->len);
172478bc019dSStefan Eßer // NOLINTNEXTLINE
1725252884aeSStefan Eßer memset(c->num, 0, c->cap * sizeof(BcDig));
1726252884aeSStefan Eßer
172744d4804dSStefan Eßer // Setup.
172850696a6eSStefan Eßer BC_NUM_RDX_SET(c, BC_NUM_RDX_VAL(a));
1729252884aeSStefan Eßer c->scale = a->scale;
1730252884aeSStefan Eßer c->len = a->len;
1731252884aeSStefan Eßer
173244d4804dSStefan Eßer // This is pulling the most significant limb of b in order to establish a
173344d4804dSStefan Eßer // good "estimate" for the actual divisor.
1734252884aeSStefan Eßer divisor = (BcBigDig) b->num[len - 1];
1735252884aeSStefan Eßer
173644d4804dSStefan Eßer // The entire bit of code in this if statement is to tighten the estimate of
173744d4804dSStefan Eßer // the divisor. The condition asks if b has any other non-zero limbs.
173878bc019dSStefan Eßer if (len > 1 && bc_num_nonZeroDig(b->num, len - 1))
173978bc019dSStefan Eßer {
174044d4804dSStefan Eßer // This takes a little bit of understanding. The "10*BC_BASE_DIGS/6+1"
174144d4804dSStefan Eßer // results in either 16 for 64-bit 9-digit limbs or 7 for 32-bit 4-digit
174244d4804dSStefan Eßer // limbs. Then it shifts a 1 by that many, which in both cases, puts the
174344d4804dSStefan Eßer // result above *half* of the max value a limb can store. Basically,
174444d4804dSStefan Eßer // this quickly calculates if the divisor is greater than half the max
174544d4804dSStefan Eßer // of a limb.
1746252884aeSStefan Eßer nonzero = (divisor > 1 << ((10 * BC_BASE_DIGS) / 6 + 1));
1747252884aeSStefan Eßer
174844d4804dSStefan Eßer // If the divisor is *not* greater than half the limb...
174978bc019dSStefan Eßer if (!nonzero)
175078bc019dSStefan Eßer {
175144d4804dSStefan Eßer // Extend the parameters by the number of missing digits in the
175244d4804dSStefan Eßer // divisor.
1753252884aeSStefan Eßer bc_num_divExtend(a, b, divisor);
1754252884aeSStefan Eßer
175544d4804dSStefan Eßer // Check bc_num_d(). In there, we grow a again and again. We do it
175644d4804dSStefan Eßer // again here; we *always* want to be sure it is big enough.
1757d101cdd6SStefan Eßer len2 = BC_MAX(a->len, b->len);
1758d101cdd6SStefan Eßer bc_num_expand(a, len2 + 1);
1759252884aeSStefan Eßer
176044d4804dSStefan Eßer // Make a have a zero most significant limb to match the len.
1761d101cdd6SStefan Eßer if (len2 + 1 > a->len) a->len = len2 + 1;
1762252884aeSStefan Eßer
176344d4804dSStefan Eßer // Grab the new divisor estimate, new because the shift has made it
176444d4804dSStefan Eßer // different.
1765d101cdd6SStefan Eßer reallen = b->len;
1766d101cdd6SStefan Eßer realend = a->len - reallen;
1767d101cdd6SStefan Eßer divisor = (BcBigDig) b->num[reallen - 1];
1768252884aeSStefan Eßer
1769d101cdd6SStefan Eßer realnonzero = bc_num_nonZeroDig(b->num, reallen - 1);
1770252884aeSStefan Eßer }
1771d101cdd6SStefan Eßer else
1772d101cdd6SStefan Eßer {
1773d101cdd6SStefan Eßer realend = end;
1774d101cdd6SStefan Eßer realnonzero = nonzero;
1775d101cdd6SStefan Eßer }
1776d101cdd6SStefan Eßer }
1777d101cdd6SStefan Eßer else
1778d101cdd6SStefan Eßer {
1779d101cdd6SStefan Eßer realend = end;
1780d101cdd6SStefan Eßer realnonzero = false;
1781252884aeSStefan Eßer }
1782252884aeSStefan Eßer
178344d4804dSStefan Eßer // If b has other nonzero limbs, we want the divisor to be one higher, so
178444d4804dSStefan Eßer // that it is an upper bound.
1785d101cdd6SStefan Eßer divisor += realnonzero;
1786252884aeSStefan Eßer
178744d4804dSStefan Eßer // Make sure c can fit the new length.
1788252884aeSStefan Eßer bc_num_expand(c, a->len);
178978bc019dSStefan Eßer // NOLINTNEXTLINE
1790252884aeSStefan Eßer memset(c->num, 0, BC_NUM_SIZE(c->cap));
1791252884aeSStefan Eßer
1792252884aeSStefan Eßer assert(c->scale >= scale);
179350696a6eSStefan Eßer rdx = BC_NUM_RDX_VAL(c) - BC_NUM_RDX(scale);
1794252884aeSStefan Eßer
1795252884aeSStefan Eßer BC_SIG_LOCK;
1796252884aeSStefan Eßer
1797252884aeSStefan Eßer bc_num_init(&cpb, len + 1);
1798252884aeSStefan Eßer
1799d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
1800252884aeSStefan Eßer
1801252884aeSStefan Eßer BC_SIG_UNLOCK;
1802252884aeSStefan Eßer
180344d4804dSStefan Eßer // This is the actual division loop.
1804d101cdd6SStefan Eßer for (i = realend - 1; i < realend && i >= rdx && BC_NUM_NONZERO(a); --i)
180578bc019dSStefan Eßer {
1806252884aeSStefan Eßer ssize_t cmp;
1807252884aeSStefan Eßer BcDig* n;
1808252884aeSStefan Eßer BcBigDig result;
1809252884aeSStefan Eßer
1810252884aeSStefan Eßer n = a->num + i;
1811252884aeSStefan Eßer assert(n >= a->num);
1812252884aeSStefan Eßer result = 0;
1813252884aeSStefan Eßer
1814252884aeSStefan Eßer cmp = bc_num_divCmp(n, b, len);
1815252884aeSStefan Eßer
181644d4804dSStefan Eßer // This is true if n is greater than b, which means that division can
181744d4804dSStefan Eßer // proceed, so this inner loop is the part that implements one instance
181844d4804dSStefan Eßer // of the division.
181978bc019dSStefan Eßer while (cmp >= 0)
182078bc019dSStefan Eßer {
182144d4804dSStefan Eßer BcBigDig n1, dividend, quotient;
1822252884aeSStefan Eßer
182344d4804dSStefan Eßer // These should be named obviously enough. Just imagine that it's a
182444d4804dSStefan Eßer // division of one limb. Because that's what it is.
1825252884aeSStefan Eßer n1 = (BcBigDig) n[len];
1826252884aeSStefan Eßer dividend = n1 * BC_BASE_POW + (BcBigDig) n[len - 1];
182744d4804dSStefan Eßer quotient = (dividend / divisor);
1828252884aeSStefan Eßer
182944d4804dSStefan Eßer // If this is true, then we can just subtract. Remember: setting
183044d4804dSStefan Eßer // quotient to 1 is not bad because we already know that n is
183144d4804dSStefan Eßer // greater than b.
183278bc019dSStefan Eßer if (quotient <= 1)
183378bc019dSStefan Eßer {
183444d4804dSStefan Eßer quotient = 1;
1835252884aeSStefan Eßer bc_num_subArrays(n, b->num, len);
1836252884aeSStefan Eßer }
183778bc019dSStefan Eßer else
183878bc019dSStefan Eßer {
183944d4804dSStefan Eßer assert(quotient <= BC_BASE_POW);
1840252884aeSStefan Eßer
184144d4804dSStefan Eßer // We need to multiply and subtract for a quotient above 1.
184244d4804dSStefan Eßer bc_num_mulArray(b, (BcBigDig) quotient, &cpb);
1843252884aeSStefan Eßer bc_num_subArrays(n, cpb.num, cpb.len);
1844252884aeSStefan Eßer }
1845252884aeSStefan Eßer
184644d4804dSStefan Eßer // The result is the *real* quotient, by the way, but it might take
184744d4804dSStefan Eßer // multiple trips around this loop to get it.
184844d4804dSStefan Eßer result += quotient;
1849252884aeSStefan Eßer assert(result <= BC_BASE_POW);
1850252884aeSStefan Eßer
185144d4804dSStefan Eßer // And here's why it might take multiple trips: n might *still* be
185244d4804dSStefan Eßer // greater than b. So we have to loop again. That's what this is
185344d4804dSStefan Eßer // setting up for: the condition of the while loop.
1854d101cdd6SStefan Eßer if (realnonzero) cmp = bc_num_divCmp(n, b, len);
1855252884aeSStefan Eßer else cmp = -1;
1856252884aeSStefan Eßer }
1857252884aeSStefan Eßer
1858252884aeSStefan Eßer assert(result < BC_BASE_POW);
1859252884aeSStefan Eßer
186044d4804dSStefan Eßer // Store the actual limb quotient.
1861252884aeSStefan Eßer c->num[i] = (BcDig) result;
1862252884aeSStefan Eßer }
1863252884aeSStefan Eßer
1864252884aeSStefan Eßer err:
1865252884aeSStefan Eßer BC_SIG_MAYLOCK;
1866252884aeSStefan Eßer bc_num_free(&cpb);
1867d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
1868252884aeSStefan Eßer }
1869252884aeSStefan Eßer
187044d4804dSStefan Eßer /**
187144d4804dSStefan Eßer * Implements division. This is a BcNumBinOp function.
187244d4804dSStefan Eßer * @param a The first operand.
187344d4804dSStefan Eßer * @param b The second operand.
187444d4804dSStefan Eßer * @param c The return parameter.
187544d4804dSStefan Eßer * @param scale The current scale.
187644d4804dSStefan Eßer */
187778bc019dSStefan Eßer static void
bc_num_d(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)187878bc019dSStefan Eßer bc_num_d(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
187978bc019dSStefan Eßer {
188050696a6eSStefan Eßer size_t len, cpardx;
1881252884aeSStefan Eßer BcNum cpa, cpb;
1882d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
1883d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
1884d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
1885252884aeSStefan Eßer
188644d4804dSStefan Eßer if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO);
188744d4804dSStefan Eßer
188878bc019dSStefan Eßer if (BC_NUM_ZERO(a))
188978bc019dSStefan Eßer {
1890252884aeSStefan Eßer bc_num_setToZero(c, scale);
1891252884aeSStefan Eßer return;
1892252884aeSStefan Eßer }
189344d4804dSStefan Eßer
189478bc019dSStefan Eßer if (BC_NUM_ONE(b))
189578bc019dSStefan Eßer {
1896252884aeSStefan Eßer bc_num_copy(c, a);
189750696a6eSStefan Eßer bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b));
1898252884aeSStefan Eßer return;
1899252884aeSStefan Eßer }
190044d4804dSStefan Eßer
190144d4804dSStefan Eßer // If this is true, we can use bc_num_divArray(), which would be faster.
190278bc019dSStefan Eßer if (!BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b) && b->len == 1 && !scale)
190378bc019dSStefan Eßer {
1904252884aeSStefan Eßer BcBigDig rem;
1905252884aeSStefan Eßer bc_num_divArray(a, (BcBigDig) b->num[0], c, &rem);
190650696a6eSStefan Eßer bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b));
1907252884aeSStefan Eßer return;
1908252884aeSStefan Eßer }
1909252884aeSStefan Eßer
191050696a6eSStefan Eßer len = bc_num_divReq(a, b, scale);
1911252884aeSStefan Eßer
1912252884aeSStefan Eßer BC_SIG_LOCK;
1913252884aeSStefan Eßer
191444d4804dSStefan Eßer // Initialize copies of the parameters. We want the length of the first
191544d4804dSStefan Eßer // operand copy to be as big as the result because of the way the division
191644d4804dSStefan Eßer // is implemented.
1917252884aeSStefan Eßer bc_num_init(&cpa, len);
1918252884aeSStefan Eßer bc_num_copy(&cpa, a);
1919252884aeSStefan Eßer bc_num_createCopy(&cpb, b);
1920252884aeSStefan Eßer
1921d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
1922252884aeSStefan Eßer
1923252884aeSStefan Eßer BC_SIG_UNLOCK;
1924252884aeSStefan Eßer
1925252884aeSStefan Eßer len = b->len;
1926252884aeSStefan Eßer
192744d4804dSStefan Eßer // Like the above comment, we want the copy of the first parameter to be
192844d4804dSStefan Eßer // larger than the second parameter.
192978bc019dSStefan Eßer if (len > cpa.len)
193078bc019dSStefan Eßer {
1931252884aeSStefan Eßer bc_num_expand(&cpa, bc_vm_growSize(len, 2));
1932252884aeSStefan Eßer bc_num_extend(&cpa, (len - cpa.len) * BC_BASE_DIGS);
1933252884aeSStefan Eßer }
1934252884aeSStefan Eßer
193550696a6eSStefan Eßer cpardx = BC_NUM_RDX_VAL_NP(cpa);
193650696a6eSStefan Eßer cpa.scale = cpardx * BC_BASE_DIGS;
1937252884aeSStefan Eßer
193844d4804dSStefan Eßer // This is just setting up the scale in preparation for the division.
1939252884aeSStefan Eßer bc_num_extend(&cpa, b->scale);
194050696a6eSStefan Eßer cpardx = BC_NUM_RDX_VAL_NP(cpa) - BC_NUM_RDX(b->scale);
194150696a6eSStefan Eßer BC_NUM_RDX_SET_NP(cpa, cpardx);
194250696a6eSStefan Eßer cpa.scale = cpardx * BC_BASE_DIGS;
1943252884aeSStefan Eßer
194444d4804dSStefan Eßer // Once again, just setting things up, this time to match scale.
194578bc019dSStefan Eßer if (scale > cpa.scale)
194678bc019dSStefan Eßer {
1947252884aeSStefan Eßer bc_num_extend(&cpa, scale);
194850696a6eSStefan Eßer cpardx = BC_NUM_RDX_VAL_NP(cpa);
194950696a6eSStefan Eßer cpa.scale = cpardx * BC_BASE_DIGS;
1950252884aeSStefan Eßer }
1951252884aeSStefan Eßer
195244d4804dSStefan Eßer // Grow if necessary.
1953252884aeSStefan Eßer if (cpa.cap == cpa.len) bc_num_expand(&cpa, bc_vm_growSize(cpa.len, 1));
1954252884aeSStefan Eßer
1955252884aeSStefan Eßer // We want an extra zero in front to make things simpler.
1956252884aeSStefan Eßer cpa.num[cpa.len++] = 0;
1957252884aeSStefan Eßer
195844d4804dSStefan Eßer // Still setting things up. Why all of these things are needed is not
195944d4804dSStefan Eßer // something that can be easily explained, but it has to do with making the
196044d4804dSStefan Eßer // actual algorithm easier to understand because it can assume a lot of
196144d4804dSStefan Eßer // things. Thus, you should view all of this setup code as establishing
196244d4804dSStefan Eßer // assumptions for bc_num_d_long(), where the actual division happens.
1963a970610aSStefan Eßer //
1964a970610aSStefan Eßer // But in short, this setup makes it so bc_num_d_long() can pretend the
1965a970610aSStefan Eßer // numbers are integers.
196644d4804dSStefan Eßer if (cpardx == cpa.len) cpa.len = bc_num_nonZeroLen(&cpa);
196744d4804dSStefan Eßer if (BC_NUM_RDX_VAL_NP(cpb) == cpb.len) cpb.len = bc_num_nonZeroLen(&cpb);
196850696a6eSStefan Eßer cpb.scale = 0;
196950696a6eSStefan Eßer BC_NUM_RDX_SET_NP(cpb, 0);
1970252884aeSStefan Eßer
1971252884aeSStefan Eßer bc_num_d_long(&cpa, &cpb, c, scale);
1972252884aeSStefan Eßer
197350696a6eSStefan Eßer bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b));
1974252884aeSStefan Eßer
1975252884aeSStefan Eßer err:
1976252884aeSStefan Eßer BC_SIG_MAYLOCK;
1977252884aeSStefan Eßer bc_num_free(&cpb);
1978252884aeSStefan Eßer bc_num_free(&cpa);
1979d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
1980252884aeSStefan Eßer }
1981252884aeSStefan Eßer
198244d4804dSStefan Eßer /**
198344d4804dSStefan Eßer * Implements divmod. This is the actual modulus function; since modulus
198444d4804dSStefan Eßer * requires a division anyway, this returns the quotient and modulus. Either can
198544d4804dSStefan Eßer * be thrown out as desired.
198644d4804dSStefan Eßer * @param a The first operand.
198744d4804dSStefan Eßer * @param b The second operand.
198844d4804dSStefan Eßer * @param c The return parameter for the quotient.
198944d4804dSStefan Eßer * @param d The return parameter for the modulus.
199044d4804dSStefan Eßer * @param scale The current scale.
199144d4804dSStefan Eßer * @param ts The scale that the operation should be done to. Yes, it's not
199244d4804dSStefan Eßer * necessarily the same as scale, per the bc spec.
199344d4804dSStefan Eßer */
199478bc019dSStefan Eßer static void
bc_num_r(BcNum * a,BcNum * b,BcNum * restrict c,BcNum * restrict d,size_t scale,size_t ts)199578bc019dSStefan Eßer bc_num_r(BcNum* a, BcNum* b, BcNum* restrict c, BcNum* restrict d, size_t scale,
199678bc019dSStefan Eßer size_t ts)
1997252884aeSStefan Eßer {
1998252884aeSStefan Eßer BcNum temp;
1999d101cdd6SStefan Eßer // realscale is meant to quiet a warning on GCC about longjmp() clobbering.
2000d101cdd6SStefan Eßer // This one is real.
2001d101cdd6SStefan Eßer size_t realscale;
2002252884aeSStefan Eßer bool neg;
2003d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2004d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
2005d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2006252884aeSStefan Eßer
200744d4804dSStefan Eßer if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO);
200844d4804dSStefan Eßer
200978bc019dSStefan Eßer if (BC_NUM_ZERO(a))
201078bc019dSStefan Eßer {
2011252884aeSStefan Eßer bc_num_setToZero(c, ts);
2012252884aeSStefan Eßer bc_num_setToZero(d, ts);
2013252884aeSStefan Eßer return;
2014252884aeSStefan Eßer }
2015252884aeSStefan Eßer
2016252884aeSStefan Eßer BC_SIG_LOCK;
2017252884aeSStefan Eßer
2018252884aeSStefan Eßer bc_num_init(&temp, d->cap);
2019252884aeSStefan Eßer
2020d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
2021252884aeSStefan Eßer
2022252884aeSStefan Eßer BC_SIG_UNLOCK;
2023252884aeSStefan Eßer
202444d4804dSStefan Eßer // Division.
2025252884aeSStefan Eßer bc_num_d(a, b, c, scale);
2026252884aeSStefan Eßer
202744d4804dSStefan Eßer // We want an extra digit so we can safely truncate.
2028d101cdd6SStefan Eßer if (scale) realscale = ts + 1;
2029d101cdd6SStefan Eßer else realscale = scale;
2030252884aeSStefan Eßer
203150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(c));
203250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
203350696a6eSStefan Eßer
203444d4804dSStefan Eßer // Implement the rest of the (a - (a / b) * b) formula.
2035d101cdd6SStefan Eßer bc_num_m(c, b, &temp, realscale);
2036d101cdd6SStefan Eßer bc_num_sub(a, &temp, d, realscale);
2037252884aeSStefan Eßer
203844d4804dSStefan Eßer // Extend if necessary.
2039252884aeSStefan Eßer if (ts > d->scale && BC_NUM_NONZERO(d)) bc_num_extend(d, ts - d->scale);
2040252884aeSStefan Eßer
204150696a6eSStefan Eßer neg = BC_NUM_NEG(d);
204250696a6eSStefan Eßer bc_num_retireMul(d, ts, BC_NUM_NEG(a), BC_NUM_NEG(b));
204350696a6eSStefan Eßer d->rdx = BC_NUM_NEG_VAL(d, BC_NUM_NONZERO(d) ? neg : false);
2044252884aeSStefan Eßer
2045252884aeSStefan Eßer err:
2046252884aeSStefan Eßer BC_SIG_MAYLOCK;
2047252884aeSStefan Eßer bc_num_free(&temp);
2048d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
2049252884aeSStefan Eßer }
2050252884aeSStefan Eßer
205144d4804dSStefan Eßer /**
205244d4804dSStefan Eßer * Implements modulus/remainder. (Yes, I know they are different, but not in the
205344d4804dSStefan Eßer * context of bc.) This is a BcNumBinOp function.
205444d4804dSStefan Eßer * @param a The first operand.
205544d4804dSStefan Eßer * @param b The second operand.
205644d4804dSStefan Eßer * @param c The return parameter.
205744d4804dSStefan Eßer * @param scale The current scale.
205844d4804dSStefan Eßer */
205978bc019dSStefan Eßer static void
bc_num_rem(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)206078bc019dSStefan Eßer bc_num_rem(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
206178bc019dSStefan Eßer {
2062252884aeSStefan Eßer BcNum c1;
2063252884aeSStefan Eßer size_t ts;
2064d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2065d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
2066d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2067252884aeSStefan Eßer
2068252884aeSStefan Eßer ts = bc_vm_growSize(scale, b->scale);
2069252884aeSStefan Eßer ts = BC_MAX(ts, a->scale);
2070252884aeSStefan Eßer
2071252884aeSStefan Eßer BC_SIG_LOCK;
2072252884aeSStefan Eßer
207344d4804dSStefan Eßer // Need a temp for the quotient.
2074252884aeSStefan Eßer bc_num_init(&c1, bc_num_mulReq(a, b, ts));
2075252884aeSStefan Eßer
2076d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
2077252884aeSStefan Eßer
2078252884aeSStefan Eßer BC_SIG_UNLOCK;
2079252884aeSStefan Eßer
2080252884aeSStefan Eßer bc_num_r(a, b, &c1, c, scale, ts);
2081252884aeSStefan Eßer
2082252884aeSStefan Eßer err:
2083252884aeSStefan Eßer BC_SIG_MAYLOCK;
2084252884aeSStefan Eßer bc_num_free(&c1);
2085d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
2086252884aeSStefan Eßer }
2087252884aeSStefan Eßer
208844d4804dSStefan Eßer /**
208944d4804dSStefan Eßer * Implements power (exponentiation). This is a BcNumBinOp function.
209044d4804dSStefan Eßer * @param a The first operand.
209144d4804dSStefan Eßer * @param b The second operand.
209244d4804dSStefan Eßer * @param c The return parameter.
209344d4804dSStefan Eßer * @param scale The current scale.
209444d4804dSStefan Eßer */
209578bc019dSStefan Eßer static void
bc_num_p(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)209678bc019dSStefan Eßer bc_num_p(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
209778bc019dSStefan Eßer {
209844d4804dSStefan Eßer BcNum copy, btemp;
209944d4804dSStefan Eßer BcBigDig exp;
2100d101cdd6SStefan Eßer // realscale is meant to quiet a warning on GCC about longjmp() clobbering.
2101d101cdd6SStefan Eßer // This one is real.
2102d101cdd6SStefan Eßer size_t powrdx, resrdx, realscale;
210344d4804dSStefan Eßer bool neg;
2104d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2105d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
2106d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2107d101cdd6SStefan Eßer
2108d101cdd6SStefan Eßer // This is here to silence a warning from GCC.
2109d101cdd6SStefan Eßer #if BC_GCC
2110d101cdd6SStefan Eßer btemp.len = 0;
2111d101cdd6SStefan Eßer btemp.rdx = 0;
2112d101cdd6SStefan Eßer btemp.num = NULL;
2113d101cdd6SStefan Eßer #endif // BC_GCC
2114252884aeSStefan Eßer
211544d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(b, &btemp))) bc_err(BC_ERR_MATH_NON_INTEGER);
2116252884aeSStefan Eßer
2117d101cdd6SStefan Eßer assert(btemp.len == 0 || btemp.num != NULL);
2118d101cdd6SStefan Eßer
211978bc019dSStefan Eßer if (BC_NUM_ZERO(&btemp))
212078bc019dSStefan Eßer {
2121252884aeSStefan Eßer bc_num_one(c);
2122252884aeSStefan Eßer return;
2123252884aeSStefan Eßer }
212444d4804dSStefan Eßer
212578bc019dSStefan Eßer if (BC_NUM_ZERO(a))
212678bc019dSStefan Eßer {
212744d4804dSStefan Eßer if (BC_NUM_NEG_NP(btemp)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO);
2128252884aeSStefan Eßer bc_num_setToZero(c, scale);
2129252884aeSStefan Eßer return;
2130252884aeSStefan Eßer }
213144d4804dSStefan Eßer
213278bc019dSStefan Eßer if (BC_NUM_ONE(&btemp))
213378bc019dSStefan Eßer {
213444d4804dSStefan Eßer if (!BC_NUM_NEG_NP(btemp)) bc_num_copy(c, a);
2135252884aeSStefan Eßer else bc_num_inv(a, c, scale);
2136252884aeSStefan Eßer return;
2137252884aeSStefan Eßer }
2138252884aeSStefan Eßer
213944d4804dSStefan Eßer neg = BC_NUM_NEG_NP(btemp);
214044d4804dSStefan Eßer BC_NUM_NEG_CLR_NP(btemp);
2141252884aeSStefan Eßer
214244d4804dSStefan Eßer exp = bc_num_bigdig(&btemp);
214344d4804dSStefan Eßer
214444d4804dSStefan Eßer BC_SIG_LOCK;
2145252884aeSStefan Eßer
2146252884aeSStefan Eßer bc_num_createCopy(©, a);
2147252884aeSStefan Eßer
2148d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
2149252884aeSStefan Eßer
2150252884aeSStefan Eßer BC_SIG_UNLOCK;
2151252884aeSStefan Eßer
215244d4804dSStefan Eßer // If this is true, then we do not have to do a division, and we need to
215344d4804dSStefan Eßer // set scale accordingly.
215478bc019dSStefan Eßer if (!neg)
215578bc019dSStefan Eßer {
215644d4804dSStefan Eßer size_t max = BC_MAX(scale, a->scale), scalepow;
215744d4804dSStefan Eßer scalepow = bc_num_mulOverflow(a->scale, exp);
2158d101cdd6SStefan Eßer realscale = BC_MIN(scalepow, max);
2159252884aeSStefan Eßer }
2160d101cdd6SStefan Eßer else realscale = scale;
2161252884aeSStefan Eßer
216244d4804dSStefan Eßer // This is only implementing the first exponentiation by squaring, until it
216344d4804dSStefan Eßer // reaches the first time where the square is actually used.
216478bc019dSStefan Eßer for (powrdx = a->scale; !(exp & 1); exp >>= 1)
216578bc019dSStefan Eßer {
2166252884aeSStefan Eßer powrdx <<= 1;
216750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(copy));
2168252884aeSStefan Eßer bc_num_mul(©, ©, ©, powrdx);
2169252884aeSStefan Eßer }
2170252884aeSStefan Eßer
217144d4804dSStefan Eßer // Make c a copy of copy for the purpose of saving the squares that should
217244d4804dSStefan Eßer // be saved.
2173252884aeSStefan Eßer bc_num_copy(c, ©);
2174252884aeSStefan Eßer resrdx = powrdx;
2175252884aeSStefan Eßer
217644d4804dSStefan Eßer // Now finish the exponentiation by squaring, this time saving the squares
217744d4804dSStefan Eßer // as necessary.
217878bc019dSStefan Eßer while (exp >>= 1)
217978bc019dSStefan Eßer {
2180252884aeSStefan Eßer powrdx <<= 1;
218150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(copy));
2182252884aeSStefan Eßer bc_num_mul(©, ©, ©, powrdx);
2183252884aeSStefan Eßer
218444d4804dSStefan Eßer // If this is true, we want to save that particular square. This does
218544d4804dSStefan Eßer // that by multiplying c with copy.
218678bc019dSStefan Eßer if (exp & 1)
218778bc019dSStefan Eßer {
2188252884aeSStefan Eßer resrdx += powrdx;
218950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(c));
219050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(copy));
2191252884aeSStefan Eßer bc_num_mul(c, ©, c, resrdx);
2192252884aeSStefan Eßer }
2193252884aeSStefan Eßer }
2194252884aeSStefan Eßer
219544d4804dSStefan Eßer // Invert if necessary.
2196d101cdd6SStefan Eßer if (neg) bc_num_inv(c, c, realscale);
2197252884aeSStefan Eßer
219844d4804dSStefan Eßer // Truncate if necessary.
2199d101cdd6SStefan Eßer if (c->scale > realscale) bc_num_truncate(c, c->scale - realscale);
2200252884aeSStefan Eßer
220144d4804dSStefan Eßer bc_num_clean(c);
2202252884aeSStefan Eßer
2203252884aeSStefan Eßer err:
2204252884aeSStefan Eßer BC_SIG_MAYLOCK;
2205252884aeSStefan Eßer bc_num_free(©);
2206d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
2207252884aeSStefan Eßer }
2208252884aeSStefan Eßer
2209252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
221044d4804dSStefan Eßer /**
221144d4804dSStefan Eßer * Implements the places operator. This is a BcNumBinOp function.
221244d4804dSStefan Eßer * @param a The first operand.
221344d4804dSStefan Eßer * @param b The second operand.
221444d4804dSStefan Eßer * @param c The return parameter.
221544d4804dSStefan Eßer * @param scale The current scale.
221644d4804dSStefan Eßer */
221778bc019dSStefan Eßer static void
bc_num_place(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)221878bc019dSStefan Eßer bc_num_place(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
221978bc019dSStefan Eßer {
222044d4804dSStefan Eßer BcBigDig val;
2221252884aeSStefan Eßer
2222252884aeSStefan Eßer BC_UNUSED(scale);
2223252884aeSStefan Eßer
222444d4804dSStefan Eßer val = bc_num_intop(a, b, c);
2225252884aeSStefan Eßer
222644d4804dSStefan Eßer // Just truncate or extend as appropriate.
2227252884aeSStefan Eßer if (val < c->scale) bc_num_truncate(c, c->scale - val);
2228252884aeSStefan Eßer else if (val > c->scale) bc_num_extend(c, val - c->scale);
2229252884aeSStefan Eßer }
2230252884aeSStefan Eßer
223144d4804dSStefan Eßer /**
223244d4804dSStefan Eßer * Implements the left shift operator. This is a BcNumBinOp function.
223344d4804dSStefan Eßer */
223478bc019dSStefan Eßer static void
bc_num_left(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)223578bc019dSStefan Eßer bc_num_left(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
223678bc019dSStefan Eßer {
223744d4804dSStefan Eßer BcBigDig val;
2238252884aeSStefan Eßer
2239252884aeSStefan Eßer BC_UNUSED(scale);
2240252884aeSStefan Eßer
224144d4804dSStefan Eßer val = bc_num_intop(a, b, c);
2242252884aeSStefan Eßer
2243252884aeSStefan Eßer bc_num_shiftLeft(c, (size_t) val);
2244252884aeSStefan Eßer }
2245252884aeSStefan Eßer
224644d4804dSStefan Eßer /**
224744d4804dSStefan Eßer * Implements the right shift operator. This is a BcNumBinOp function.
224844d4804dSStefan Eßer */
224978bc019dSStefan Eßer static void
bc_num_right(BcNum * a,BcNum * b,BcNum * restrict c,size_t scale)225078bc019dSStefan Eßer bc_num_right(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale)
225178bc019dSStefan Eßer {
225244d4804dSStefan Eßer BcBigDig val;
2253252884aeSStefan Eßer
2254252884aeSStefan Eßer BC_UNUSED(scale);
2255252884aeSStefan Eßer
225644d4804dSStefan Eßer val = bc_num_intop(a, b, c);
2257252884aeSStefan Eßer
2258252884aeSStefan Eßer if (BC_NUM_ZERO(c)) return;
2259252884aeSStefan Eßer
2260252884aeSStefan Eßer bc_num_shiftRight(c, (size_t) val);
2261252884aeSStefan Eßer }
2262252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
2263252884aeSStefan Eßer
226444d4804dSStefan Eßer /**
226544d4804dSStefan Eßer * Prepares for, and calls, a binary operator function. This is probably the
226644d4804dSStefan Eßer * most important function in the entire file because it establishes assumptions
226744d4804dSStefan Eßer * that make the rest of the code so easy. Those assumptions include:
226844d4804dSStefan Eßer *
226944d4804dSStefan Eßer * - a is not the same pointer as c.
227044d4804dSStefan Eßer * - b is not the same pointer as c.
227144d4804dSStefan Eßer * - there is enough room in c for the result.
227244d4804dSStefan Eßer *
227344d4804dSStefan Eßer * Without these, this whole function would basically have to be duplicated for
227444d4804dSStefan Eßer * *all* binary operators.
227544d4804dSStefan Eßer *
227644d4804dSStefan Eßer * @param a The first operand.
227744d4804dSStefan Eßer * @param b The second operand.
227844d4804dSStefan Eßer * @param c The return parameter.
227944d4804dSStefan Eßer * @param scale The current scale.
228044d4804dSStefan Eßer * @param req The number of limbs needed to fit the result.
228144d4804dSStefan Eßer */
228278bc019dSStefan Eßer static void
bc_num_binary(BcNum * a,BcNum * b,BcNum * c,size_t scale,BcNumBinOp op,size_t req)228378bc019dSStefan Eßer bc_num_binary(BcNum* a, BcNum* b, BcNum* c, size_t scale, BcNumBinOp op,
228478bc019dSStefan Eßer size_t req)
2285252884aeSStefan Eßer {
228678bc019dSStefan Eßer BcNum* ptr_a;
228778bc019dSStefan Eßer BcNum* ptr_b;
228878bc019dSStefan Eßer BcNum num2;
2289d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2290d101cdd6SStefan Eßer BcVm* vm = NULL;
2291d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2292252884aeSStefan Eßer
2293252884aeSStefan Eßer assert(a != NULL && b != NULL && c != NULL && op != NULL);
2294252884aeSStefan Eßer
229550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
229650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
229750696a6eSStefan Eßer
2298252884aeSStefan Eßer BC_SIG_LOCK;
2299252884aeSStefan Eßer
2300d101cdd6SStefan Eßer ptr_a = c == a ? &num2 : a;
2301d101cdd6SStefan Eßer ptr_b = c == b ? &num2 : b;
2302252884aeSStefan Eßer
230344d4804dSStefan Eßer // Actually reallocate. If we don't reallocate, we want to expand at the
230444d4804dSStefan Eßer // very least.
2305d101cdd6SStefan Eßer if (c == a || c == b)
230678bc019dSStefan Eßer {
2307d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2308d101cdd6SStefan Eßer vm = bcl_getspecific();
2309d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2310d101cdd6SStefan Eßer
2311d101cdd6SStefan Eßer // NOLINTNEXTLINE
2312d101cdd6SStefan Eßer memcpy(&num2, c, sizeof(BcNum));
2313d101cdd6SStefan Eßer
2314252884aeSStefan Eßer bc_num_init(c, req);
2315252884aeSStefan Eßer
231644d4804dSStefan Eßer // Must prepare for cleanup. We want this here so that locals that got
231744d4804dSStefan Eßer // set stay set since a longjmp() is not guaranteed to preserve locals.
2318d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
2319252884aeSStefan Eßer BC_SIG_UNLOCK;
2320252884aeSStefan Eßer }
232178bc019dSStefan Eßer else
232278bc019dSStefan Eßer {
2323252884aeSStefan Eßer BC_SIG_UNLOCK;
2324252884aeSStefan Eßer bc_num_expand(c, req);
2325252884aeSStefan Eßer }
2326252884aeSStefan Eßer
232744d4804dSStefan Eßer // It is okay for a and b to be the same. If a binary operator function does
232844d4804dSStefan Eßer // need them to be different, the binary operator function is responsible
232944d4804dSStefan Eßer // for that.
233044d4804dSStefan Eßer
233144d4804dSStefan Eßer // Call the actual binary operator function.
2332252884aeSStefan Eßer op(ptr_a, ptr_b, c, scale);
2333252884aeSStefan Eßer
233450696a6eSStefan Eßer assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c));
233550696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len);
233650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(c));
233750696a6eSStefan Eßer assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len);
2338252884aeSStefan Eßer
2339252884aeSStefan Eßer err:
234044d4804dSStefan Eßer // Cleanup only needed if we initialized c to a new number.
2341d101cdd6SStefan Eßer if (c == a || c == b)
234278bc019dSStefan Eßer {
2343252884aeSStefan Eßer BC_SIG_MAYLOCK;
2344252884aeSStefan Eßer bc_num_free(&num2);
2345d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
2346252884aeSStefan Eßer }
2347252884aeSStefan Eßer }
2348252884aeSStefan Eßer
234944d4804dSStefan Eßer /**
235044d4804dSStefan Eßer * Tests a number string for validity. This function has a history; I originally
235144d4804dSStefan Eßer * wrote it because I did not trust my parser. Over time, however, I came to
235244d4804dSStefan Eßer * trust it, so I was able to relegate this function to debug builds only, and I
235344d4804dSStefan Eßer * used it in assert()'s. But then I created the library, and well, I can't
235444d4804dSStefan Eßer * trust users, so I reused this for yelling at users.
235544d4804dSStefan Eßer * @param val The string to check to see if it's a valid number string.
235644d4804dSStefan Eßer * @return True if the string is a valid number string, false otherwise.
235744d4804dSStefan Eßer */
235878bc019dSStefan Eßer bool
bc_num_strValid(const char * restrict val)235978bc019dSStefan Eßer bc_num_strValid(const char* restrict val)
236078bc019dSStefan Eßer {
2361252884aeSStefan Eßer bool radix = false;
2362252884aeSStefan Eßer size_t i, len = strlen(val);
2363252884aeSStefan Eßer
236444d4804dSStefan Eßer // Notice that I don't check if there is a negative sign. That is not part
236544d4804dSStefan Eßer // of a valid number, except in the library. The library-specific code takes
236644d4804dSStefan Eßer // care of that part.
236744d4804dSStefan Eßer
236844d4804dSStefan Eßer // Nothing in the string is okay.
2369252884aeSStefan Eßer if (!len) return true;
2370252884aeSStefan Eßer
237144d4804dSStefan Eßer // Loop through the characters.
237278bc019dSStefan Eßer for (i = 0; i < len; ++i)
237378bc019dSStefan Eßer {
2374252884aeSStefan Eßer BcDig c = val[i];
2375252884aeSStefan Eßer
237644d4804dSStefan Eßer // If we have found a radix point...
237778bc019dSStefan Eßer if (c == '.')
237878bc019dSStefan Eßer {
237944d4804dSStefan Eßer // We don't allow two radices.
2380252884aeSStefan Eßer if (radix) return false;
2381252884aeSStefan Eßer
2382252884aeSStefan Eßer radix = true;
2383252884aeSStefan Eßer continue;
2384252884aeSStefan Eßer }
2385252884aeSStefan Eßer
238644d4804dSStefan Eßer // We only allow digits and uppercase letters.
2387252884aeSStefan Eßer if (!(isdigit(c) || isupper(c))) return false;
2388252884aeSStefan Eßer }
2389252884aeSStefan Eßer
2390252884aeSStefan Eßer return true;
2391252884aeSStefan Eßer }
2392252884aeSStefan Eßer
239344d4804dSStefan Eßer /**
239444d4804dSStefan Eßer * Parses one character and returns the digit that corresponds to that
239544d4804dSStefan Eßer * character according to the base.
239644d4804dSStefan Eßer * @param c The character to parse.
239744d4804dSStefan Eßer * @param base The base.
239844d4804dSStefan Eßer * @return The character as a digit.
239944d4804dSStefan Eßer */
240078bc019dSStefan Eßer static BcBigDig
bc_num_parseChar(char c,size_t base)240178bc019dSStefan Eßer bc_num_parseChar(char c, size_t base)
240278bc019dSStefan Eßer {
240344d4804dSStefan Eßer assert(isupper(c) || isdigit(c));
240444d4804dSStefan Eßer
240544d4804dSStefan Eßer // If a letter...
240678bc019dSStefan Eßer if (isupper(c))
240778bc019dSStefan Eßer {
2408d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2409d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
2410d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2411d101cdd6SStefan Eßer
241244d4804dSStefan Eßer // This returns the digit that directly corresponds with the letter.
2413252884aeSStefan Eßer c = BC_NUM_NUM_LETTER(c);
241444d4804dSStefan Eßer
241544d4804dSStefan Eßer // If the digit is greater than the base, we clamp.
2416d101cdd6SStefan Eßer if (BC_DIGIT_CLAMP)
2417d101cdd6SStefan Eßer {
241844d4804dSStefan Eßer c = ((size_t) c) >= base ? (char) base - 1 : c;
2419252884aeSStefan Eßer }
2420d101cdd6SStefan Eßer }
242144d4804dSStefan Eßer // Straight convert the digit to a number.
2422252884aeSStefan Eßer else c -= '0';
2423252884aeSStefan Eßer
2424252884aeSStefan Eßer return (BcBigDig) (uchar) c;
2425252884aeSStefan Eßer }
2426252884aeSStefan Eßer
242744d4804dSStefan Eßer /**
242844d4804dSStefan Eßer * Parses a string as a decimal number. This is separate because it's going to
242944d4804dSStefan Eßer * be the most used, and it can be heavily optimized for decimal only.
243044d4804dSStefan Eßer * @param n The number to parse into and return. Must be preallocated.
243144d4804dSStefan Eßer * @param val The string to parse.
243244d4804dSStefan Eßer */
243378bc019dSStefan Eßer static void
bc_num_parseDecimal(BcNum * restrict n,const char * restrict val)243478bc019dSStefan Eßer bc_num_parseDecimal(BcNum* restrict n, const char* restrict val)
243578bc019dSStefan Eßer {
2436252884aeSStefan Eßer size_t len, i, temp, mod;
2437252884aeSStefan Eßer const char* ptr;
2438252884aeSStefan Eßer bool zero = true, rdx;
2439d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2440d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
2441d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2442252884aeSStefan Eßer
244344d4804dSStefan Eßer // Eat leading zeroes.
244478bc019dSStefan Eßer for (i = 0; val[i] == '0'; ++i)
244578bc019dSStefan Eßer {
244678bc019dSStefan Eßer continue;
244778bc019dSStefan Eßer }
2448252884aeSStefan Eßer
2449252884aeSStefan Eßer val += i;
2450252884aeSStefan Eßer assert(!val[0] || isalnum(val[0]) || val[0] == '.');
2451252884aeSStefan Eßer
245244d4804dSStefan Eßer // All 0's. We can just return, since this procedure expects a virgin
245344d4804dSStefan Eßer // (already 0) BcNum.
2454252884aeSStefan Eßer if (!val[0]) return;
2455252884aeSStefan Eßer
245644d4804dSStefan Eßer // The length of the string is the length of the number, except it might be
245744d4804dSStefan Eßer // one bigger because of a decimal point.
2458252884aeSStefan Eßer len = strlen(val);
2459252884aeSStefan Eßer
246044d4804dSStefan Eßer // Find the location of the decimal point.
2461252884aeSStefan Eßer ptr = strchr(val, '.');
2462252884aeSStefan Eßer rdx = (ptr != NULL);
2463252884aeSStefan Eßer
246444d4804dSStefan Eßer // We eat leading zeroes again. These leading zeroes are different because
246544d4804dSStefan Eßer // they will come after the decimal point if they exist, and since that's
246644d4804dSStefan Eßer // the case, they must be preserved.
246778bc019dSStefan Eßer for (i = 0; i < len && (zero = (val[i] == '0' || val[i] == '.')); ++i)
246878bc019dSStefan Eßer {
246978bc019dSStefan Eßer continue;
247078bc019dSStefan Eßer }
2471252884aeSStefan Eßer
247244d4804dSStefan Eßer // Set the scale of the number based on the location of the decimal point.
247344d4804dSStefan Eßer // The casts to uintptr_t is to ensure that bc does not hit undefined
247444d4804dSStefan Eßer // behavior when doing math on the values.
247578bc019dSStefan Eßer n->scale = (size_t) (rdx *
247678bc019dSStefan Eßer (((uintptr_t) (val + len)) - (((uintptr_t) ptr) + 1)));
2477252884aeSStefan Eßer
247844d4804dSStefan Eßer // Set rdx.
247950696a6eSStefan Eßer BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale));
248044d4804dSStefan Eßer
248144d4804dSStefan Eßer // Calculate length. First, the length of the integer, then the number of
248244d4804dSStefan Eßer // digits in the last limb, then the length.
2483252884aeSStefan Eßer i = len - (ptr == val ? 0 : i) - rdx;
2484252884aeSStefan Eßer temp = BC_NUM_ROUND_POW(i);
2485252884aeSStefan Eßer mod = n->scale % BC_BASE_DIGS;
2486252884aeSStefan Eßer i = mod ? BC_BASE_DIGS - mod : 0;
2487252884aeSStefan Eßer n->len = ((temp + i) / BC_BASE_DIGS);
2488252884aeSStefan Eßer
2489d101cdd6SStefan Eßer // Expand and zero. The plus extra is in case the lack of clamping causes
2490d101cdd6SStefan Eßer // the number to overflow the original bounds.
2491d101cdd6SStefan Eßer bc_num_expand(n, n->len + !BC_DIGIT_CLAMP);
249278bc019dSStefan Eßer // NOLINTNEXTLINE
2493d101cdd6SStefan Eßer memset(n->num, 0, BC_NUM_SIZE(n->len + !BC_DIGIT_CLAMP));
2494252884aeSStefan Eßer
249578bc019dSStefan Eßer if (zero)
249678bc019dSStefan Eßer {
249750696a6eSStefan Eßer // I think I can set rdx directly to zero here because n should be a
249850696a6eSStefan Eßer // new number with sign set to false.
249950696a6eSStefan Eßer n->len = n->rdx = 0;
250050696a6eSStefan Eßer }
250178bc019dSStefan Eßer else
250278bc019dSStefan Eßer {
250344d4804dSStefan Eßer // There is actually stuff to parse if we make it here. Yay...
2504252884aeSStefan Eßer BcBigDig exp, pow;
2505252884aeSStefan Eßer
2506252884aeSStefan Eßer assert(i <= BC_NUM_BIGDIG_MAX);
2507252884aeSStefan Eßer
250844d4804dSStefan Eßer // The exponent and power.
2509252884aeSStefan Eßer exp = (BcBigDig) i;
2510252884aeSStefan Eßer pow = bc_num_pow10[exp];
2511252884aeSStefan Eßer
251244d4804dSStefan Eßer // Parse loop. We parse backwards because numbers are stored little
251344d4804dSStefan Eßer // endian.
251478bc019dSStefan Eßer for (i = len - 1; i < len; --i, ++exp)
251578bc019dSStefan Eßer {
2516252884aeSStefan Eßer char c = val[i];
2517252884aeSStefan Eßer
251844d4804dSStefan Eßer // Skip the decimal point.
2519252884aeSStefan Eßer if (c == '.') exp -= 1;
252078bc019dSStefan Eßer else
252178bc019dSStefan Eßer {
252244d4804dSStefan Eßer // The index of the limb.
2523252884aeSStefan Eßer size_t idx = exp / BC_BASE_DIGS;
2524d101cdd6SStefan Eßer BcBigDig dig;
2525252884aeSStefan Eßer
2526d101cdd6SStefan Eßer if (isupper(c))
2527d101cdd6SStefan Eßer {
252844d4804dSStefan Eßer // Clamp for the base.
2529d101cdd6SStefan Eßer if (!BC_DIGIT_CLAMP) c = BC_NUM_NUM_LETTER(c);
2530d101cdd6SStefan Eßer else c = 9;
2531d101cdd6SStefan Eßer }
2532d101cdd6SStefan Eßer else c -= '0';
253344d4804dSStefan Eßer
2534d101cdd6SStefan Eßer // Add the digit to the limb. This takes care of overflow from
2535d101cdd6SStefan Eßer // lack of clamping.
2536d101cdd6SStefan Eßer dig = ((BcBigDig) n->num[idx]) + ((BcBigDig) c) * pow;
2537d101cdd6SStefan Eßer if (dig >= BC_BASE_POW)
2538d101cdd6SStefan Eßer {
2539d101cdd6SStefan Eßer // We cannot go over BC_BASE_POW with clamping.
2540d101cdd6SStefan Eßer assert(!BC_DIGIT_CLAMP);
2541d101cdd6SStefan Eßer
2542d101cdd6SStefan Eßer n->num[idx + 1] = (BcDig) (dig / BC_BASE_POW);
2543d101cdd6SStefan Eßer n->num[idx] = (BcDig) (dig % BC_BASE_POW);
2544d101cdd6SStefan Eßer assert(n->num[idx] >= 0 && n->num[idx] < BC_BASE_POW);
2545d101cdd6SStefan Eßer assert(n->num[idx + 1] >= 0 &&
2546d101cdd6SStefan Eßer n->num[idx + 1] < BC_BASE_POW);
2547d101cdd6SStefan Eßer }
2548d101cdd6SStefan Eßer else
2549d101cdd6SStefan Eßer {
2550d101cdd6SStefan Eßer n->num[idx] = (BcDig) dig;
2551d101cdd6SStefan Eßer assert(n->num[idx] >= 0 && n->num[idx] < BC_BASE_POW);
2552d101cdd6SStefan Eßer }
2553252884aeSStefan Eßer
255444d4804dSStefan Eßer // Adjust the power and exponent.
2555252884aeSStefan Eßer if ((exp + 1) % BC_BASE_DIGS == 0) pow = 1;
2556252884aeSStefan Eßer else pow *= BC_BASE;
2557252884aeSStefan Eßer }
2558252884aeSStefan Eßer }
2559252884aeSStefan Eßer }
2560d101cdd6SStefan Eßer
2561d101cdd6SStefan Eßer // Make sure to add one to the length if needed from lack of clamping.
2562d101cdd6SStefan Eßer n->len += (!BC_DIGIT_CLAMP && n->num[n->len] != 0);
2563252884aeSStefan Eßer }
2564252884aeSStefan Eßer
256544d4804dSStefan Eßer /**
256644d4804dSStefan Eßer * Parse a number in any base (besides decimal).
256744d4804dSStefan Eßer * @param n The number to parse into and return. Must be preallocated.
256844d4804dSStefan Eßer * @param val The string to parse.
256944d4804dSStefan Eßer * @param base The base to parse as.
257044d4804dSStefan Eßer */
257178bc019dSStefan Eßer static void
bc_num_parseBase(BcNum * restrict n,const char * restrict val,BcBigDig base)257278bc019dSStefan Eßer bc_num_parseBase(BcNum* restrict n, const char* restrict val, BcBigDig base)
2573252884aeSStefan Eßer {
257478bc019dSStefan Eßer BcNum temp, mult1, mult2, result1, result2;
257578bc019dSStefan Eßer BcNum* m1;
257678bc019dSStefan Eßer BcNum* m2;
257778bc019dSStefan Eßer BcNum* ptr;
2578252884aeSStefan Eßer char c = 0;
2579252884aeSStefan Eßer bool zero = true;
2580252884aeSStefan Eßer BcBigDig v;
2581d101cdd6SStefan Eßer size_t digs, len = strlen(val);
2582d101cdd6SStefan Eßer // This is volatile to quiet a warning on GCC about longjmp() clobbering.
2583d101cdd6SStefan Eßer volatile size_t i;
2584d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2585d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
2586d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2587252884aeSStefan Eßer
258844d4804dSStefan Eßer // If zero, just return because the number should be virgin (already 0).
258978bc019dSStefan Eßer for (i = 0; zero && i < len; ++i)
259078bc019dSStefan Eßer {
259178bc019dSStefan Eßer zero = (val[i] == '.' || val[i] == '0');
259278bc019dSStefan Eßer }
2593252884aeSStefan Eßer if (zero) return;
2594252884aeSStefan Eßer
2595252884aeSStefan Eßer BC_SIG_LOCK;
2596252884aeSStefan Eßer
2597252884aeSStefan Eßer bc_num_init(&temp, BC_NUM_BIGDIG_LOG10);
2598252884aeSStefan Eßer bc_num_init(&mult1, BC_NUM_BIGDIG_LOG10);
2599252884aeSStefan Eßer
2600d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, int_err);
2601252884aeSStefan Eßer
2602252884aeSStefan Eßer BC_SIG_UNLOCK;
2603252884aeSStefan Eßer
260444d4804dSStefan Eßer // We split parsing into parsing the integer and parsing the fractional
260544d4804dSStefan Eßer // part.
260644d4804dSStefan Eßer
260744d4804dSStefan Eßer // Parse the integer part. This is the easy part because we just multiply
260844d4804dSStefan Eßer // the number by the base, then add the digit.
260978bc019dSStefan Eßer for (i = 0; i < len && (c = val[i]) && c != '.'; ++i)
261078bc019dSStefan Eßer {
261144d4804dSStefan Eßer // Convert the character to a digit.
2612252884aeSStefan Eßer v = bc_num_parseChar(c, base);
2613252884aeSStefan Eßer
261444d4804dSStefan Eßer // Multiply the number.
2615252884aeSStefan Eßer bc_num_mulArray(n, base, &mult1);
261644d4804dSStefan Eßer
261744d4804dSStefan Eßer // Convert the digit to a number and add.
2618252884aeSStefan Eßer bc_num_bigdig2num(&temp, v);
2619252884aeSStefan Eßer bc_num_add(&mult1, &temp, n, 0);
2620252884aeSStefan Eßer }
2621252884aeSStefan Eßer
262244d4804dSStefan Eßer // If this condition is true, then we are done. We still need to do cleanup
262344d4804dSStefan Eßer // though.
262410328f8bSStefan Eßer if (i == len && !val[i]) goto int_err;
2625252884aeSStefan Eßer
262644d4804dSStefan Eßer // If we get here, we *must* be at the radix point.
262710328f8bSStefan Eßer assert(val[i] == '.');
2628252884aeSStefan Eßer
2629252884aeSStefan Eßer BC_SIG_LOCK;
2630252884aeSStefan Eßer
263144d4804dSStefan Eßer // Unset the jump to reset in for these new initializations.
2632d101cdd6SStefan Eßer BC_UNSETJMP(vm);
2633252884aeSStefan Eßer
2634252884aeSStefan Eßer bc_num_init(&mult2, BC_NUM_BIGDIG_LOG10);
2635252884aeSStefan Eßer bc_num_init(&result1, BC_NUM_DEF_SIZE);
2636252884aeSStefan Eßer bc_num_init(&result2, BC_NUM_DEF_SIZE);
2637252884aeSStefan Eßer bc_num_one(&mult1);
2638252884aeSStefan Eßer
2639d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
2640252884aeSStefan Eßer
2641252884aeSStefan Eßer BC_SIG_UNLOCK;
2642252884aeSStefan Eßer
264344d4804dSStefan Eßer // Pointers for easy switching.
2644252884aeSStefan Eßer m1 = &mult1;
2645252884aeSStefan Eßer m2 = &mult2;
2646252884aeSStefan Eßer
264744d4804dSStefan Eßer // Parse the fractional part. This is the hard part.
264878bc019dSStefan Eßer for (i += 1, digs = 0; i < len && (c = val[i]); ++i, ++digs)
264978bc019dSStefan Eßer {
265050696a6eSStefan Eßer size_t rdx;
265150696a6eSStefan Eßer
265244d4804dSStefan Eßer // Convert the character to a digit.
2653252884aeSStefan Eßer v = bc_num_parseChar(c, base);
2654252884aeSStefan Eßer
265544d4804dSStefan Eßer // We keep growing result2 according to the base because the more digits
265644d4804dSStefan Eßer // after the radix, the more significant the digits close to the radix
265744d4804dSStefan Eßer // should be.
2658252884aeSStefan Eßer bc_num_mulArray(&result1, base, &result2);
2659252884aeSStefan Eßer
266044d4804dSStefan Eßer // Convert the digit to a number.
2661252884aeSStefan Eßer bc_num_bigdig2num(&temp, v);
266244d4804dSStefan Eßer
266344d4804dSStefan Eßer // Add the digit into the fraction part.
2664252884aeSStefan Eßer bc_num_add(&result2, &temp, &result1, 0);
266544d4804dSStefan Eßer
266644d4804dSStefan Eßer // Keep growing m1 and m2 for use after the loop.
2667252884aeSStefan Eßer bc_num_mulArray(m1, base, m2);
2668252884aeSStefan Eßer
266950696a6eSStefan Eßer rdx = BC_NUM_RDX_VAL(m2);
267050696a6eSStefan Eßer
267150696a6eSStefan Eßer if (m2->len < rdx) m2->len = rdx;
2672252884aeSStefan Eßer
267344d4804dSStefan Eßer // Switch.
2674252884aeSStefan Eßer ptr = m1;
2675252884aeSStefan Eßer m1 = m2;
2676252884aeSStefan Eßer m2 = ptr;
2677252884aeSStefan Eßer }
2678252884aeSStefan Eßer
2679252884aeSStefan Eßer // This one cannot be a divide by 0 because mult starts out at 1, then is
268044d4804dSStefan Eßer // multiplied by base, and base cannot be 0, so mult cannot be 0. And this
268144d4804dSStefan Eßer // is the reason we keep growing m1 and m2; this division is what converts
268244d4804dSStefan Eßer // the parsed fractional part from an integer to a fractional part.
2683252884aeSStefan Eßer bc_num_div(&result1, m1, &result2, digs * 2);
268444d4804dSStefan Eßer
268544d4804dSStefan Eßer // Pretruncate.
2686252884aeSStefan Eßer bc_num_truncate(&result2, digs);
268744d4804dSStefan Eßer
268844d4804dSStefan Eßer // The final add of the integer part to the fractional part.
2689252884aeSStefan Eßer bc_num_add(n, &result2, n, digs);
2690252884aeSStefan Eßer
269144d4804dSStefan Eßer // Basic cleanup.
269278bc019dSStefan Eßer if (BC_NUM_NONZERO(n))
269378bc019dSStefan Eßer {
2694252884aeSStefan Eßer if (n->scale < digs) bc_num_extend(n, digs - n->scale);
2695252884aeSStefan Eßer }
2696252884aeSStefan Eßer else bc_num_zero(n);
2697252884aeSStefan Eßer
2698252884aeSStefan Eßer err:
2699252884aeSStefan Eßer BC_SIG_MAYLOCK;
2700252884aeSStefan Eßer bc_num_free(&result2);
2701252884aeSStefan Eßer bc_num_free(&result1);
2702252884aeSStefan Eßer bc_num_free(&mult2);
2703252884aeSStefan Eßer int_err:
2704252884aeSStefan Eßer BC_SIG_MAYLOCK;
2705252884aeSStefan Eßer bc_num_free(&mult1);
2706252884aeSStefan Eßer bc_num_free(&temp);
2707d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
2708252884aeSStefan Eßer }
2709252884aeSStefan Eßer
271044d4804dSStefan Eßer /**
271144d4804dSStefan Eßer * Prints a backslash+newline combo if the number of characters needs it. This
271244d4804dSStefan Eßer * is really a convenience function.
271344d4804dSStefan Eßer */
271478bc019dSStefan Eßer static inline void
bc_num_printNewline(void)271578bc019dSStefan Eßer bc_num_printNewline(void)
271678bc019dSStefan Eßer {
271750696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY
2718d101cdd6SStefan Eßer if (vm->nchars >= vm->line_len - 1 && vm->line_len)
271978bc019dSStefan Eßer {
27207e5c51e5SStefan Eßer bc_vm_putchar('\\', bc_flush_none);
27217e5c51e5SStefan Eßer bc_vm_putchar('\n', bc_flush_err);
2722252884aeSStefan Eßer }
272350696a6eSStefan Eßer #endif // !BC_ENABLE_LIBRARY
2724252884aeSStefan Eßer }
2725252884aeSStefan Eßer
272644d4804dSStefan Eßer /**
272744d4804dSStefan Eßer * Prints a character after a backslash+newline, if needed.
272844d4804dSStefan Eßer * @param c The character to print.
272944d4804dSStefan Eßer * @param bslash Whether to print a backslash+newline.
273044d4804dSStefan Eßer */
273178bc019dSStefan Eßer static void
bc_num_putchar(int c,bool bslash)273278bc019dSStefan Eßer bc_num_putchar(int c, bool bslash)
273378bc019dSStefan Eßer {
273444d4804dSStefan Eßer if (c != '\n' && bslash) bc_num_printNewline();
27357e5c51e5SStefan Eßer bc_vm_putchar(c, bc_flush_save);
2736252884aeSStefan Eßer }
2737252884aeSStefan Eßer
273844d4804dSStefan Eßer #if !BC_ENABLE_LIBRARY
273944d4804dSStefan Eßer
274044d4804dSStefan Eßer /**
274144d4804dSStefan Eßer * Prints a character for a number's digit. This is for printing for dc's P
274244d4804dSStefan Eßer * command. This function does not need to worry about radix points. This is a
274344d4804dSStefan Eßer * BcNumDigitOp.
274444d4804dSStefan Eßer * @param n The "digit" to print.
274544d4804dSStefan Eßer * @param len The "length" of the digit, or number of characters that will
274644d4804dSStefan Eßer * need to be printed for the digit.
274744d4804dSStefan Eßer * @param rdx True if a decimal (radix) point should be printed.
274844d4804dSStefan Eßer * @param bslash True if a backslash+newline should be printed if the character
274944d4804dSStefan Eßer * limit for the line is reached, false otherwise.
275044d4804dSStefan Eßer */
275178bc019dSStefan Eßer static void
bc_num_printChar(size_t n,size_t len,bool rdx,bool bslash)275278bc019dSStefan Eßer bc_num_printChar(size_t n, size_t len, bool rdx, bool bslash)
275378bc019dSStefan Eßer {
2754252884aeSStefan Eßer BC_UNUSED(rdx);
2755252884aeSStefan Eßer BC_UNUSED(len);
275644d4804dSStefan Eßer BC_UNUSED(bslash);
2757252884aeSStefan Eßer assert(len == 1);
27587e5c51e5SStefan Eßer bc_vm_putchar((uchar) n, bc_flush_save);
2759252884aeSStefan Eßer }
2760252884aeSStefan Eßer
276144d4804dSStefan Eßer #endif // !BC_ENABLE_LIBRARY
276244d4804dSStefan Eßer
276344d4804dSStefan Eßer /**
276444d4804dSStefan Eßer * Prints a series of characters for large bases. This is for printing in bases
276544d4804dSStefan Eßer * above hexadecimal. This is a BcNumDigitOp.
276644d4804dSStefan Eßer * @param n The "digit" to print.
276744d4804dSStefan Eßer * @param len The "length" of the digit, or number of characters that will
276844d4804dSStefan Eßer * need to be printed for the digit.
276944d4804dSStefan Eßer * @param rdx True if a decimal (radix) point should be printed.
277044d4804dSStefan Eßer * @param bslash True if a backslash+newline should be printed if the character
277144d4804dSStefan Eßer * limit for the line is reached, false otherwise.
277244d4804dSStefan Eßer */
277378bc019dSStefan Eßer static void
bc_num_printDigits(size_t n,size_t len,bool rdx,bool bslash)277478bc019dSStefan Eßer bc_num_printDigits(size_t n, size_t len, bool rdx, bool bslash)
277578bc019dSStefan Eßer {
2776252884aeSStefan Eßer size_t exp, pow;
2777252884aeSStefan Eßer
277844d4804dSStefan Eßer // If needed, print the radix; otherwise, print a space to separate digits.
277944d4804dSStefan Eßer bc_num_putchar(rdx ? '.' : ' ', true);
2780252884aeSStefan Eßer
278144d4804dSStefan Eßer // Calculate the exponent and power.
278278bc019dSStefan Eßer for (exp = 0, pow = 1; exp < len - 1; ++exp, pow *= BC_BASE)
278378bc019dSStefan Eßer {
278478bc019dSStefan Eßer continue;
278578bc019dSStefan Eßer }
2786252884aeSStefan Eßer
278744d4804dSStefan Eßer // Print each character individually.
278878bc019dSStefan Eßer for (exp = 0; exp < len; pow /= BC_BASE, ++exp)
278978bc019dSStefan Eßer {
279044d4804dSStefan Eßer // The individual subdigit.
2791252884aeSStefan Eßer size_t dig = n / pow;
279244d4804dSStefan Eßer
279344d4804dSStefan Eßer // Take the subdigit away.
2794252884aeSStefan Eßer n -= dig * pow;
279544d4804dSStefan Eßer
279644d4804dSStefan Eßer // Print the subdigit.
279744d4804dSStefan Eßer bc_num_putchar(((uchar) dig) + '0', bslash || exp != len - 1);
2798252884aeSStefan Eßer }
2799252884aeSStefan Eßer }
2800252884aeSStefan Eßer
280144d4804dSStefan Eßer /**
280244d4804dSStefan Eßer * Prints a character for a number's digit. This is for printing in bases for
280344d4804dSStefan Eßer * hexadecimal and below because they always print only one character at a time.
280444d4804dSStefan Eßer * This is a BcNumDigitOp.
280544d4804dSStefan Eßer * @param n The "digit" to print.
280644d4804dSStefan Eßer * @param len The "length" of the digit, or number of characters that will
280744d4804dSStefan Eßer * need to be printed for the digit.
280844d4804dSStefan Eßer * @param rdx True if a decimal (radix) point should be printed.
280944d4804dSStefan Eßer * @param bslash True if a backslash+newline should be printed if the character
281044d4804dSStefan Eßer * limit for the line is reached, false otherwise.
281144d4804dSStefan Eßer */
281278bc019dSStefan Eßer static void
bc_num_printHex(size_t n,size_t len,bool rdx,bool bslash)281378bc019dSStefan Eßer bc_num_printHex(size_t n, size_t len, bool rdx, bool bslash)
281478bc019dSStefan Eßer {
2815252884aeSStefan Eßer BC_UNUSED(len);
281644d4804dSStefan Eßer BC_UNUSED(bslash);
2817252884aeSStefan Eßer
2818252884aeSStefan Eßer assert(len == 1);
2819252884aeSStefan Eßer
282044d4804dSStefan Eßer if (rdx) bc_num_putchar('.', true);
2821252884aeSStefan Eßer
282244d4804dSStefan Eßer bc_num_putchar(bc_num_hex_digits[n], bslash);
2823252884aeSStefan Eßer }
2824252884aeSStefan Eßer
282544d4804dSStefan Eßer /**
282644d4804dSStefan Eßer * Prints a decimal number. This is specially written for optimization since
282744d4804dSStefan Eßer * this will be used the most and because bc's numbers are already in decimal.
282844d4804dSStefan Eßer * @param n The number to print.
282944d4804dSStefan Eßer * @param newline Whether to print backslash+newlines on long enough lines.
283044d4804dSStefan Eßer */
283178bc019dSStefan Eßer static void
bc_num_printDecimal(const BcNum * restrict n,bool newline)283278bc019dSStefan Eßer bc_num_printDecimal(const BcNum* restrict n, bool newline)
283378bc019dSStefan Eßer {
283450696a6eSStefan Eßer size_t i, j, rdx = BC_NUM_RDX_VAL(n);
2835252884aeSStefan Eßer bool zero = true;
2836252884aeSStefan Eßer size_t buffer[BC_BASE_DIGS];
2837252884aeSStefan Eßer
283844d4804dSStefan Eßer // Print loop.
283978bc019dSStefan Eßer for (i = n->len - 1; i < n->len; --i)
284078bc019dSStefan Eßer {
2841252884aeSStefan Eßer BcDig n9 = n->num[i];
2842252884aeSStefan Eßer size_t temp;
2843252884aeSStefan Eßer bool irdx = (i == rdx - 1);
2844252884aeSStefan Eßer
284544d4804dSStefan Eßer // Calculate the number of digits in the limb.
2846252884aeSStefan Eßer zero = (zero & !irdx);
2847252884aeSStefan Eßer temp = n->scale % BC_BASE_DIGS;
2848252884aeSStefan Eßer temp = i || !temp ? 0 : BC_BASE_DIGS - temp;
2849252884aeSStefan Eßer
285078bc019dSStefan Eßer // NOLINTNEXTLINE
2851252884aeSStefan Eßer memset(buffer, 0, BC_BASE_DIGS * sizeof(size_t));
2852252884aeSStefan Eßer
285344d4804dSStefan Eßer // Fill the buffer with individual digits.
285478bc019dSStefan Eßer for (j = 0; n9 && j < BC_BASE_DIGS; ++j)
285578bc019dSStefan Eßer {
2856d213476dSStefan Eßer buffer[j] = ((size_t) n9) % BC_BASE;
2857252884aeSStefan Eßer n9 /= BC_BASE;
2858252884aeSStefan Eßer }
2859252884aeSStefan Eßer
286044d4804dSStefan Eßer // Print the digits in the buffer.
286178bc019dSStefan Eßer for (j = BC_BASE_DIGS - 1; j < BC_BASE_DIGS && j >= temp; --j)
286278bc019dSStefan Eßer {
286344d4804dSStefan Eßer // Figure out whether to print the decimal point.
2864252884aeSStefan Eßer bool print_rdx = (irdx & (j == BC_BASE_DIGS - 1));
286544d4804dSStefan Eßer
286644d4804dSStefan Eßer // The zero variable helps us skip leading zero digits in the limb.
2867252884aeSStefan Eßer zero = (zero && buffer[j] == 0);
286844d4804dSStefan Eßer
286978bc019dSStefan Eßer if (!zero)
287078bc019dSStefan Eßer {
287144d4804dSStefan Eßer // While the first three arguments should be self-explanatory,
287244d4804dSStefan Eßer // the last needs explaining. I don't want to print a newline
287344d4804dSStefan Eßer // when the last digit to be printed could take the place of the
287444d4804dSStefan Eßer // backslash rather than being pushed, as a single character, to
287544d4804dSStefan Eßer // the next line. That's what that last argument does for bc.
287644d4804dSStefan Eßer bc_num_printHex(buffer[j], 1, print_rdx,
287744d4804dSStefan Eßer !newline || (j > temp || i != 0));
287844d4804dSStefan Eßer }
2879252884aeSStefan Eßer }
2880252884aeSStefan Eßer }
2881252884aeSStefan Eßer }
2882252884aeSStefan Eßer
2883252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
2884252884aeSStefan Eßer
288544d4804dSStefan Eßer /**
288644d4804dSStefan Eßer * Prints a number in scientific or engineering format. When doing this, we are
288744d4804dSStefan Eßer * always printing in decimal.
288844d4804dSStefan Eßer * @param n The number to print.
288944d4804dSStefan Eßer * @param eng True if we are in engineering mode.
289044d4804dSStefan Eßer * @param newline Whether to print backslash+newlines on long enough lines.
289144d4804dSStefan Eßer */
289278bc019dSStefan Eßer static void
bc_num_printExponent(const BcNum * restrict n,bool eng,bool newline)289378bc019dSStefan Eßer bc_num_printExponent(const BcNum* restrict n, bool eng, bool newline)
289444d4804dSStefan Eßer {
289550696a6eSStefan Eßer size_t places, mod, nrdx = BC_NUM_RDX_VAL(n);
289650696a6eSStefan Eßer bool neg = (n->len <= nrdx);
2897252884aeSStefan Eßer BcNum temp, exp;
2898252884aeSStefan Eßer BcDig digs[BC_NUM_BIGDIG_LOG10];
2899d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
2900d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
2901d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
2902252884aeSStefan Eßer
2903252884aeSStefan Eßer BC_SIG_LOCK;
2904252884aeSStefan Eßer
2905252884aeSStefan Eßer bc_num_createCopy(&temp, n);
2906252884aeSStefan Eßer
2907d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, exit);
2908252884aeSStefan Eßer
2909252884aeSStefan Eßer BC_SIG_UNLOCK;
2910252884aeSStefan Eßer
291144d4804dSStefan Eßer // We need to calculate the exponents, and they change based on whether the
291244d4804dSStefan Eßer // number is all fractional or not, obviously.
291378bc019dSStefan Eßer if (neg)
291478bc019dSStefan Eßer {
2915a970610aSStefan Eßer // Figure out the negative power of 10.
2916a970610aSStefan Eßer places = bc_num_negPow10(n);
2917252884aeSStefan Eßer
2918a970610aSStefan Eßer // Figure out how many digits mod 3 there are (important for
2919a970610aSStefan Eßer // engineering mode).
2920252884aeSStefan Eßer mod = places % 3;
2921252884aeSStefan Eßer
292244d4804dSStefan Eßer // Calculate places if we are in engineering mode.
2923252884aeSStefan Eßer if (eng && mod != 0) places += 3 - mod;
292444d4804dSStefan Eßer
292544d4804dSStefan Eßer // Shift the temp to the right place.
2926252884aeSStefan Eßer bc_num_shiftLeft(&temp, places);
2927252884aeSStefan Eßer }
292878bc019dSStefan Eßer else
292978bc019dSStefan Eßer {
293044d4804dSStefan Eßer // This is the number of digits that we are supposed to put behind the
293144d4804dSStefan Eßer // decimal point.
2932252884aeSStefan Eßer places = bc_num_intDigits(n) - 1;
293344d4804dSStefan Eßer
293444d4804dSStefan Eßer // Calculate the true number based on whether engineering mode is
293544d4804dSStefan Eßer // activated.
2936252884aeSStefan Eßer mod = places % 3;
2937252884aeSStefan Eßer if (eng && mod != 0) places -= 3 - (3 - mod);
293844d4804dSStefan Eßer
293944d4804dSStefan Eßer // Shift the temp to the right place.
2940252884aeSStefan Eßer bc_num_shiftRight(&temp, places);
2941252884aeSStefan Eßer }
2942252884aeSStefan Eßer
294344d4804dSStefan Eßer // Print the shifted number.
294444d4804dSStefan Eßer bc_num_printDecimal(&temp, newline);
2945252884aeSStefan Eßer
294644d4804dSStefan Eßer // Print the e.
294744d4804dSStefan Eßer bc_num_putchar('e', !newline);
294844d4804dSStefan Eßer
294944d4804dSStefan Eßer // Need to explicitly print a zero exponent.
295078bc019dSStefan Eßer if (!places)
295178bc019dSStefan Eßer {
295244d4804dSStefan Eßer bc_num_printHex(0, 1, false, !newline);
2953252884aeSStefan Eßer goto exit;
2954252884aeSStefan Eßer }
2955252884aeSStefan Eßer
295644d4804dSStefan Eßer // Need to print sign for the exponent.
295744d4804dSStefan Eßer if (neg) bc_num_putchar('-', true);
2958252884aeSStefan Eßer
295944d4804dSStefan Eßer // Create a temporary for the exponent...
2960252884aeSStefan Eßer bc_num_setup(&exp, digs, BC_NUM_BIGDIG_LOG10);
2961252884aeSStefan Eßer bc_num_bigdig2num(&exp, (BcBigDig) places);
2962252884aeSStefan Eßer
296344d4804dSStefan Eßer /// ..and print it.
296444d4804dSStefan Eßer bc_num_printDecimal(&exp, newline);
2965252884aeSStefan Eßer
2966252884aeSStefan Eßer exit:
2967252884aeSStefan Eßer BC_SIG_MAYLOCK;
2968252884aeSStefan Eßer bc_num_free(&temp);
2969d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
2970252884aeSStefan Eßer }
2971252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
2972252884aeSStefan Eßer
297344d4804dSStefan Eßer /**
2974aa339f1dSStefan Eßer * Takes a number with limbs with base BC_BASE_POW and converts the limb at the
2975aa339f1dSStefan Eßer * given index to base @a pow, where @a pow is obase^N.
297644d4804dSStefan Eßer * @param n The number to convert.
297744d4804dSStefan Eßer * @param rem BC_BASE_POW - @a pow.
297844d4804dSStefan Eßer * @param pow The power of obase we will convert the number to.
297944d4804dSStefan Eßer * @param idx The index of the number to start converting at. Doing the
298044d4804dSStefan Eßer * conversion is O(n^2); we have to sweep through starting at the
2981aa339f1dSStefan Eßer * least significant limb.
298244d4804dSStefan Eßer */
298378bc019dSStefan Eßer static void
bc_num_printFixup(BcNum * restrict n,BcBigDig rem,BcBigDig pow,size_t idx)298478bc019dSStefan Eßer bc_num_printFixup(BcNum* restrict n, BcBigDig rem, BcBigDig pow, size_t idx)
2985252884aeSStefan Eßer {
2986252884aeSStefan Eßer size_t i, len = n->len - idx;
2987252884aeSStefan Eßer BcBigDig acc;
2988252884aeSStefan Eßer BcDig* a = n->num + idx;
2989252884aeSStefan Eßer
299044d4804dSStefan Eßer // Ignore if there's just one limb left. This is the part that requires the
299144d4804dSStefan Eßer // extra loop after the one calling this function in bc_num_printPrepare().
2992252884aeSStefan Eßer if (len < 2) return;
2993252884aeSStefan Eßer
299444d4804dSStefan Eßer // Loop through the remaining limbs and convert. We start at the second limb
299544d4804dSStefan Eßer // because we pull the value from the previous one as well.
299678bc019dSStefan Eßer for (i = len - 1; i > 0; --i)
299778bc019dSStefan Eßer {
299844d4804dSStefan Eßer // Get the limb and add it to the previous, along with multiplying by
299944d4804dSStefan Eßer // the remainder because that's the proper overflow. "acc" means
300044d4804dSStefan Eßer // "accumulator," by the way.
3001252884aeSStefan Eßer acc = ((BcBigDig) a[i]) * rem + ((BcBigDig) a[i - 1]);
300244d4804dSStefan Eßer
300344d4804dSStefan Eßer // Store a value in base pow in the previous limb.
3004252884aeSStefan Eßer a[i - 1] = (BcDig) (acc % pow);
300544d4804dSStefan Eßer
300644d4804dSStefan Eßer // Divide by the base and accumulate the remaining value in the limb.
3007252884aeSStefan Eßer acc /= pow;
3008252884aeSStefan Eßer acc += (BcBigDig) a[i];
3009252884aeSStefan Eßer
301044d4804dSStefan Eßer // If the accumulator is greater than the base...
301178bc019dSStefan Eßer if (acc >= BC_BASE_POW)
301278bc019dSStefan Eßer {
301344d4804dSStefan Eßer // Do we need to grow?
301478bc019dSStefan Eßer if (i == len - 1)
301578bc019dSStefan Eßer {
301644d4804dSStefan Eßer // Grow.
3017252884aeSStefan Eßer len = bc_vm_growSize(len, 1);
3018252884aeSStefan Eßer bc_num_expand(n, bc_vm_growSize(len, idx));
301944d4804dSStefan Eßer
302044d4804dSStefan Eßer // Update the pointer because it may have moved.
3021252884aeSStefan Eßer a = n->num + idx;
302244d4804dSStefan Eßer
302344d4804dSStefan Eßer // Zero out the last limb.
3024252884aeSStefan Eßer a[len - 1] = 0;
3025252884aeSStefan Eßer }
3026252884aeSStefan Eßer
302744d4804dSStefan Eßer // Overflow into the next limb since we are over the base.
3028252884aeSStefan Eßer a[i + 1] += acc / BC_BASE_POW;
3029252884aeSStefan Eßer acc %= BC_BASE_POW;
3030252884aeSStefan Eßer }
3031252884aeSStefan Eßer
3032252884aeSStefan Eßer assert(acc < BC_BASE_POW);
303344d4804dSStefan Eßer
303444d4804dSStefan Eßer // Set the limb.
3035252884aeSStefan Eßer a[i] = (BcDig) acc;
3036252884aeSStefan Eßer }
3037252884aeSStefan Eßer
303844d4804dSStefan Eßer // We may have grown the number, so adjust the length.
3039252884aeSStefan Eßer n->len = len + idx;
3040252884aeSStefan Eßer }
3041252884aeSStefan Eßer
304244d4804dSStefan Eßer /**
3043aa339f1dSStefan Eßer * Prepares a number for printing in a base that does not have BC_BASE_POW as a
3044aa339f1dSStefan Eßer * power. This basically converts the number from having limbs of base
304544d4804dSStefan Eßer * BC_BASE_POW to limbs of pow, where pow is obase^N.
304644d4804dSStefan Eßer * @param n The number to prepare for printing.
304744d4804dSStefan Eßer * @param rem The remainder of BC_BASE_POW when divided by a power of the base.
304844d4804dSStefan Eßer * @param pow The power of the base.
304944d4804dSStefan Eßer */
305078bc019dSStefan Eßer static void
bc_num_printPrepare(BcNum * restrict n,BcBigDig rem,BcBigDig pow)305178bc019dSStefan Eßer bc_num_printPrepare(BcNum* restrict n, BcBigDig rem, BcBigDig pow)
305278bc019dSStefan Eßer {
3053252884aeSStefan Eßer size_t i;
3054252884aeSStefan Eßer
305544d4804dSStefan Eßer // Loop from the least significant limb to the most significant limb and
305644d4804dSStefan Eßer // convert limbs in each pass.
305778bc019dSStefan Eßer for (i = 0; i < n->len; ++i)
305878bc019dSStefan Eßer {
305978bc019dSStefan Eßer bc_num_printFixup(n, rem, pow, i);
306078bc019dSStefan Eßer }
3061252884aeSStefan Eßer
306244d4804dSStefan Eßer // bc_num_printFixup() does not do everything it is supposed to, so we do
306344d4804dSStefan Eßer // the last bit of cleanup here. That cleanup is to ensure that each limb
306444d4804dSStefan Eßer // is less than pow and to expand the number to fit new limbs as necessary.
306578bc019dSStefan Eßer for (i = 0; i < n->len; ++i)
306678bc019dSStefan Eßer {
3067252884aeSStefan Eßer assert(pow == ((BcBigDig) ((BcDig) pow)));
3068252884aeSStefan Eßer
306944d4804dSStefan Eßer // If the limb needs fixing...
307078bc019dSStefan Eßer if (n->num[i] >= (BcDig) pow)
307178bc019dSStefan Eßer {
307244d4804dSStefan Eßer // Do we need to grow?
307378bc019dSStefan Eßer if (i + 1 == n->len)
307478bc019dSStefan Eßer {
307544d4804dSStefan Eßer // Grow the number.
3076252884aeSStefan Eßer n->len = bc_vm_growSize(n->len, 1);
3077252884aeSStefan Eßer bc_num_expand(n, n->len);
307844d4804dSStefan Eßer
307944d4804dSStefan Eßer // Without this, we might use uninitialized data.
3080252884aeSStefan Eßer n->num[i + 1] = 0;
3081252884aeSStefan Eßer }
3082252884aeSStefan Eßer
3083252884aeSStefan Eßer assert(pow < BC_BASE_POW);
308444d4804dSStefan Eßer
308544d4804dSStefan Eßer // Overflow into the next limb.
3086252884aeSStefan Eßer n->num[i + 1] += n->num[i] / ((BcDig) pow);
3087252884aeSStefan Eßer n->num[i] %= (BcDig) pow;
3088252884aeSStefan Eßer }
3089252884aeSStefan Eßer }
3090252884aeSStefan Eßer }
3091252884aeSStefan Eßer
309278bc019dSStefan Eßer static void
bc_num_printNum(BcNum * restrict n,BcBigDig base,size_t len,BcNumDigitOp print,bool newline)309378bc019dSStefan Eßer bc_num_printNum(BcNum* restrict n, BcBigDig base, size_t len,
309444d4804dSStefan Eßer BcNumDigitOp print, bool newline)
3095252884aeSStefan Eßer {
3096252884aeSStefan Eßer BcVec stack;
309778bc019dSStefan Eßer BcNum intp, fracp1, fracp2, digit, flen1, flen2;
309878bc019dSStefan Eßer BcNum* n1;
309978bc019dSStefan Eßer BcNum* n2;
310078bc019dSStefan Eßer BcNum* temp;
310178bc019dSStefan Eßer BcBigDig dig = 0, acc, exp;
310278bc019dSStefan Eßer BcBigDig* ptr;
310344d4804dSStefan Eßer size_t i, j, nrdx, idigits;
3104252884aeSStefan Eßer bool radix;
3105252884aeSStefan Eßer BcDig digit_digs[BC_NUM_BIGDIG_LOG10 + 1];
3106d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3107d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
3108d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3109252884aeSStefan Eßer
3110252884aeSStefan Eßer assert(base > 1);
3111252884aeSStefan Eßer
311244d4804dSStefan Eßer // Easy case. Even with scale, we just print this.
311378bc019dSStefan Eßer if (BC_NUM_ZERO(n))
311478bc019dSStefan Eßer {
311544d4804dSStefan Eßer print(0, len, false, !newline);
3116252884aeSStefan Eßer return;
3117252884aeSStefan Eßer }
3118252884aeSStefan Eßer
3119252884aeSStefan Eßer // This function uses an algorithm that Stefan Esser <se@freebsd.org> came
3120252884aeSStefan Eßer // up with to print the integer part of a number. What it does is convert
3121252884aeSStefan Eßer // intp into a number of the specified base, but it does it directly,
3122252884aeSStefan Eßer // instead of just doing a series of divisions and printing the remainders
3123252884aeSStefan Eßer // in reverse order.
3124252884aeSStefan Eßer //
3125252884aeSStefan Eßer // Let me explain in a bit more detail:
3126252884aeSStefan Eßer //
312744d4804dSStefan Eßer // The algorithm takes the current least significant limb (after intp has
312844d4804dSStefan Eßer // been converted to an integer) and the next to least significant limb, and
312944d4804dSStefan Eßer // it converts the least significant limb into one of the specified base,
313044d4804dSStefan Eßer // putting any overflow into the next to least significant limb. It iterates
313144d4804dSStefan Eßer // through the whole number, from least significant to most significant,
313244d4804dSStefan Eßer // doing this conversion. At the end of that iteration, the least
313344d4804dSStefan Eßer // significant limb is converted, but the others are not, so it iterates
313444d4804dSStefan Eßer // again, starting at the next to least significant limb. It keeps doing
313544d4804dSStefan Eßer // that conversion, skipping one more limb than the last time, until all
313644d4804dSStefan Eßer // limbs have been converted. Then it prints them in reverse order.
3137252884aeSStefan Eßer //
3138252884aeSStefan Eßer // That is the gist of the algorithm. It leaves out several things, such as
313944d4804dSStefan Eßer // the fact that limbs are not always converted into the specified base, but
314044d4804dSStefan Eßer // into something close, basically a power of the specified base. In
3141252884aeSStefan Eßer // Stefan's words, "You could consider BcDigs to be of base 10^BC_BASE_DIGS
3142252884aeSStefan Eßer // in the normal case and obase^N for the largest value of N that satisfies
3143252884aeSStefan Eßer // obase^N <= 10^BC_BASE_DIGS. [This means that] the result is not in base
3144252884aeSStefan Eßer // "obase", but in base "obase^N", which happens to be printable as a number
3145252884aeSStefan Eßer // of base "obase" without consideration for neighbouring BcDigs." This fact
3146252884aeSStefan Eßer // is what necessitates the existence of the loop later in this function.
3147252884aeSStefan Eßer //
3148252884aeSStefan Eßer // The conversion happens in bc_num_printPrepare() where the outer loop
3149252884aeSStefan Eßer // happens and bc_num_printFixup() where the inner loop, or actual
315044d4804dSStefan Eßer // conversion, happens. In other words, bc_num_printPrepare() is where the
315144d4804dSStefan Eßer // loop that starts at the least significant limb and goes to the most
315244d4804dSStefan Eßer // significant limb. Then, on every iteration of its loop, it calls
315344d4804dSStefan Eßer // bc_num_printFixup(), which has the inner loop of actually converting
315444d4804dSStefan Eßer // the limbs it passes into limbs of base obase^N rather than base
315544d4804dSStefan Eßer // BC_BASE_POW.
3156252884aeSStefan Eßer
315750696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL(n);
315850696a6eSStefan Eßer
3159252884aeSStefan Eßer BC_SIG_LOCK;
3160252884aeSStefan Eßer
316144d4804dSStefan Eßer // The stack is what allows us to reverse the digits for printing.
316244d4804dSStefan Eßer bc_vec_init(&stack, sizeof(BcBigDig), BC_DTOR_NONE);
316350696a6eSStefan Eßer bc_num_init(&fracp1, nrdx);
3164252884aeSStefan Eßer
316544d4804dSStefan Eßer // intp will be the "integer part" of the number, so copy it.
3166252884aeSStefan Eßer bc_num_createCopy(&intp, n);
3167252884aeSStefan Eßer
3168d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
3169252884aeSStefan Eßer
3170252884aeSStefan Eßer BC_SIG_UNLOCK;
3171252884aeSStefan Eßer
317244d4804dSStefan Eßer // Make intp an integer.
3173252884aeSStefan Eßer bc_num_truncate(&intp, intp.scale);
3174252884aeSStefan Eßer
317544d4804dSStefan Eßer // Get the fractional part out.
3176252884aeSStefan Eßer bc_num_sub(n, &intp, &fracp1, 0);
3177252884aeSStefan Eßer
317844d4804dSStefan Eßer // If the base is not the same as the last base used for printing, we need
317944d4804dSStefan Eßer // to update the cached exponent and power. Yes, we cache the values of the
318044d4804dSStefan Eßer // exponent and power. That is to prevent us from calculating them every
318144d4804dSStefan Eßer // time because printing will probably happen multiple times on the same
318244d4804dSStefan Eßer // base.
3183d101cdd6SStefan Eßer if (base != vm->last_base)
318478bc019dSStefan Eßer {
3185d101cdd6SStefan Eßer vm->last_pow = 1;
3186d101cdd6SStefan Eßer vm->last_exp = 0;
3187252884aeSStefan Eßer
318844d4804dSStefan Eßer // Calculate the exponent and power.
3189d101cdd6SStefan Eßer while (vm->last_pow * base <= BC_BASE_POW)
319078bc019dSStefan Eßer {
3191d101cdd6SStefan Eßer vm->last_pow *= base;
3192d101cdd6SStefan Eßer vm->last_exp += 1;
3193252884aeSStefan Eßer }
3194252884aeSStefan Eßer
319544d4804dSStefan Eßer // Also, the remainder and base itself.
3196d101cdd6SStefan Eßer vm->last_rem = BC_BASE_POW - vm->last_pow;
3197d101cdd6SStefan Eßer vm->last_base = base;
3198252884aeSStefan Eßer }
3199252884aeSStefan Eßer
3200d101cdd6SStefan Eßer exp = vm->last_exp;
3201252884aeSStefan Eßer
3202d101cdd6SStefan Eßer // If vm->last_rem is 0, then the base we are printing in is a divisor of
320344d4804dSStefan Eßer // BC_BASE_POW, which is the easy case because it means that BC_BASE_POW is
320444d4804dSStefan Eßer // a power of obase, and no conversion is needed. If it *is* 0, then we have
320544d4804dSStefan Eßer // the hard case, and we have to prepare the number for the base.
3206d101cdd6SStefan Eßer if (vm->last_rem != 0)
3207d101cdd6SStefan Eßer {
3208d101cdd6SStefan Eßer bc_num_printPrepare(&intp, vm->last_rem, vm->last_pow);
3209d101cdd6SStefan Eßer }
3210252884aeSStefan Eßer
321144d4804dSStefan Eßer // After the conversion comes the surprisingly easy part. From here on out,
321244d4804dSStefan Eßer // this is basically naive code that I wrote, adjusted for the larger bases.
321344d4804dSStefan Eßer
321444d4804dSStefan Eßer // Fill the stack of digits for the integer part.
321578bc019dSStefan Eßer for (i = 0; i < intp.len; ++i)
321678bc019dSStefan Eßer {
321744d4804dSStefan Eßer // Get the limb.
3218252884aeSStefan Eßer acc = (BcBigDig) intp.num[i];
3219252884aeSStefan Eßer
322044d4804dSStefan Eßer // Turn the limb into digits of base obase.
3221252884aeSStefan Eßer for (j = 0; j < exp && (i < intp.len - 1 || acc != 0); ++j)
3222252884aeSStefan Eßer {
322344d4804dSStefan Eßer // This condition is true if we are not at the last digit.
322478bc019dSStefan Eßer if (j != exp - 1)
322578bc019dSStefan Eßer {
3226252884aeSStefan Eßer dig = acc % base;
3227252884aeSStefan Eßer acc /= base;
3228252884aeSStefan Eßer }
322978bc019dSStefan Eßer else
323078bc019dSStefan Eßer {
3231252884aeSStefan Eßer dig = acc;
3232252884aeSStefan Eßer acc = 0;
3233252884aeSStefan Eßer }
3234252884aeSStefan Eßer
3235252884aeSStefan Eßer assert(dig < base);
3236252884aeSStefan Eßer
323744d4804dSStefan Eßer // Push the digit onto the stack.
3238252884aeSStefan Eßer bc_vec_push(&stack, &dig);
3239252884aeSStefan Eßer }
3240252884aeSStefan Eßer
3241252884aeSStefan Eßer assert(acc == 0);
3242252884aeSStefan Eßer }
3243252884aeSStefan Eßer
324444d4804dSStefan Eßer // Go through the stack backwards and print each digit.
324578bc019dSStefan Eßer for (i = 0; i < stack.len; ++i)
324678bc019dSStefan Eßer {
3247252884aeSStefan Eßer ptr = bc_vec_item_rev(&stack, i);
324844d4804dSStefan Eßer
3249252884aeSStefan Eßer assert(ptr != NULL);
325044d4804dSStefan Eßer
325144d4804dSStefan Eßer // While the first three arguments should be self-explanatory, the last
3252f4fbc49dSStefan Eßer // needs explaining. I don't want to print a backslash+newline when the
3253f4fbc49dSStefan Eßer // last digit to be printed could take the place of the backslash rather
3254f4fbc49dSStefan Eßer // than being pushed, as a single character, to the next line. That's
3255f4fbc49dSStefan Eßer // what that last argument does for bc.
3256f4fbc49dSStefan Eßer //
3257f4fbc49dSStefan Eßer // First, it needs to check if newlines are completely disabled. If they
3258f4fbc49dSStefan Eßer // are not disabled, it needs to check the next part.
3259f4fbc49dSStefan Eßer //
3260f4fbc49dSStefan Eßer // If the number has a scale, then because we are printing just the
3261f4fbc49dSStefan Eßer // integer part, there will be at least two more characters (a radix
3262f4fbc49dSStefan Eßer // point plus at least one digit). So if there is a scale, a backslash
3263f4fbc49dSStefan Eßer // is necessary.
3264f4fbc49dSStefan Eßer //
3265f4fbc49dSStefan Eßer // Finally, the last condition checks to see if we are at the end of the
3266f4fbc49dSStefan Eßer // stack. If we are *not* (i.e., the index is not one less than the
3267f4fbc49dSStefan Eßer // stack length), then a backslash is necessary because there is at
3268f4fbc49dSStefan Eßer // least one more character for at least one more digit). Otherwise, if
3269f4fbc49dSStefan Eßer // the index is equal to one less than the stack length, we want to
3270f4fbc49dSStefan Eßer // disable backslash printing.
3271f4fbc49dSStefan Eßer //
3272f4fbc49dSStefan Eßer // The function that prints bases 17 and above will take care of not
3273f4fbc49dSStefan Eßer // printing a backslash in the right case.
327478bc019dSStefan Eßer print(*ptr, len, false,
3275f4fbc49dSStefan Eßer !newline || (n->scale != 0 || i < stack.len - 1));
3276252884aeSStefan Eßer }
3277252884aeSStefan Eßer
327844d4804dSStefan Eßer // We are done if there is no fractional part.
3279252884aeSStefan Eßer if (!n->scale) goto err;
3280252884aeSStefan Eßer
3281252884aeSStefan Eßer BC_SIG_LOCK;
3282252884aeSStefan Eßer
328344d4804dSStefan Eßer // Reset the jump because some locals are changing.
3284d101cdd6SStefan Eßer BC_UNSETJMP(vm);
3285252884aeSStefan Eßer
328650696a6eSStefan Eßer bc_num_init(&fracp2, nrdx);
3287252884aeSStefan Eßer bc_num_setup(&digit, digit_digs, sizeof(digit_digs) / sizeof(BcDig));
3288252884aeSStefan Eßer bc_num_init(&flen1, BC_NUM_BIGDIG_LOG10);
3289252884aeSStefan Eßer bc_num_init(&flen2, BC_NUM_BIGDIG_LOG10);
3290252884aeSStefan Eßer
3291d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, frac_err);
3292252884aeSStefan Eßer
3293252884aeSStefan Eßer BC_SIG_UNLOCK;
3294252884aeSStefan Eßer
3295252884aeSStefan Eßer bc_num_one(&flen1);
3296252884aeSStefan Eßer
3297252884aeSStefan Eßer radix = true;
329844d4804dSStefan Eßer
329944d4804dSStefan Eßer // Pointers for easy switching.
3300252884aeSStefan Eßer n1 = &flen1;
3301252884aeSStefan Eßer n2 = &flen2;
3302252884aeSStefan Eßer
3303252884aeSStefan Eßer fracp2.scale = n->scale;
330450696a6eSStefan Eßer BC_NUM_RDX_SET_NP(fracp2, BC_NUM_RDX(fracp2.scale));
3305252884aeSStefan Eßer
330644d4804dSStefan Eßer // As long as we have not reached the scale of the number, keep printing.
330778bc019dSStefan Eßer while ((idigits = bc_num_intDigits(n1)) <= n->scale)
330878bc019dSStefan Eßer {
330944d4804dSStefan Eßer // These numbers will keep growing.
3310252884aeSStefan Eßer bc_num_expand(&fracp2, fracp1.len + 1);
3311252884aeSStefan Eßer bc_num_mulArray(&fracp1, base, &fracp2);
331250696a6eSStefan Eßer
331350696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL_NP(fracp2);
331450696a6eSStefan Eßer
331544d4804dSStefan Eßer // Ensure an invariant.
331650696a6eSStefan Eßer if (fracp2.len < nrdx) fracp2.len = nrdx;
3317252884aeSStefan Eßer
3318252884aeSStefan Eßer // fracp is guaranteed to be non-negative and small enough.
331944d4804dSStefan Eßer dig = bc_num_bigdig2(&fracp2);
3320252884aeSStefan Eßer
332144d4804dSStefan Eßer // Convert the digit to a number and subtract it from the number.
3322252884aeSStefan Eßer bc_num_bigdig2num(&digit, dig);
3323252884aeSStefan Eßer bc_num_sub(&fracp2, &digit, &fracp1, 0);
3324252884aeSStefan Eßer
332544d4804dSStefan Eßer // While the first three arguments should be self-explanatory, the last
332644d4804dSStefan Eßer // needs explaining. I don't want to print a newline when the last digit
332744d4804dSStefan Eßer // to be printed could take the place of the backslash rather than being
332844d4804dSStefan Eßer // pushed, as a single character, to the next line. That's what that
332944d4804dSStefan Eßer // last argument does for bc.
333044d4804dSStefan Eßer print(dig, len, radix, !newline || idigits != n->scale);
333144d4804dSStefan Eßer
333244d4804dSStefan Eßer // Update the multipliers.
3333252884aeSStefan Eßer bc_num_mulArray(n1, base, n2);
3334252884aeSStefan Eßer
3335252884aeSStefan Eßer radix = false;
333644d4804dSStefan Eßer
333744d4804dSStefan Eßer // Switch.
3338252884aeSStefan Eßer temp = n1;
3339252884aeSStefan Eßer n1 = n2;
3340252884aeSStefan Eßer n2 = temp;
3341252884aeSStefan Eßer }
3342252884aeSStefan Eßer
3343252884aeSStefan Eßer frac_err:
3344252884aeSStefan Eßer BC_SIG_MAYLOCK;
3345252884aeSStefan Eßer bc_num_free(&flen2);
3346252884aeSStefan Eßer bc_num_free(&flen1);
3347252884aeSStefan Eßer bc_num_free(&fracp2);
3348252884aeSStefan Eßer err:
3349252884aeSStefan Eßer BC_SIG_MAYLOCK;
3350252884aeSStefan Eßer bc_num_free(&fracp1);
3351252884aeSStefan Eßer bc_num_free(&intp);
3352252884aeSStefan Eßer bc_vec_free(&stack);
3353d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
3354252884aeSStefan Eßer }
3355252884aeSStefan Eßer
335644d4804dSStefan Eßer /**
335744d4804dSStefan Eßer * Prints a number in the specified base, or rather, figures out which function
335844d4804dSStefan Eßer * to call to print the number in the specified base and calls it.
335944d4804dSStefan Eßer * @param n The number to print.
336044d4804dSStefan Eßer * @param base The base to print in.
336144d4804dSStefan Eßer * @param newline Whether to print backslash+newlines on long enough lines.
336244d4804dSStefan Eßer */
336378bc019dSStefan Eßer static void
bc_num_printBase(BcNum * restrict n,BcBigDig base,bool newline)336478bc019dSStefan Eßer bc_num_printBase(BcNum* restrict n, BcBigDig base, bool newline)
336578bc019dSStefan Eßer {
3366252884aeSStefan Eßer size_t width;
3367252884aeSStefan Eßer BcNumDigitOp print;
336850696a6eSStefan Eßer bool neg = BC_NUM_NEG(n);
3369252884aeSStefan Eßer
337044d4804dSStefan Eßer // Clear the sign because it makes the actual printing easier when we have
337144d4804dSStefan Eßer // to do math.
337250696a6eSStefan Eßer BC_NUM_NEG_CLR(n);
3373252884aeSStefan Eßer
337444d4804dSStefan Eßer // Bases at hexadecimal and below are printed as one character, larger bases
337544d4804dSStefan Eßer // are printed as a series of digits separated by spaces.
337678bc019dSStefan Eßer if (base <= BC_NUM_MAX_POSIX_IBASE)
337778bc019dSStefan Eßer {
3378252884aeSStefan Eßer width = 1;
3379252884aeSStefan Eßer print = bc_num_printHex;
3380252884aeSStefan Eßer }
338178bc019dSStefan Eßer else
338278bc019dSStefan Eßer {
3383252884aeSStefan Eßer assert(base <= BC_BASE_POW);
3384252884aeSStefan Eßer width = bc_num_log10(base - 1);
3385252884aeSStefan Eßer print = bc_num_printDigits;
3386252884aeSStefan Eßer }
3387252884aeSStefan Eßer
338844d4804dSStefan Eßer // Print.
338944d4804dSStefan Eßer bc_num_printNum(n, base, width, print, newline);
339044d4804dSStefan Eßer
339144d4804dSStefan Eßer // Reset the sign.
339250696a6eSStefan Eßer n->rdx = BC_NUM_NEG_VAL(n, neg);
3393252884aeSStefan Eßer }
3394252884aeSStefan Eßer
339544d4804dSStefan Eßer #if !BC_ENABLE_LIBRARY
339644d4804dSStefan Eßer
339778bc019dSStefan Eßer void
bc_num_stream(BcNum * restrict n)339878bc019dSStefan Eßer bc_num_stream(BcNum* restrict n)
339978bc019dSStefan Eßer {
340044d4804dSStefan Eßer bc_num_printNum(n, BC_NUM_STREAM_BASE, 1, bc_num_printChar, false);
3401252884aeSStefan Eßer }
340244d4804dSStefan Eßer
340344d4804dSStefan Eßer #endif // !BC_ENABLE_LIBRARY
3404252884aeSStefan Eßer
340578bc019dSStefan Eßer void
bc_num_setup(BcNum * restrict n,BcDig * restrict num,size_t cap)340678bc019dSStefan Eßer bc_num_setup(BcNum* restrict n, BcDig* restrict num, size_t cap)
340778bc019dSStefan Eßer {
3408252884aeSStefan Eßer assert(n != NULL);
3409252884aeSStefan Eßer n->num = num;
3410252884aeSStefan Eßer n->cap = cap;
3411252884aeSStefan Eßer bc_num_zero(n);
3412252884aeSStefan Eßer }
3413252884aeSStefan Eßer
341478bc019dSStefan Eßer void
bc_num_init(BcNum * restrict n,size_t req)341578bc019dSStefan Eßer bc_num_init(BcNum* restrict n, size_t req)
341678bc019dSStefan Eßer {
3417252884aeSStefan Eßer BcDig* num;
3418252884aeSStefan Eßer
3419252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
3420252884aeSStefan Eßer
3421252884aeSStefan Eßer assert(n != NULL);
3422252884aeSStefan Eßer
342344d4804dSStefan Eßer // BC_NUM_DEF_SIZE is set to be about the smallest allocation size that
342444d4804dSStefan Eßer // malloc() returns in practice, so just use it.
3425252884aeSStefan Eßer req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
3426252884aeSStefan Eßer
342744d4804dSStefan Eßer // If we can't use a temp, allocate.
3428d101cdd6SStefan Eßer if (req != BC_NUM_DEF_SIZE) num = bc_vm_malloc(BC_NUM_SIZE(req));
3429d101cdd6SStefan Eßer else
343078bc019dSStefan Eßer {
3431d101cdd6SStefan Eßer num = bc_vm_getTemp() == NULL ? bc_vm_malloc(BC_NUM_SIZE(req)) :
3432d101cdd6SStefan Eßer bc_vm_takeTemp();
343378bc019dSStefan Eßer }
3434252884aeSStefan Eßer
3435252884aeSStefan Eßer bc_num_setup(n, num, req);
3436252884aeSStefan Eßer }
3437252884aeSStefan Eßer
343878bc019dSStefan Eßer void
bc_num_clear(BcNum * restrict n)343978bc019dSStefan Eßer bc_num_clear(BcNum* restrict n)
344078bc019dSStefan Eßer {
3441252884aeSStefan Eßer n->num = NULL;
3442252884aeSStefan Eßer n->cap = 0;
3443252884aeSStefan Eßer }
3444252884aeSStefan Eßer
344578bc019dSStefan Eßer void
bc_num_free(void * num)344678bc019dSStefan Eßer bc_num_free(void* num)
344778bc019dSStefan Eßer {
3448252884aeSStefan Eßer BcNum* n = (BcNum*) num;
3449252884aeSStefan Eßer
3450252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
3451252884aeSStefan Eßer
3452252884aeSStefan Eßer assert(n != NULL);
3453252884aeSStefan Eßer
345444d4804dSStefan Eßer if (n->cap == BC_NUM_DEF_SIZE) bc_vm_addTemp(n->num);
3455252884aeSStefan Eßer else free(n->num);
3456252884aeSStefan Eßer }
3457252884aeSStefan Eßer
345878bc019dSStefan Eßer void
bc_num_copy(BcNum * d,const BcNum * s)345978bc019dSStefan Eßer bc_num_copy(BcNum* d, const BcNum* s)
346078bc019dSStefan Eßer {
3461252884aeSStefan Eßer assert(d != NULL && s != NULL);
346244d4804dSStefan Eßer
3463252884aeSStefan Eßer if (d == s) return;
346444d4804dSStefan Eßer
3465252884aeSStefan Eßer bc_num_expand(d, s->len);
3466252884aeSStefan Eßer d->len = s->len;
346744d4804dSStefan Eßer
346844d4804dSStefan Eßer // I can just copy directly here because the sign *and* rdx will be
346944d4804dSStefan Eßer // properly preserved.
3470252884aeSStefan Eßer d->rdx = s->rdx;
3471252884aeSStefan Eßer d->scale = s->scale;
347278bc019dSStefan Eßer // NOLINTNEXTLINE
3473252884aeSStefan Eßer memcpy(d->num, s->num, BC_NUM_SIZE(d->len));
3474252884aeSStefan Eßer }
3475252884aeSStefan Eßer
347678bc019dSStefan Eßer void
bc_num_createCopy(BcNum * d,const BcNum * s)347778bc019dSStefan Eßer bc_num_createCopy(BcNum* d, const BcNum* s)
347878bc019dSStefan Eßer {
3479252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
3480252884aeSStefan Eßer bc_num_init(d, s->len);
3481252884aeSStefan Eßer bc_num_copy(d, s);
3482252884aeSStefan Eßer }
3483252884aeSStefan Eßer
348478bc019dSStefan Eßer void
bc_num_createFromBigdig(BcNum * restrict n,BcBigDig val)348578bc019dSStefan Eßer bc_num_createFromBigdig(BcNum* restrict n, BcBigDig val)
348678bc019dSStefan Eßer {
3487252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
348850696a6eSStefan Eßer bc_num_init(n, BC_NUM_BIGDIG_LOG10);
3489252884aeSStefan Eßer bc_num_bigdig2num(n, val);
3490252884aeSStefan Eßer }
3491252884aeSStefan Eßer
349278bc019dSStefan Eßer size_t
bc_num_scale(const BcNum * restrict n)349378bc019dSStefan Eßer bc_num_scale(const BcNum* restrict n)
349478bc019dSStefan Eßer {
3495252884aeSStefan Eßer return n->scale;
3496252884aeSStefan Eßer }
3497252884aeSStefan Eßer
349878bc019dSStefan Eßer size_t
bc_num_len(const BcNum * restrict n)349978bc019dSStefan Eßer bc_num_len(const BcNum* restrict n)
350078bc019dSStefan Eßer {
3501252884aeSStefan Eßer size_t len = n->len;
3502252884aeSStefan Eßer
350344d4804dSStefan Eßer // Always return at least 1.
3504028616d0SStefan Eßer if (BC_NUM_ZERO(n)) return n->scale ? n->scale : 1;
3505252884aeSStefan Eßer
350644d4804dSStefan Eßer // If this is true, there is no integer portion of the number.
350778bc019dSStefan Eßer if (BC_NUM_RDX_VAL(n) == len)
350878bc019dSStefan Eßer {
350944d4804dSStefan Eßer // We have to take into account the fact that some of the digits right
351044d4804dSStefan Eßer // after the decimal could be zero. If that is the case, we need to
351144d4804dSStefan Eßer // ignore them until we hit the first non-zero digit.
351244d4804dSStefan Eßer
3513252884aeSStefan Eßer size_t zero, scale;
3514252884aeSStefan Eßer
351544d4804dSStefan Eßer // The number of limbs with non-zero digits.
351644d4804dSStefan Eßer len = bc_num_nonZeroLen(n);
3517252884aeSStefan Eßer
351844d4804dSStefan Eßer // Get the number of digits in the last limb.
3519252884aeSStefan Eßer scale = n->scale % BC_BASE_DIGS;
3520252884aeSStefan Eßer scale = scale ? scale : BC_BASE_DIGS;
3521252884aeSStefan Eßer
352244d4804dSStefan Eßer // Get the number of zero digits.
3523252884aeSStefan Eßer zero = bc_num_zeroDigits(n->num + len - 1);
3524252884aeSStefan Eßer
352544d4804dSStefan Eßer // Calculate the true length.
3526252884aeSStefan Eßer len = len * BC_BASE_DIGS - zero - (BC_BASE_DIGS - scale);
3527252884aeSStefan Eßer }
352844d4804dSStefan Eßer // Otherwise, count the number of int digits and return that plus the scale.
3529252884aeSStefan Eßer else len = bc_num_intDigits(n) + n->scale;
3530252884aeSStefan Eßer
3531252884aeSStefan Eßer return len;
3532252884aeSStefan Eßer }
3533252884aeSStefan Eßer
353478bc019dSStefan Eßer void
bc_num_parse(BcNum * restrict n,const char * restrict val,BcBigDig base)353578bc019dSStefan Eßer bc_num_parse(BcNum* restrict n, const char* restrict val, BcBigDig base)
353678bc019dSStefan Eßer {
3537103d7cdfSStefan Eßer #if BC_DEBUG
3538d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3539d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
3540d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3541103d7cdfSStefan Eßer #endif // BC_DEBUG
3542d101cdd6SStefan Eßer
3543252884aeSStefan Eßer assert(n != NULL && val != NULL && base);
3544d101cdd6SStefan Eßer assert(base >= BC_NUM_MIN_BASE && base <= vm->maxes[BC_PROG_GLOBALS_IBASE]);
3545252884aeSStefan Eßer assert(bc_num_strValid(val));
3546252884aeSStefan Eßer
354744d4804dSStefan Eßer // A one character number is *always* parsed as though the base was the
354844d4804dSStefan Eßer // maximum allowed ibase, per the bc spec.
354978bc019dSStefan Eßer if (!val[1])
355078bc019dSStefan Eßer {
3551252884aeSStefan Eßer BcBigDig dig = bc_num_parseChar(val[0], BC_NUM_MAX_LBASE);
3552252884aeSStefan Eßer bc_num_bigdig2num(n, dig);
3553252884aeSStefan Eßer }
3554252884aeSStefan Eßer else if (base == BC_BASE) bc_num_parseDecimal(n, val);
3555252884aeSStefan Eßer else bc_num_parseBase(n, val, base);
355650696a6eSStefan Eßer
355750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(n));
3558252884aeSStefan Eßer }
3559252884aeSStefan Eßer
356078bc019dSStefan Eßer void
bc_num_print(BcNum * restrict n,BcBigDig base,bool newline)356178bc019dSStefan Eßer bc_num_print(BcNum* restrict n, BcBigDig base, bool newline)
356278bc019dSStefan Eßer {
3563252884aeSStefan Eßer assert(n != NULL);
3564252884aeSStefan Eßer assert(BC_ENABLE_EXTRA_MATH || base >= BC_NUM_MIN_BASE);
3565252884aeSStefan Eßer
356644d4804dSStefan Eßer // We may need a newline, just to start.
3567252884aeSStefan Eßer bc_num_printNewline();
3568252884aeSStefan Eßer
356978bc019dSStefan Eßer if (BC_NUM_NONZERO(n))
357078bc019dSStefan Eßer {
3571d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3572d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
3573d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3574d101cdd6SStefan Eßer
3575d43fa8efSStefan Eßer // Print the sign.
3576d43fa8efSStefan Eßer if (BC_NUM_NEG(n)) bc_num_putchar('-', true);
3577d43fa8efSStefan Eßer
357876238846SStefan Eßer // Print the leading zero if necessary. We don't print when using
357976238846SStefan Eßer // scientific or engineering modes.
358076238846SStefan Eßer if (BC_Z && BC_NUM_RDX_VAL(n) == n->len && base != 0 && base != 1)
358178bc019dSStefan Eßer {
3582d43fa8efSStefan Eßer bc_num_printHex(0, 1, false, !newline);
3583d43fa8efSStefan Eßer }
358478bc019dSStefan Eßer }
3585d43fa8efSStefan Eßer
358644d4804dSStefan Eßer // Short-circuit 0.
358744d4804dSStefan Eßer if (BC_NUM_ZERO(n)) bc_num_printHex(0, 1, false, !newline);
358844d4804dSStefan Eßer else if (base == BC_BASE) bc_num_printDecimal(n, newline);
3589252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
359044d4804dSStefan Eßer else if (base == 0 || base == 1)
359178bc019dSStefan Eßer {
359244d4804dSStefan Eßer bc_num_printExponent(n, base != 0, newline);
359378bc019dSStefan Eßer }
3594252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
359544d4804dSStefan Eßer else bc_num_printBase(n, base, newline);
3596252884aeSStefan Eßer
359744d4804dSStefan Eßer if (newline) bc_num_putchar('\n', false);
3598252884aeSStefan Eßer }
3599252884aeSStefan Eßer
360078bc019dSStefan Eßer BcBigDig
bc_num_bigdig2(const BcNum * restrict n)360178bc019dSStefan Eßer bc_num_bigdig2(const BcNum* restrict n)
360278bc019dSStefan Eßer {
3603103d7cdfSStefan Eßer #if BC_DEBUG
3604d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3605d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
3606d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3607103d7cdfSStefan Eßer #endif // BC_DEBUG
3608d101cdd6SStefan Eßer
3609252884aeSStefan Eßer // This function returns no errors because it's guaranteed to succeed if
361044d4804dSStefan Eßer // its preconditions are met. Those preconditions include both n needs to
3611d101cdd6SStefan Eßer // be non-NULL, n being non-negative, and n being less than vm->max. If all
361244d4804dSStefan Eßer // of that is true, then we can just convert without worrying about negative
361344d4804dSStefan Eßer // errors or overflow.
3614252884aeSStefan Eßer
3615252884aeSStefan Eßer BcBigDig r = 0;
361650696a6eSStefan Eßer size_t nrdx = BC_NUM_RDX_VAL(n);
3617252884aeSStefan Eßer
361844d4804dSStefan Eßer assert(n != NULL);
361950696a6eSStefan Eßer assert(!BC_NUM_NEG(n));
3620d101cdd6SStefan Eßer assert(bc_num_cmp(n, &vm->max) < 0);
362150696a6eSStefan Eßer assert(n->len - nrdx <= 3);
3622252884aeSStefan Eßer
3623252884aeSStefan Eßer // There is a small speed win from unrolling the loop here, and since it
3624252884aeSStefan Eßer // only adds 53 bytes, I decided that it was worth it.
362578bc019dSStefan Eßer switch (n->len - nrdx)
362678bc019dSStefan Eßer {
3627252884aeSStefan Eßer case 3:
362850696a6eSStefan Eßer {
362950696a6eSStefan Eßer r = (BcBigDig) n->num[nrdx + 2];
363078bc019dSStefan Eßer
3631252884aeSStefan Eßer // Fallthrough.
363250696a6eSStefan Eßer BC_FALLTHROUGH
363378bc019dSStefan Eßer }
363450696a6eSStefan Eßer
3635252884aeSStefan Eßer case 2:
363650696a6eSStefan Eßer {
363750696a6eSStefan Eßer r = r * BC_BASE_POW + (BcBigDig) n->num[nrdx + 1];
363878bc019dSStefan Eßer
3639252884aeSStefan Eßer // Fallthrough.
364050696a6eSStefan Eßer BC_FALLTHROUGH
364178bc019dSStefan Eßer }
364250696a6eSStefan Eßer
3643252884aeSStefan Eßer case 1:
364450696a6eSStefan Eßer {
364550696a6eSStefan Eßer r = r * BC_BASE_POW + (BcBigDig) n->num[nrdx];
364650696a6eSStefan Eßer }
3647252884aeSStefan Eßer }
3648252884aeSStefan Eßer
364944d4804dSStefan Eßer return r;
3650252884aeSStefan Eßer }
3651252884aeSStefan Eßer
365278bc019dSStefan Eßer BcBigDig
bc_num_bigdig(const BcNum * restrict n)365378bc019dSStefan Eßer bc_num_bigdig(const BcNum* restrict n)
365478bc019dSStefan Eßer {
3655d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3656d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
3657d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3658d101cdd6SStefan Eßer
365944d4804dSStefan Eßer assert(n != NULL);
3660252884aeSStefan Eßer
366144d4804dSStefan Eßer // This error checking is extremely important, and if you do not have a
366244d4804dSStefan Eßer // guarantee that converting a number will always succeed in a particular
366344d4804dSStefan Eßer // case, you *must* call this function to get these error checks. This
366444d4804dSStefan Eßer // includes all instances of numbers inputted by the user or calculated by
366544d4804dSStefan Eßer // the user. Otherwise, you can call the faster bc_num_bigdig2().
366644d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(n))) bc_err(BC_ERR_MATH_NEGATIVE);
3667d101cdd6SStefan Eßer if (BC_ERR(bc_num_cmp(n, &vm->max) >= 0)) bc_err(BC_ERR_MATH_OVERFLOW);
3668252884aeSStefan Eßer
366944d4804dSStefan Eßer return bc_num_bigdig2(n);
3670252884aeSStefan Eßer }
3671252884aeSStefan Eßer
367278bc019dSStefan Eßer void
bc_num_bigdig2num(BcNum * restrict n,BcBigDig val)367378bc019dSStefan Eßer bc_num_bigdig2num(BcNum* restrict n, BcBigDig val)
367478bc019dSStefan Eßer {
3675252884aeSStefan Eßer BcDig* ptr;
3676252884aeSStefan Eßer size_t i;
3677252884aeSStefan Eßer
3678252884aeSStefan Eßer assert(n != NULL);
3679252884aeSStefan Eßer
3680252884aeSStefan Eßer bc_num_zero(n);
3681252884aeSStefan Eßer
368244d4804dSStefan Eßer // Already 0.
3683252884aeSStefan Eßer if (!val) return;
3684252884aeSStefan Eßer
368544d4804dSStefan Eßer // Expand first. This is the only way this function can fail, and it's a
368644d4804dSStefan Eßer // fatal error.
3687252884aeSStefan Eßer bc_num_expand(n, BC_NUM_BIGDIG_LOG10);
3688252884aeSStefan Eßer
368944d4804dSStefan Eßer // The conversion is easy because numbers are laid out in little-endian
369044d4804dSStefan Eßer // order.
3691252884aeSStefan Eßer for (ptr = n->num, i = 0; val; ++i, val /= BC_BASE_POW)
369278bc019dSStefan Eßer {
3693252884aeSStefan Eßer ptr[i] = val % BC_BASE_POW;
369478bc019dSStefan Eßer }
3695252884aeSStefan Eßer
3696252884aeSStefan Eßer n->len = i;
3697252884aeSStefan Eßer }
3698252884aeSStefan Eßer
369944d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
370044d4804dSStefan Eßer
370178bc019dSStefan Eßer void
bc_num_rng(const BcNum * restrict n,BcRNG * rng)370278bc019dSStefan Eßer bc_num_rng(const BcNum* restrict n, BcRNG* rng)
370378bc019dSStefan Eßer {
370450696a6eSStefan Eßer BcNum temp, temp2, intn, frac;
3705252884aeSStefan Eßer BcRand state1, state2, inc1, inc2;
370650696a6eSStefan Eßer size_t nrdx = BC_NUM_RDX_VAL(n);
3707d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3708d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
3709d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3710252884aeSStefan Eßer
371144d4804dSStefan Eßer // This function holds the secret of how I interpret a seed number for the
371244d4804dSStefan Eßer // PRNG. Well, it's actually in the development manual
371344d4804dSStefan Eßer // (manuals/development.md#pseudo-random-number-generator), so look there
371444d4804dSStefan Eßer // before you try to understand this.
371544d4804dSStefan Eßer
3716252884aeSStefan Eßer BC_SIG_LOCK;
3717252884aeSStefan Eßer
3718252884aeSStefan Eßer bc_num_init(&temp, n->len);
3719252884aeSStefan Eßer bc_num_init(&temp2, n->len);
372050696a6eSStefan Eßer bc_num_init(&frac, nrdx);
3721252884aeSStefan Eßer bc_num_init(&intn, bc_num_int(n));
3722252884aeSStefan Eßer
3723d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
3724252884aeSStefan Eßer
3725252884aeSStefan Eßer BC_SIG_UNLOCK;
3726252884aeSStefan Eßer
3727d101cdd6SStefan Eßer assert(BC_NUM_RDX_VALID_NP(vm->max));
3728252884aeSStefan Eßer
372978bc019dSStefan Eßer // NOLINTNEXTLINE
373050696a6eSStefan Eßer memcpy(frac.num, n->num, BC_NUM_SIZE(nrdx));
373150696a6eSStefan Eßer frac.len = nrdx;
373250696a6eSStefan Eßer BC_NUM_RDX_SET_NP(frac, nrdx);
3733252884aeSStefan Eßer frac.scale = n->scale;
3734252884aeSStefan Eßer
373550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(frac));
3736d101cdd6SStefan Eßer assert(BC_NUM_RDX_VALID_NP(vm->max2));
373750696a6eSStefan Eßer
373844d4804dSStefan Eßer // Multiply the fraction and truncate so that it's an integer. The
373944d4804dSStefan Eßer // truncation is what clamps it, by the way.
3740d101cdd6SStefan Eßer bc_num_mul(&frac, &vm->max2, &temp, 0);
3741252884aeSStefan Eßer bc_num_truncate(&temp, temp.scale);
3742252884aeSStefan Eßer bc_num_copy(&frac, &temp);
3743252884aeSStefan Eßer
374444d4804dSStefan Eßer // Get the integer.
374578bc019dSStefan Eßer // NOLINTNEXTLINE
374650696a6eSStefan Eßer memcpy(intn.num, n->num + nrdx, BC_NUM_SIZE(bc_num_int(n)));
3747252884aeSStefan Eßer intn.len = bc_num_int(n);
3748252884aeSStefan Eßer
3749252884aeSStefan Eßer // This assert is here because it has to be true. It is also here to justify
375044d4804dSStefan Eßer // some optimizations.
3751d101cdd6SStefan Eßer assert(BC_NUM_NONZERO(&vm->max));
3752252884aeSStefan Eßer
375344d4804dSStefan Eßer // If there *was* a fractional part...
375478bc019dSStefan Eßer if (BC_NUM_NONZERO(&frac))
375578bc019dSStefan Eßer {
375644d4804dSStefan Eßer // This divmod splits frac into the two state parts.
3757d101cdd6SStefan Eßer bc_num_divmod(&frac, &vm->max, &temp, &temp2, 0);
3758252884aeSStefan Eßer
3759d101cdd6SStefan Eßer // frac is guaranteed to be smaller than vm->max * vm->max (pow).
3760d101cdd6SStefan Eßer // This means that when dividing frac by vm->max, as above, the
3761d101cdd6SStefan Eßer // quotient and remainder are both guaranteed to be less than vm->max,
3762252884aeSStefan Eßer // which means we can use bc_num_bigdig2() here and not worry about
3763252884aeSStefan Eßer // overflow.
376444d4804dSStefan Eßer state1 = (BcRand) bc_num_bigdig2(&temp2);
376544d4804dSStefan Eßer state2 = (BcRand) bc_num_bigdig2(&temp);
3766252884aeSStefan Eßer }
3767252884aeSStefan Eßer else state1 = state2 = 0;
3768252884aeSStefan Eßer
376944d4804dSStefan Eßer // If there *was* an integer part...
377078bc019dSStefan Eßer if (BC_NUM_NONZERO(&intn))
377178bc019dSStefan Eßer {
377244d4804dSStefan Eßer // This divmod splits intn into the two inc parts.
3773d101cdd6SStefan Eßer bc_num_divmod(&intn, &vm->max, &temp, &temp2, 0);
3774252884aeSStefan Eßer
3775d101cdd6SStefan Eßer // Because temp2 is the mod of vm->max, from above, it is guaranteed
3776252884aeSStefan Eßer // to be small enough to use bc_num_bigdig2().
377744d4804dSStefan Eßer inc1 = (BcRand) bc_num_bigdig2(&temp2);
3778252884aeSStefan Eßer
377944d4804dSStefan Eßer // Clamp the second inc part.
3780d101cdd6SStefan Eßer if (bc_num_cmp(&temp, &vm->max) >= 0)
378178bc019dSStefan Eßer {
3782252884aeSStefan Eßer bc_num_copy(&temp2, &temp);
3783d101cdd6SStefan Eßer bc_num_mod(&temp2, &vm->max, &temp, 0);
3784252884aeSStefan Eßer }
3785252884aeSStefan Eßer
3786d101cdd6SStefan Eßer // The if statement above ensures that temp is less than vm->max, which
3787252884aeSStefan Eßer // means that we can use bc_num_bigdig2() here.
378844d4804dSStefan Eßer inc2 = (BcRand) bc_num_bigdig2(&temp);
3789252884aeSStefan Eßer }
3790252884aeSStefan Eßer else inc1 = inc2 = 0;
3791252884aeSStefan Eßer
3792252884aeSStefan Eßer bc_rand_seed(rng, state1, state2, inc1, inc2);
3793252884aeSStefan Eßer
3794252884aeSStefan Eßer err:
3795252884aeSStefan Eßer BC_SIG_MAYLOCK;
3796252884aeSStefan Eßer bc_num_free(&intn);
3797252884aeSStefan Eßer bc_num_free(&frac);
3798252884aeSStefan Eßer bc_num_free(&temp2);
3799252884aeSStefan Eßer bc_num_free(&temp);
3800d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
3801252884aeSStefan Eßer }
3802252884aeSStefan Eßer
380378bc019dSStefan Eßer void
bc_num_createFromRNG(BcNum * restrict n,BcRNG * rng)380478bc019dSStefan Eßer bc_num_createFromRNG(BcNum* restrict n, BcRNG* rng)
380578bc019dSStefan Eßer {
3806252884aeSStefan Eßer BcRand s1, s2, i1, i2;
380750696a6eSStefan Eßer BcNum conv, temp1, temp2, temp3;
3808252884aeSStefan Eßer BcDig temp1_num[BC_RAND_NUM_SIZE], temp2_num[BC_RAND_NUM_SIZE];
3809252884aeSStefan Eßer BcDig conv_num[BC_NUM_BIGDIG_LOG10];
3810d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
3811d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
3812d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
3813252884aeSStefan Eßer
3814252884aeSStefan Eßer BC_SIG_LOCK;
3815252884aeSStefan Eßer
3816252884aeSStefan Eßer bc_num_init(&temp3, 2 * BC_RAND_NUM_SIZE);
3817252884aeSStefan Eßer
3818d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
3819252884aeSStefan Eßer
3820252884aeSStefan Eßer BC_SIG_UNLOCK;
3821252884aeSStefan Eßer
3822252884aeSStefan Eßer bc_num_setup(&temp1, temp1_num, sizeof(temp1_num) / sizeof(BcDig));
3823252884aeSStefan Eßer bc_num_setup(&temp2, temp2_num, sizeof(temp2_num) / sizeof(BcDig));
3824252884aeSStefan Eßer bc_num_setup(&conv, conv_num, sizeof(conv_num) / sizeof(BcDig));
3825252884aeSStefan Eßer
3826252884aeSStefan Eßer // This assert is here because it has to be true. It is also here to justify
3827d101cdd6SStefan Eßer // the assumption that vm->max is not zero.
3828d101cdd6SStefan Eßer assert(BC_NUM_NONZERO(&vm->max));
3829252884aeSStefan Eßer
383044d4804dSStefan Eßer // Because this is true, we can just ignore math errors that would happen
383144d4804dSStefan Eßer // otherwise.
3832d101cdd6SStefan Eßer assert(BC_NUM_NONZERO(&vm->max2));
3833252884aeSStefan Eßer
3834252884aeSStefan Eßer bc_rand_getRands(rng, &s1, &s2, &i1, &i2);
3835252884aeSStefan Eßer
383644d4804dSStefan Eßer // Put the second piece of state into a number.
3837252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) s2);
3838252884aeSStefan Eßer
383950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(conv));
384050696a6eSStefan Eßer
384144d4804dSStefan Eßer // Multiply by max to make room for the first piece of state.
3842d101cdd6SStefan Eßer bc_num_mul(&conv, &vm->max, &temp1, 0);
3843252884aeSStefan Eßer
384444d4804dSStefan Eßer // Add in the first piece of state.
3845252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) s1);
3846252884aeSStefan Eßer bc_num_add(&conv, &temp1, &temp2, 0);
3847252884aeSStefan Eßer
384844d4804dSStefan Eßer // Divide to make it an entirely fractional part.
3849d101cdd6SStefan Eßer bc_num_div(&temp2, &vm->max2, &temp3, BC_RAND_STATE_BITS);
3850252884aeSStefan Eßer
385144d4804dSStefan Eßer // Now start on the increment parts. It's the same process without the
385244d4804dSStefan Eßer // divide, so put the second piece of increment into a number.
3853252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) i2);
3854252884aeSStefan Eßer
385550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(conv));
385650696a6eSStefan Eßer
385744d4804dSStefan Eßer // Multiply by max to make room for the first piece of increment.
3858d101cdd6SStefan Eßer bc_num_mul(&conv, &vm->max, &temp1, 0);
3859252884aeSStefan Eßer
386044d4804dSStefan Eßer // Add in the first piece of increment.
3861252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) i1);
3862252884aeSStefan Eßer bc_num_add(&conv, &temp1, &temp2, 0);
3863252884aeSStefan Eßer
386444d4804dSStefan Eßer // Now add the two together.
3865252884aeSStefan Eßer bc_num_add(&temp2, &temp3, n, 0);
3866252884aeSStefan Eßer
386750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(n));
386850696a6eSStefan Eßer
3869252884aeSStefan Eßer err:
3870252884aeSStefan Eßer BC_SIG_MAYLOCK;
3871252884aeSStefan Eßer bc_num_free(&temp3);
3872d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
3873252884aeSStefan Eßer }
3874252884aeSStefan Eßer
387578bc019dSStefan Eßer void
bc_num_irand(BcNum * restrict a,BcNum * restrict b,BcRNG * restrict rng)387678bc019dSStefan Eßer bc_num_irand(BcNum* restrict a, BcNum* restrict b, BcRNG* restrict rng)
387778bc019dSStefan Eßer {
387844d4804dSStefan Eßer BcNum atemp;
387976238846SStefan Eßer size_t i;
3880252884aeSStefan Eßer
3881252884aeSStefan Eßer assert(a != b);
3882252884aeSStefan Eßer
388344d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(a))) bc_err(BC_ERR_MATH_NEGATIVE);
388444d4804dSStefan Eßer
388544d4804dSStefan Eßer // If either of these are true, then the numbers are integers.
3886252884aeSStefan Eßer if (BC_NUM_ZERO(a) || BC_NUM_ONE(a)) return;
3887252884aeSStefan Eßer
3888d101cdd6SStefan Eßer #if BC_GCC
3889d101cdd6SStefan Eßer // This is here in GCC to quiet the "maybe-uninitialized" warning.
3890d101cdd6SStefan Eßer atemp.num = NULL;
3891d101cdd6SStefan Eßer atemp.len = 0;
3892d101cdd6SStefan Eßer #endif // BC_GCC
3893d101cdd6SStefan Eßer
389444d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(a, &atemp))) bc_err(BC_ERR_MATH_NON_INTEGER);
3895252884aeSStefan Eßer
3896d101cdd6SStefan Eßer assert(atemp.num != NULL);
389744d4804dSStefan Eßer assert(atemp.len);
3898252884aeSStefan Eßer
389976238846SStefan Eßer if (atemp.len > 2)
390076238846SStefan Eßer {
390176238846SStefan Eßer size_t len;
390276238846SStefan Eßer
390376238846SStefan Eßer len = atemp.len - 2;
3904252884aeSStefan Eßer
390544d4804dSStefan Eßer // Just generate a random number for each limb.
390676238846SStefan Eßer for (i = 0; i < len; i += 2)
390778bc019dSStefan Eßer {
390876238846SStefan Eßer BcRand dig;
390976238846SStefan Eßer
391076238846SStefan Eßer dig = bc_rand_bounded(rng, BC_BASE_RAND_POW);
391176238846SStefan Eßer
391276238846SStefan Eßer b->num[i] = (BcDig) (dig % BC_BASE_POW);
391376238846SStefan Eßer b->num[i + 1] = (BcDig) (dig / BC_BASE_POW);
391476238846SStefan Eßer }
391576238846SStefan Eßer }
391676238846SStefan Eßer else
391776238846SStefan Eßer {
391876238846SStefan Eßer // We need this set.
391976238846SStefan Eßer i = 0;
392078bc019dSStefan Eßer }
3921252884aeSStefan Eßer
392276238846SStefan Eßer // This will be true if there's one full limb after the two limb groups.
392376238846SStefan Eßer if (i == atemp.len - 2)
392476238846SStefan Eßer {
392576238846SStefan Eßer // Increment this for easy use.
392676238846SStefan Eßer i += 1;
392776238846SStefan Eßer
392876238846SStefan Eßer // If the last digit is not one, we need to set a bound for it
392976238846SStefan Eßer // explicitly. Since there's still an empty limb, we need to fill that.
393076238846SStefan Eßer if (atemp.num[i] != 1)
393176238846SStefan Eßer {
393276238846SStefan Eßer BcRand dig;
393376238846SStefan Eßer BcRand bound;
393476238846SStefan Eßer
393576238846SStefan Eßer // Set the bound to the bound of the last limb times the amount
393676238846SStefan Eßer // needed to fill the second-to-last limb as well.
393776238846SStefan Eßer bound = ((BcRand) atemp.num[i]) * BC_BASE_POW;
393876238846SStefan Eßer
393976238846SStefan Eßer dig = bc_rand_bounded(rng, bound);
394076238846SStefan Eßer
394176238846SStefan Eßer // Fill the last two.
394276238846SStefan Eßer b->num[i - 1] = (BcDig) (dig % BC_BASE_POW);
394376238846SStefan Eßer b->num[i] = (BcDig) (dig / BC_BASE_POW);
394476238846SStefan Eßer
394576238846SStefan Eßer // Ensure that the length will be correct. If the last limb is zero,
394676238846SStefan Eßer // then the length needs to be one less than the bound.
394776238846SStefan Eßer b->len = atemp.len - (b->num[i] == 0);
394876238846SStefan Eßer }
394976238846SStefan Eßer // Here the last limb *is* one, which means the last limb does *not*
395076238846SStefan Eßer // need to be filled. Also, the length needs to be one less because the
395176238846SStefan Eßer // last limb is 0.
395276238846SStefan Eßer else
395376238846SStefan Eßer {
395476238846SStefan Eßer b->num[i - 1] = (BcDig) bc_rand_bounded(rng, BC_BASE_POW);
395576238846SStefan Eßer b->len = atemp.len - 1;
395676238846SStefan Eßer }
395776238846SStefan Eßer }
395876238846SStefan Eßer // Here, there is only one limb to fill.
395976238846SStefan Eßer else
396076238846SStefan Eßer {
396176238846SStefan Eßer // See above for how this works.
396278bc019dSStefan Eßer if (atemp.num[i] != 1)
396378bc019dSStefan Eßer {
396444d4804dSStefan Eßer b->num[i] = (BcDig) bc_rand_bounded(rng, (BcRand) atemp.num[i]);
396576238846SStefan Eßer b->len = atemp.len - (b->num[i] == 0);
3966252884aeSStefan Eßer }
396776238846SStefan Eßer else b->len = atemp.len - 1;
396876238846SStefan Eßer }
3969252884aeSStefan Eßer
3970252884aeSStefan Eßer bc_num_clean(b);
3971252884aeSStefan Eßer
397250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
3973252884aeSStefan Eßer }
397444d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
3975252884aeSStefan Eßer
397678bc019dSStefan Eßer size_t
bc_num_addReq(const BcNum * a,const BcNum * b,size_t scale)397778bc019dSStefan Eßer bc_num_addReq(const BcNum* a, const BcNum* b, size_t scale)
397878bc019dSStefan Eßer {
3979252884aeSStefan Eßer size_t aint, bint, ardx, brdx;
3980252884aeSStefan Eßer
398144d4804dSStefan Eßer // Addition and subtraction require the max of the length of the two numbers
398244d4804dSStefan Eßer // plus 1.
398344d4804dSStefan Eßer
3984252884aeSStefan Eßer BC_UNUSED(scale);
3985252884aeSStefan Eßer
398650696a6eSStefan Eßer ardx = BC_NUM_RDX_VAL(a);
3987252884aeSStefan Eßer aint = bc_num_int(a);
3988252884aeSStefan Eßer assert(aint <= a->len && ardx <= a->len);
3989252884aeSStefan Eßer
399050696a6eSStefan Eßer brdx = BC_NUM_RDX_VAL(b);
3991252884aeSStefan Eßer bint = bc_num_int(b);
3992252884aeSStefan Eßer assert(bint <= b->len && brdx <= b->len);
3993252884aeSStefan Eßer
3994252884aeSStefan Eßer ardx = BC_MAX(ardx, brdx);
3995252884aeSStefan Eßer aint = BC_MAX(aint, bint);
3996252884aeSStefan Eßer
3997252884aeSStefan Eßer return bc_vm_growSize(bc_vm_growSize(ardx, aint), 1);
3998252884aeSStefan Eßer }
3999252884aeSStefan Eßer
400078bc019dSStefan Eßer size_t
bc_num_mulReq(const BcNum * a,const BcNum * b,size_t scale)400178bc019dSStefan Eßer bc_num_mulReq(const BcNum* a, const BcNum* b, size_t scale)
400278bc019dSStefan Eßer {
4003252884aeSStefan Eßer size_t max, rdx;
400444d4804dSStefan Eßer
400544d4804dSStefan Eßer // Multiplication requires the sum of the lengths of the numbers.
400644d4804dSStefan Eßer
400750696a6eSStefan Eßer rdx = bc_vm_growSize(BC_NUM_RDX_VAL(a), BC_NUM_RDX_VAL(b));
400844d4804dSStefan Eßer
4009252884aeSStefan Eßer max = BC_NUM_RDX(scale);
401044d4804dSStefan Eßer
4011252884aeSStefan Eßer max = bc_vm_growSize(BC_MAX(max, rdx), 1);
4012252884aeSStefan Eßer rdx = bc_vm_growSize(bc_vm_growSize(bc_num_int(a), bc_num_int(b)), max);
401344d4804dSStefan Eßer
4014252884aeSStefan Eßer return rdx;
4015252884aeSStefan Eßer }
4016252884aeSStefan Eßer
401778bc019dSStefan Eßer size_t
bc_num_divReq(const BcNum * a,const BcNum * b,size_t scale)401878bc019dSStefan Eßer bc_num_divReq(const BcNum* a, const BcNum* b, size_t scale)
401978bc019dSStefan Eßer {
402050696a6eSStefan Eßer size_t max, rdx;
402144d4804dSStefan Eßer
402244d4804dSStefan Eßer // Division requires the length of the dividend plus the scale.
402344d4804dSStefan Eßer
402450696a6eSStefan Eßer rdx = bc_vm_growSize(BC_NUM_RDX_VAL(a), BC_NUM_RDX_VAL(b));
402544d4804dSStefan Eßer
402650696a6eSStefan Eßer max = BC_NUM_RDX(scale);
402744d4804dSStefan Eßer
402850696a6eSStefan Eßer max = bc_vm_growSize(BC_MAX(max, rdx), 1);
402950696a6eSStefan Eßer rdx = bc_vm_growSize(bc_num_int(a), max);
403044d4804dSStefan Eßer
403150696a6eSStefan Eßer return rdx;
403250696a6eSStefan Eßer }
403350696a6eSStefan Eßer
403478bc019dSStefan Eßer size_t
bc_num_powReq(const BcNum * a,const BcNum * b,size_t scale)403578bc019dSStefan Eßer bc_num_powReq(const BcNum* a, const BcNum* b, size_t scale)
403678bc019dSStefan Eßer {
4037252884aeSStefan Eßer BC_UNUSED(scale);
4038252884aeSStefan Eßer return bc_vm_growSize(bc_vm_growSize(a->len, b->len), 1);
4039252884aeSStefan Eßer }
4040252884aeSStefan Eßer
4041252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
404278bc019dSStefan Eßer size_t
bc_num_placesReq(const BcNum * a,const BcNum * b,size_t scale)404378bc019dSStefan Eßer bc_num_placesReq(const BcNum* a, const BcNum* b, size_t scale)
404478bc019dSStefan Eßer {
4045252884aeSStefan Eßer BC_UNUSED(scale);
404650696a6eSStefan Eßer return a->len + b->len - BC_NUM_RDX_VAL(a) - BC_NUM_RDX_VAL(b);
4047252884aeSStefan Eßer }
4048252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
4049252884aeSStefan Eßer
405078bc019dSStefan Eßer void
bc_num_add(BcNum * a,BcNum * b,BcNum * c,size_t scale)405178bc019dSStefan Eßer bc_num_add(BcNum* a, BcNum* b, BcNum* c, size_t scale)
405278bc019dSStefan Eßer {
405350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
405450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
4055252884aeSStefan Eßer bc_num_binary(a, b, c, false, bc_num_as, bc_num_addReq(a, b, scale));
4056252884aeSStefan Eßer }
4057252884aeSStefan Eßer
405878bc019dSStefan Eßer void
bc_num_sub(BcNum * a,BcNum * b,BcNum * c,size_t scale)405978bc019dSStefan Eßer bc_num_sub(BcNum* a, BcNum* b, BcNum* c, size_t scale)
406078bc019dSStefan Eßer {
406150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
406250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
4063252884aeSStefan Eßer bc_num_binary(a, b, c, true, bc_num_as, bc_num_addReq(a, b, scale));
4064252884aeSStefan Eßer }
4065252884aeSStefan Eßer
406678bc019dSStefan Eßer void
bc_num_mul(BcNum * a,BcNum * b,BcNum * c,size_t scale)406778bc019dSStefan Eßer bc_num_mul(BcNum* a, BcNum* b, BcNum* c, size_t scale)
406878bc019dSStefan Eßer {
406950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
407050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
4071252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_m, bc_num_mulReq(a, b, scale));
4072252884aeSStefan Eßer }
4073252884aeSStefan Eßer
407478bc019dSStefan Eßer void
bc_num_div(BcNum * a,BcNum * b,BcNum * c,size_t scale)407578bc019dSStefan Eßer bc_num_div(BcNum* a, BcNum* b, BcNum* c, size_t scale)
407678bc019dSStefan Eßer {
407750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
407850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
407950696a6eSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_d, bc_num_divReq(a, b, scale));
4080252884aeSStefan Eßer }
4081252884aeSStefan Eßer
408278bc019dSStefan Eßer void
bc_num_mod(BcNum * a,BcNum * b,BcNum * c,size_t scale)408378bc019dSStefan Eßer bc_num_mod(BcNum* a, BcNum* b, BcNum* c, size_t scale)
408478bc019dSStefan Eßer {
408550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
408650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
408750696a6eSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_rem, bc_num_divReq(a, b, scale));
4088252884aeSStefan Eßer }
4089252884aeSStefan Eßer
409078bc019dSStefan Eßer void
bc_num_pow(BcNum * a,BcNum * b,BcNum * c,size_t scale)409178bc019dSStefan Eßer bc_num_pow(BcNum* a, BcNum* b, BcNum* c, size_t scale)
409278bc019dSStefan Eßer {
409350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
409450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
4095252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_p, bc_num_powReq(a, b, scale));
4096252884aeSStefan Eßer }
4097252884aeSStefan Eßer
4098252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
409978bc019dSStefan Eßer void
bc_num_places(BcNum * a,BcNum * b,BcNum * c,size_t scale)410078bc019dSStefan Eßer bc_num_places(BcNum* a, BcNum* b, BcNum* c, size_t scale)
410178bc019dSStefan Eßer {
410250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
410350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
4104252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_place, bc_num_placesReq(a, b, scale));
4105252884aeSStefan Eßer }
4106252884aeSStefan Eßer
410778bc019dSStefan Eßer void
bc_num_lshift(BcNum * a,BcNum * b,BcNum * c,size_t scale)410878bc019dSStefan Eßer bc_num_lshift(BcNum* a, BcNum* b, BcNum* c, size_t scale)
410978bc019dSStefan Eßer {
411050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
411150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
4112252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_left, bc_num_placesReq(a, b, scale));
4113252884aeSStefan Eßer }
4114252884aeSStefan Eßer
411578bc019dSStefan Eßer void
bc_num_rshift(BcNum * a,BcNum * b,BcNum * c,size_t scale)411678bc019dSStefan Eßer bc_num_rshift(BcNum* a, BcNum* b, BcNum* c, size_t scale)
411778bc019dSStefan Eßer {
411850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a));
411950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
4120252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_right, bc_num_placesReq(a, b, scale));
4121252884aeSStefan Eßer }
4122252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
4123252884aeSStefan Eßer
412478bc019dSStefan Eßer void
bc_num_sqrt(BcNum * restrict a,BcNum * restrict b,size_t scale)412578bc019dSStefan Eßer bc_num_sqrt(BcNum* restrict a, BcNum* restrict b, size_t scale)
412678bc019dSStefan Eßer {
412778bc019dSStefan Eßer BcNum num1, num2, half, f, fprime;
412878bc019dSStefan Eßer BcNum* x0;
412978bc019dSStefan Eßer BcNum* x1;
413078bc019dSStefan Eßer BcNum* temp;
4131d101cdd6SStefan Eßer // realscale is meant to quiet a warning on GCC about longjmp() clobbering.
4132d101cdd6SStefan Eßer // This one is real.
4133d101cdd6SStefan Eßer size_t pow, len, rdx, req, resscale, realscale;
4134252884aeSStefan Eßer BcDig half_digs[1];
4135d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
4136d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
4137d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
4138252884aeSStefan Eßer
4139252884aeSStefan Eßer assert(a != NULL && b != NULL && a != b);
4140252884aeSStefan Eßer
414144d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(a))) bc_err(BC_ERR_MATH_NEGATIVE);
4142252884aeSStefan Eßer
414344d4804dSStefan Eßer // We want to calculate to a's scale if it is bigger so that the result will
414444d4804dSStefan Eßer // truncate properly.
4145d101cdd6SStefan Eßer if (a->scale > scale) realscale = a->scale;
4146d101cdd6SStefan Eßer else realscale = scale;
4147252884aeSStefan Eßer
414844d4804dSStefan Eßer // Set parameters for the result.
4149252884aeSStefan Eßer len = bc_vm_growSize(bc_num_intDigits(a), 1);
4150d101cdd6SStefan Eßer rdx = BC_NUM_RDX(realscale);
415144d4804dSStefan Eßer
415244d4804dSStefan Eßer // Square root needs half of the length of the parameter.
415350696a6eSStefan Eßer req = bc_vm_growSize(BC_MAX(rdx, BC_NUM_RDX_VAL(a)), len >> 1);
4154f4fbc49dSStefan Eßer req = bc_vm_growSize(req, 1);
4155252884aeSStefan Eßer
4156252884aeSStefan Eßer BC_SIG_LOCK;
4157252884aeSStefan Eßer
415844d4804dSStefan Eßer // Unlike the binary operators, this function is the only single parameter
415944d4804dSStefan Eßer // function and is expected to initialize the result. This means that it
416044d4804dSStefan Eßer // expects that b is *NOT* preallocated. We allocate it here.
4161f4fbc49dSStefan Eßer bc_num_init(b, req);
4162252884aeSStefan Eßer
4163252884aeSStefan Eßer BC_SIG_UNLOCK;
4164252884aeSStefan Eßer
416550696a6eSStefan Eßer assert(a != NULL && b != NULL && a != b);
416650696a6eSStefan Eßer assert(a->num != NULL && b->num != NULL);
416750696a6eSStefan Eßer
416844d4804dSStefan Eßer // Easy case.
416978bc019dSStefan Eßer if (BC_NUM_ZERO(a))
417078bc019dSStefan Eßer {
4171d101cdd6SStefan Eßer bc_num_setToZero(b, realscale);
4172252884aeSStefan Eßer return;
4173252884aeSStefan Eßer }
417444d4804dSStefan Eßer
417544d4804dSStefan Eßer // Another easy case.
417678bc019dSStefan Eßer if (BC_NUM_ONE(a))
417778bc019dSStefan Eßer {
4178252884aeSStefan Eßer bc_num_one(b);
4179d101cdd6SStefan Eßer bc_num_extend(b, realscale);
4180252884aeSStefan Eßer return;
4181252884aeSStefan Eßer }
4182252884aeSStefan Eßer
418344d4804dSStefan Eßer // Set the parameters again.
4184d101cdd6SStefan Eßer rdx = BC_NUM_RDX(realscale);
418550696a6eSStefan Eßer rdx = BC_MAX(rdx, BC_NUM_RDX_VAL(a));
4186252884aeSStefan Eßer len = bc_vm_growSize(a->len, rdx);
4187252884aeSStefan Eßer
4188252884aeSStefan Eßer BC_SIG_LOCK;
4189252884aeSStefan Eßer
4190252884aeSStefan Eßer bc_num_init(&num1, len);
4191252884aeSStefan Eßer bc_num_init(&num2, len);
4192252884aeSStefan Eßer bc_num_setup(&half, half_digs, sizeof(half_digs) / sizeof(BcDig));
4193252884aeSStefan Eßer
419444d4804dSStefan Eßer // There is a division by two in the formula. We set up a number that's 1/2
419544d4804dSStefan Eßer // so that we can use multiplication instead of heavy division.
4196f4fbc49dSStefan Eßer bc_num_setToZero(&half, 1);
4197252884aeSStefan Eßer half.num[0] = BC_BASE_POW / 2;
4198252884aeSStefan Eßer half.len = 1;
419950696a6eSStefan Eßer BC_NUM_RDX_SET_NP(half, 1);
4200252884aeSStefan Eßer
4201252884aeSStefan Eßer bc_num_init(&f, len);
4202252884aeSStefan Eßer bc_num_init(&fprime, len);
4203252884aeSStefan Eßer
4204d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
4205252884aeSStefan Eßer
4206252884aeSStefan Eßer BC_SIG_UNLOCK;
4207252884aeSStefan Eßer
420844d4804dSStefan Eßer // Pointers for easy switching.
4209252884aeSStefan Eßer x0 = &num1;
4210252884aeSStefan Eßer x1 = &num2;
4211252884aeSStefan Eßer
421244d4804dSStefan Eßer // Start with 1.
4213252884aeSStefan Eßer bc_num_one(x0);
421444d4804dSStefan Eßer
421544d4804dSStefan Eßer // The power of the operand is needed for the estimate.
4216252884aeSStefan Eßer pow = bc_num_intDigits(a);
4217252884aeSStefan Eßer
421844d4804dSStefan Eßer // The code in this if statement calculates the initial estimate. First, if
4219f4fbc49dSStefan Eßer // a is less than 1, then 0 is a good estimate. Otherwise, we want something
4220f4fbc49dSStefan Eßer // in the same ballpark. That ballpark is half of pow because the result
4221f4fbc49dSStefan Eßer // will have half the digits.
422278bc019dSStefan Eßer if (pow)
422378bc019dSStefan Eßer {
422444d4804dSStefan Eßer // An odd number is served by starting with 2^((pow-1)/2), and an even
422544d4804dSStefan Eßer // number is served by starting with 6^((pow-2)/2). Why? Because math.
4226252884aeSStefan Eßer if (pow & 1) x0->num[0] = 2;
4227252884aeSStefan Eßer else x0->num[0] = 6;
4228252884aeSStefan Eßer
4229252884aeSStefan Eßer pow -= 2 - (pow & 1);
4230252884aeSStefan Eßer bc_num_shiftLeft(x0, pow / 2);
4231252884aeSStefan Eßer }
4232252884aeSStefan Eßer
423350696a6eSStefan Eßer // I can set the rdx here directly because neg should be false.
423410328f8bSStefan Eßer x0->scale = x0->rdx = 0;
4235d101cdd6SStefan Eßer resscale = (realscale + BC_BASE_DIGS) + 2;
4236252884aeSStefan Eßer
423744d4804dSStefan Eßer // This is the calculation loop. This compare goes to 0 eventually as the
423844d4804dSStefan Eßer // difference between the two numbers gets smaller than resscale.
423978bc019dSStefan Eßer while (bc_num_cmp(x1, x0))
424078bc019dSStefan Eßer {
4241252884aeSStefan Eßer assert(BC_NUM_NONZERO(x0));
4242252884aeSStefan Eßer
424344d4804dSStefan Eßer // This loop directly corresponds to the iteration in Newton's method.
424444d4804dSStefan Eßer // If you know the formula, this loop makes sense. Go study the formula.
424544d4804dSStefan Eßer
4246252884aeSStefan Eßer bc_num_div(a, x0, &f, resscale);
4247252884aeSStefan Eßer bc_num_add(x0, &f, &fprime, resscale);
424850696a6eSStefan Eßer
424950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(fprime));
425050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(half));
425150696a6eSStefan Eßer
4252252884aeSStefan Eßer bc_num_mul(&fprime, &half, x1, resscale);
4253252884aeSStefan Eßer
425444d4804dSStefan Eßer // Switch.
4255252884aeSStefan Eßer temp = x0;
4256252884aeSStefan Eßer x0 = x1;
4257252884aeSStefan Eßer x1 = temp;
4258252884aeSStefan Eßer }
4259252884aeSStefan Eßer
426044d4804dSStefan Eßer // Copy to the result and truncate.
4261252884aeSStefan Eßer bc_num_copy(b, x0);
4262d101cdd6SStefan Eßer if (b->scale > realscale) bc_num_truncate(b, b->scale - realscale);
4263252884aeSStefan Eßer
426450696a6eSStefan Eßer assert(!BC_NUM_NEG(b) || BC_NUM_NONZERO(b));
426550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b));
426650696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(b) <= b->len || !b->len);
426750696a6eSStefan Eßer assert(!b->len || b->num[b->len - 1] || BC_NUM_RDX_VAL(b) == b->len);
4268252884aeSStefan Eßer
4269252884aeSStefan Eßer err:
4270252884aeSStefan Eßer BC_SIG_MAYLOCK;
4271252884aeSStefan Eßer bc_num_free(&fprime);
4272252884aeSStefan Eßer bc_num_free(&f);
4273252884aeSStefan Eßer bc_num_free(&num2);
4274252884aeSStefan Eßer bc_num_free(&num1);
4275d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
4276252884aeSStefan Eßer }
4277252884aeSStefan Eßer
427878bc019dSStefan Eßer void
bc_num_divmod(BcNum * a,BcNum * b,BcNum * c,BcNum * d,size_t scale)427978bc019dSStefan Eßer bc_num_divmod(BcNum* a, BcNum* b, BcNum* c, BcNum* d, size_t scale)
428078bc019dSStefan Eßer {
4281252884aeSStefan Eßer size_t ts, len;
428250696a6eSStefan Eßer BcNum *ptr_a, num2;
4283d101cdd6SStefan Eßer // This is volatile to quiet a warning on GCC about clobbering with
4284d101cdd6SStefan Eßer // longjmp().
4285d101cdd6SStefan Eßer volatile bool init = false;
4286d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
4287d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
4288d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
4289252884aeSStefan Eßer
429044d4804dSStefan Eßer // The bulk of this function is just doing what bc_num_binary() does for the
429144d4804dSStefan Eßer // binary operators. However, it assumes that only c and a can be equal.
429244d4804dSStefan Eßer
429344d4804dSStefan Eßer // Set up the parameters.
4294252884aeSStefan Eßer ts = BC_MAX(scale + b->scale, a->scale);
4295252884aeSStefan Eßer len = bc_num_mulReq(a, b, ts);
4296252884aeSStefan Eßer
4297252884aeSStefan Eßer assert(a != NULL && b != NULL && c != NULL && d != NULL);
4298252884aeSStefan Eßer assert(c != d && a != d && b != d && b != c);
4299252884aeSStefan Eßer
430044d4804dSStefan Eßer // Initialize or expand as necessary.
430178bc019dSStefan Eßer if (c == a)
430278bc019dSStefan Eßer {
430378bc019dSStefan Eßer // NOLINTNEXTLINE
4304252884aeSStefan Eßer memcpy(&num2, c, sizeof(BcNum));
4305252884aeSStefan Eßer ptr_a = &num2;
4306252884aeSStefan Eßer
4307252884aeSStefan Eßer BC_SIG_LOCK;
4308252884aeSStefan Eßer
4309252884aeSStefan Eßer bc_num_init(c, len);
4310252884aeSStefan Eßer
4311252884aeSStefan Eßer init = true;
4312252884aeSStefan Eßer
4313d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
4314252884aeSStefan Eßer
4315252884aeSStefan Eßer BC_SIG_UNLOCK;
4316252884aeSStefan Eßer }
431778bc019dSStefan Eßer else
431878bc019dSStefan Eßer {
4319252884aeSStefan Eßer ptr_a = a;
4320252884aeSStefan Eßer bc_num_expand(c, len);
4321252884aeSStefan Eßer }
4322252884aeSStefan Eßer
432344d4804dSStefan Eßer // Do the quick version if possible.
432478bc019dSStefan Eßer if (BC_NUM_NONZERO(a) && !BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b) &&
432578bc019dSStefan Eßer b->len == 1 && !scale)
432650696a6eSStefan Eßer {
4327252884aeSStefan Eßer BcBigDig rem;
4328252884aeSStefan Eßer
4329252884aeSStefan Eßer bc_num_divArray(ptr_a, (BcBigDig) b->num[0], c, &rem);
4330252884aeSStefan Eßer
4331252884aeSStefan Eßer assert(rem < BC_BASE_POW);
4332252884aeSStefan Eßer
4333252884aeSStefan Eßer d->num[0] = (BcDig) rem;
4334252884aeSStefan Eßer d->len = (rem != 0);
4335252884aeSStefan Eßer }
433644d4804dSStefan Eßer // Do the slow method.
4337252884aeSStefan Eßer else bc_num_r(ptr_a, b, c, d, scale, ts);
4338252884aeSStefan Eßer
433950696a6eSStefan Eßer assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c));
434050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(c));
434150696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len);
434250696a6eSStefan Eßer assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len);
434350696a6eSStefan Eßer assert(!BC_NUM_NEG(d) || BC_NUM_NONZERO(d));
434450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(d));
434550696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(d) <= d->len || !d->len);
434650696a6eSStefan Eßer assert(!d->len || d->num[d->len - 1] || BC_NUM_RDX_VAL(d) == d->len);
4347252884aeSStefan Eßer
4348252884aeSStefan Eßer err:
434944d4804dSStefan Eßer // Only cleanup if we initialized.
435078bc019dSStefan Eßer if (init)
435178bc019dSStefan Eßer {
4352252884aeSStefan Eßer BC_SIG_MAYLOCK;
4353252884aeSStefan Eßer bc_num_free(&num2);
4354d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
4355252884aeSStefan Eßer }
4356252884aeSStefan Eßer }
4357252884aeSStefan Eßer
435878bc019dSStefan Eßer void
bc_num_modexp(BcNum * a,BcNum * b,BcNum * c,BcNum * restrict d)435978bc019dSStefan Eßer bc_num_modexp(BcNum* a, BcNum* b, BcNum* c, BcNum* restrict d)
436078bc019dSStefan Eßer {
436144d4804dSStefan Eßer BcNum base, exp, two, temp, atemp, btemp, ctemp;
4362252884aeSStefan Eßer BcDig two_digs[2];
4363d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY
4364d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific();
4365d101cdd6SStefan Eßer #endif // BC_ENABLE_LIBRARY
4366252884aeSStefan Eßer
4367252884aeSStefan Eßer assert(a != NULL && b != NULL && c != NULL && d != NULL);
4368252884aeSStefan Eßer assert(a != d && b != d && c != d);
4369252884aeSStefan Eßer
437044d4804dSStefan Eßer if (BC_ERR(BC_NUM_ZERO(c))) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO);
437144d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(b))) bc_err(BC_ERR_MATH_NEGATIVE);
437244d4804dSStefan Eßer
4373103d7cdfSStefan Eßer #if BC_DEBUG || BC_GCC
437444d4804dSStefan Eßer // This is entirely for quieting a useless scan-build error.
437544d4804dSStefan Eßer btemp.len = 0;
437644d4804dSStefan Eßer ctemp.len = 0;
4377103d7cdfSStefan Eßer #endif // BC_DEBUG || BC_GCC
437844d4804dSStefan Eßer
437944d4804dSStefan Eßer // Eliminate fractional parts that are zero or error if they are not zero.
438044d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(a, &atemp) || bc_num_nonInt(b, &btemp) ||
438144d4804dSStefan Eßer bc_num_nonInt(c, &ctemp)))
438244d4804dSStefan Eßer {
438344d4804dSStefan Eßer bc_err(BC_ERR_MATH_NON_INTEGER);
438444d4804dSStefan Eßer }
438544d4804dSStefan Eßer
438644d4804dSStefan Eßer bc_num_expand(d, ctemp.len);
4387252884aeSStefan Eßer
4388252884aeSStefan Eßer BC_SIG_LOCK;
4389252884aeSStefan Eßer
439044d4804dSStefan Eßer bc_num_init(&base, ctemp.len);
4391252884aeSStefan Eßer bc_num_setup(&two, two_digs, sizeof(two_digs) / sizeof(BcDig));
439244d4804dSStefan Eßer bc_num_init(&temp, btemp.len + 1);
439344d4804dSStefan Eßer bc_num_createCopy(&exp, &btemp);
4394252884aeSStefan Eßer
4395d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, err);
4396252884aeSStefan Eßer
4397252884aeSStefan Eßer BC_SIG_UNLOCK;
4398252884aeSStefan Eßer
4399252884aeSStefan Eßer bc_num_one(&two);
4400252884aeSStefan Eßer two.num[0] = 2;
4401252884aeSStefan Eßer bc_num_one(d);
4402252884aeSStefan Eßer
4403252884aeSStefan Eßer // We already checked for 0.
440444d4804dSStefan Eßer bc_num_rem(&atemp, &ctemp, &base, 0);
4405252884aeSStefan Eßer
440644d4804dSStefan Eßer // If you know the algorithm I used, the memory-efficient method, then this
440744d4804dSStefan Eßer // loop should be self-explanatory because it is the calculation loop.
440878bc019dSStefan Eßer while (BC_NUM_NONZERO(&exp))
440978bc019dSStefan Eßer {
4410252884aeSStefan Eßer // Num two cannot be 0, so no errors.
4411252884aeSStefan Eßer bc_num_divmod(&exp, &two, &exp, &temp, 0);
4412252884aeSStefan Eßer
441378bc019dSStefan Eßer if (BC_NUM_ONE(&temp) && !BC_NUM_NEG_NP(temp))
441478bc019dSStefan Eßer {
441550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(d));
441650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(base));
4417252884aeSStefan Eßer
4418252884aeSStefan Eßer bc_num_mul(d, &base, &temp, 0);
4419252884aeSStefan Eßer
4420252884aeSStefan Eßer // We already checked for 0.
442144d4804dSStefan Eßer bc_num_rem(&temp, &ctemp, d, 0);
4422252884aeSStefan Eßer }
4423252884aeSStefan Eßer
442450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(base));
442550696a6eSStefan Eßer
4426252884aeSStefan Eßer bc_num_mul(&base, &base, &temp, 0);
4427252884aeSStefan Eßer
4428252884aeSStefan Eßer // We already checked for 0.
442944d4804dSStefan Eßer bc_num_rem(&temp, &ctemp, &base, 0);
4430252884aeSStefan Eßer }
4431252884aeSStefan Eßer
4432252884aeSStefan Eßer err:
4433252884aeSStefan Eßer BC_SIG_MAYLOCK;
4434252884aeSStefan Eßer bc_num_free(&exp);
4435252884aeSStefan Eßer bc_num_free(&temp);
4436252884aeSStefan Eßer bc_num_free(&base);
4437d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm);
443850696a6eSStefan Eßer assert(!BC_NUM_NEG(d) || d->len);
443950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(d));
444050696a6eSStefan Eßer assert(!d->len || d->num[d->len - 1] || BC_NUM_RDX_VAL(d) == d->len);
4441252884aeSStefan Eßer }
4442252884aeSStefan Eßer
4443252884aeSStefan Eßer #if BC_DEBUG_CODE
444478bc019dSStefan Eßer void
bc_num_printDebug(const BcNum * n,const char * name,bool emptyline)444578bc019dSStefan Eßer bc_num_printDebug(const BcNum* n, const char* name, bool emptyline)
444678bc019dSStefan Eßer {
4447d101cdd6SStefan Eßer bc_file_puts(&vm->fout, bc_flush_none, name);
4448d101cdd6SStefan Eßer bc_file_puts(&vm->fout, bc_flush_none, ": ");
444944d4804dSStefan Eßer bc_num_printDecimal(n, true);
4450d101cdd6SStefan Eßer bc_file_putchar(&vm->fout, bc_flush_err, '\n');
4451d101cdd6SStefan Eßer if (emptyline) bc_file_putchar(&vm->fout, bc_flush_err, '\n');
4452d101cdd6SStefan Eßer vm->nchars = 0;
4453252884aeSStefan Eßer }
4454252884aeSStefan Eßer
445578bc019dSStefan Eßer void
bc_num_printDigs(const BcDig * n,size_t len,bool emptyline)445678bc019dSStefan Eßer bc_num_printDigs(const BcDig* n, size_t len, bool emptyline)
445778bc019dSStefan Eßer {
4458252884aeSStefan Eßer size_t i;
4459252884aeSStefan Eßer
4460252884aeSStefan Eßer for (i = len - 1; i < len; --i)
446178bc019dSStefan Eßer {
4462d101cdd6SStefan Eßer bc_file_printf(&vm->fout, " %lu", (unsigned long) n[i]);
446378bc019dSStefan Eßer }
4464252884aeSStefan Eßer
4465d101cdd6SStefan Eßer bc_file_putchar(&vm->fout, bc_flush_err, '\n');
4466d101cdd6SStefan Eßer if (emptyline) bc_file_putchar(&vm->fout, bc_flush_err, '\n');
4467d101cdd6SStefan Eßer vm->nchars = 0;
4468252884aeSStefan Eßer }
4469252884aeSStefan Eßer
447078bc019dSStefan Eßer void
bc_num_printWithDigs(const BcNum * n,const char * name,bool emptyline)447178bc019dSStefan Eßer bc_num_printWithDigs(const BcNum* n, const char* name, bool emptyline)
447278bc019dSStefan Eßer {
4473d101cdd6SStefan Eßer bc_file_puts(&vm->fout, bc_flush_none, name);
4474d101cdd6SStefan Eßer bc_file_printf(&vm->fout, " len: %zu, rdx: %zu, scale: %zu\n", name, n->len,
447578bc019dSStefan Eßer BC_NUM_RDX_VAL(n), n->scale);
4476252884aeSStefan Eßer bc_num_printDigs(n->num, n->len, emptyline);
4477252884aeSStefan Eßer }
4478252884aeSStefan Eßer
447978bc019dSStefan Eßer void
bc_num_dump(const char * varname,const BcNum * n)448078bc019dSStefan Eßer bc_num_dump(const char* varname, const BcNum* n)
448178bc019dSStefan Eßer {
4482252884aeSStefan Eßer ulong i, scale = n->scale;
4483252884aeSStefan Eßer
4484d101cdd6SStefan Eßer bc_file_printf(&vm->ferr, "\n%s = %s", varname,
448550696a6eSStefan Eßer n->len ? (BC_NUM_NEG(n) ? "-" : "+") : "0 ");
4486252884aeSStefan Eßer
448778bc019dSStefan Eßer for (i = n->len - 1; i < n->len; --i)
448878bc019dSStefan Eßer {
44897e5c51e5SStefan Eßer if (i + 1 == BC_NUM_RDX_VAL(n))
449078bc019dSStefan Eßer {
4491d101cdd6SStefan Eßer bc_file_puts(&vm->ferr, bc_flush_none, ". ");
449278bc019dSStefan Eßer }
4493252884aeSStefan Eßer
449450696a6eSStefan Eßer if (scale / BC_BASE_DIGS != BC_NUM_RDX_VAL(n) - i - 1)
449578bc019dSStefan Eßer {
4496d101cdd6SStefan Eßer bc_file_printf(&vm->ferr, "%lu ", (unsigned long) n->num[i]);
449778bc019dSStefan Eßer }
449878bc019dSStefan Eßer else
449978bc019dSStefan Eßer {
4500252884aeSStefan Eßer int mod = scale % BC_BASE_DIGS;
4501252884aeSStefan Eßer int d = BC_BASE_DIGS - mod;
4502252884aeSStefan Eßer BcDig div;
4503252884aeSStefan Eßer
450478bc019dSStefan Eßer if (mod != 0)
450578bc019dSStefan Eßer {
4506252884aeSStefan Eßer div = n->num[i] / ((BcDig) bc_num_pow10[(ulong) d]);
4507d101cdd6SStefan Eßer bc_file_printf(&vm->ferr, "%lu", (unsigned long) div);
4508252884aeSStefan Eßer }
4509252884aeSStefan Eßer
4510252884aeSStefan Eßer div = n->num[i] % ((BcDig) bc_num_pow10[(ulong) d]);
4511d101cdd6SStefan Eßer bc_file_printf(&vm->ferr, " ' %lu ", (unsigned long) div);
4512252884aeSStefan Eßer }
4513252884aeSStefan Eßer }
4514252884aeSStefan Eßer
4515d101cdd6SStefan Eßer bc_file_printf(&vm->ferr, "(%zu | %zu.%zu / %zu) %lu\n", n->scale, n->len,
451678bc019dSStefan Eßer BC_NUM_RDX_VAL(n), n->cap, (unsigned long) (void*) n->num);
45177e5c51e5SStefan Eßer
4518d101cdd6SStefan Eßer bc_file_flush(&vm->ferr, bc_flush_err);
4519252884aeSStefan Eßer }
4520252884aeSStefan Eßer #endif // BC_DEBUG_CODE
4521