1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 610328f8bSStefan Eßer * Copyright (c) 2018-2021 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> 47252884aeSStefan Eßer 4844d4804dSStefan Eßer // Before you try to understand this code, see the development manual 4944d4804dSStefan Eßer // (manuals/development.md#numbers). 5044d4804dSStefan Eßer 51252884aeSStefan Eßer static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale); 52252884aeSStefan Eßer 5344d4804dSStefan Eßer /** 5444d4804dSStefan Eßer * Multiply two numbers and throw a math error if they overflow. 5544d4804dSStefan Eßer * @param a The first operand. 5644d4804dSStefan Eßer * @param b The second operand. 5744d4804dSStefan Eßer * @return The product of the two operands. 5844d4804dSStefan Eßer */ 5944d4804dSStefan Eßer static inline size_t bc_num_mulOverflow(size_t a, size_t b) { 6044d4804dSStefan Eßer size_t res = a * b; 6144d4804dSStefan Eßer if (BC_ERR(BC_VM_MUL_OVERFLOW(a, b, res))) bc_err(BC_ERR_MATH_OVERFLOW); 6244d4804dSStefan Eßer return res; 6344d4804dSStefan Eßer } 6444d4804dSStefan Eßer 6544d4804dSStefan Eßer /** 6644d4804dSStefan Eßer * Conditionally negate @a n based on @a neg. Algorithm taken from 6744d4804dSStefan Eßer * https://graphics.stanford.edu/~seander/bithacks.html#ConditionalNegate . 6844d4804dSStefan Eßer * @param n The value to turn into a signed value and negate. 6944d4804dSStefan Eßer * @param neg The condition to negate or not. 7044d4804dSStefan Eßer */ 71252884aeSStefan Eßer static inline ssize_t bc_num_neg(size_t n, bool neg) { 72252884aeSStefan Eßer return (((ssize_t) n) ^ -((ssize_t) neg)) + neg; 73252884aeSStefan Eßer } 74252884aeSStefan Eßer 7544d4804dSStefan Eßer /** 7644d4804dSStefan Eßer * Compare a BcNum against zero. 7744d4804dSStefan Eßer * @param n The number to compare. 7844d4804dSStefan Eßer * @return -1 if the number is less than 0, 1 if greater, and 0 if equal. 7944d4804dSStefan Eßer */ 80252884aeSStefan Eßer ssize_t bc_num_cmpZero(const BcNum *n) { 8150696a6eSStefan Eßer return bc_num_neg((n)->len != 0, BC_NUM_NEG(n)); 82252884aeSStefan Eßer } 83252884aeSStefan Eßer 8444d4804dSStefan Eßer /** 8544d4804dSStefan Eßer * Return the number of integer limbs in a BcNum. This is the opposite of rdx. 8644d4804dSStefan Eßer * @param n The number to return the amount of integer limbs for. 8744d4804dSStefan Eßer * @return The amount of integer limbs in @a n. 8844d4804dSStefan Eßer */ 89252884aeSStefan Eßer static inline size_t bc_num_int(const BcNum *n) { 9050696a6eSStefan Eßer return n->len ? n->len - BC_NUM_RDX_VAL(n) : 0; 91252884aeSStefan Eßer } 92252884aeSStefan Eßer 9344d4804dSStefan Eßer /** 9444d4804dSStefan Eßer * Expand a number's allocation capacity to at least req limbs. 9544d4804dSStefan Eßer * @param n The number to expand. 9644d4804dSStefan Eßer * @param req The number limbs to expand the allocation capacity to. 9744d4804dSStefan Eßer */ 98252884aeSStefan Eßer static void bc_num_expand(BcNum *restrict n, size_t req) { 99252884aeSStefan Eßer 100252884aeSStefan Eßer assert(n != NULL); 101252884aeSStefan Eßer 102252884aeSStefan Eßer req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; 103252884aeSStefan Eßer 104252884aeSStefan Eßer if (req > n->cap) { 105252884aeSStefan Eßer 106252884aeSStefan Eßer BC_SIG_LOCK; 107252884aeSStefan Eßer 108252884aeSStefan Eßer n->num = bc_vm_realloc(n->num, BC_NUM_SIZE(req)); 109252884aeSStefan Eßer n->cap = req; 110252884aeSStefan Eßer 111252884aeSStefan Eßer BC_SIG_UNLOCK; 112252884aeSStefan Eßer } 113252884aeSStefan Eßer } 114252884aeSStefan Eßer 11544d4804dSStefan Eßer /** 11644d4804dSStefan Eßer * Set a number to 0 with the specified scale. 11744d4804dSStefan Eßer * @param n The number to set to zero. 11844d4804dSStefan Eßer * @param scale The scale to set the number to. 11944d4804dSStefan Eßer */ 120252884aeSStefan Eßer static void bc_num_setToZero(BcNum *restrict n, size_t scale) { 121252884aeSStefan Eßer assert(n != NULL); 122252884aeSStefan Eßer n->scale = scale; 123252884aeSStefan Eßer n->len = n->rdx = 0; 124252884aeSStefan Eßer } 125252884aeSStefan Eßer 12650696a6eSStefan Eßer void bc_num_zero(BcNum *restrict n) { 127252884aeSStefan Eßer bc_num_setToZero(n, 0); 128252884aeSStefan Eßer } 129252884aeSStefan Eßer 130252884aeSStefan Eßer void bc_num_one(BcNum *restrict n) { 131252884aeSStefan Eßer bc_num_zero(n); 132252884aeSStefan Eßer n->len = 1; 133252884aeSStefan Eßer n->num[0] = 1; 134252884aeSStefan Eßer } 135252884aeSStefan Eßer 13644d4804dSStefan Eßer /** 13744d4804dSStefan Eßer * "Cleans" a number, which means reducing the length if the most significant 13844d4804dSStefan Eßer * limbs are zero. 13944d4804dSStefan Eßer * @param n The number to clean. 14044d4804dSStefan Eßer */ 141252884aeSStefan Eßer static void bc_num_clean(BcNum *restrict n) { 142252884aeSStefan Eßer 14344d4804dSStefan Eßer // Reduce the length. 144252884aeSStefan Eßer while (BC_NUM_NONZERO(n) && !n->num[n->len - 1]) n->len -= 1; 145252884aeSStefan Eßer 14644d4804dSStefan Eßer // Special cases. 14750696a6eSStefan Eßer if (BC_NUM_ZERO(n)) n->rdx = 0; 14850696a6eSStefan Eßer else { 14944d4804dSStefan Eßer 15044d4804dSStefan Eßer // len must be at least as much as rdx. 15150696a6eSStefan Eßer size_t rdx = BC_NUM_RDX_VAL(n); 15250696a6eSStefan Eßer if (n->len < rdx) n->len = rdx; 153252884aeSStefan Eßer } 154252884aeSStefan Eßer } 155252884aeSStefan Eßer 15644d4804dSStefan Eßer /** 15744d4804dSStefan Eßer * Returns the log base 10 of @a i. I could have done this with floating-point 15844d4804dSStefan Eßer * math, and in fact, I originally did. However, that was the only 15944d4804dSStefan Eßer * floating-point code in the entire codebase, and I decided I didn't want any. 16044d4804dSStefan Eßer * This is fast enough. Also, it might handle larger numbers better. 16144d4804dSStefan Eßer * @param i The number to return the log base 10 of. 16244d4804dSStefan Eßer * @return The log base 10 of @a i. 16344d4804dSStefan Eßer */ 164252884aeSStefan Eßer static size_t bc_num_log10(size_t i) { 165252884aeSStefan Eßer size_t len; 166252884aeSStefan Eßer for (len = 1; i; i /= BC_BASE, ++len); 167252884aeSStefan Eßer assert(len - 1 <= BC_BASE_DIGS + 1); 168252884aeSStefan Eßer return len - 1; 169252884aeSStefan Eßer } 170252884aeSStefan Eßer 17144d4804dSStefan Eßer /** 17244d4804dSStefan Eßer * Returns the number of decimal digits in a limb that are zero starting at the 17344d4804dSStefan Eßer * most significant digits. This basically returns how much of the limb is used. 17444d4804dSStefan Eßer * @param n The number. 17544d4804dSStefan Eßer * @return The number of decimal digits that are 0 starting at the most 17644d4804dSStefan Eßer * significant digits. 17744d4804dSStefan Eßer */ 178252884aeSStefan Eßer static inline size_t bc_num_zeroDigits(const BcDig *n) { 179252884aeSStefan Eßer assert(*n >= 0); 180252884aeSStefan Eßer assert(((size_t) *n) < BC_BASE_POW); 181252884aeSStefan Eßer return BC_BASE_DIGS - bc_num_log10((size_t) *n); 182252884aeSStefan Eßer } 183252884aeSStefan Eßer 18444d4804dSStefan Eßer /** 18544d4804dSStefan Eßer * Return the total number of integer digits in a number. This is the opposite 18644d4804dSStefan Eßer * of scale, like bc_num_int() is the opposite of rdx. 18744d4804dSStefan Eßer * @param n The number. 18844d4804dSStefan Eßer * @return The number of integer digits in @a n. 18944d4804dSStefan Eßer */ 190252884aeSStefan Eßer static size_t bc_num_intDigits(const BcNum *n) { 191252884aeSStefan Eßer size_t digits = bc_num_int(n) * BC_BASE_DIGS; 192252884aeSStefan Eßer if (digits > 0) digits -= bc_num_zeroDigits(n->num + n->len - 1); 193252884aeSStefan Eßer return digits; 194252884aeSStefan Eßer } 195252884aeSStefan Eßer 19644d4804dSStefan Eßer /** 19744d4804dSStefan Eßer * Returns the number of limbs of a number that are non-zero starting at the 19844d4804dSStefan Eßer * most significant limbs. This expects that there are *no* integer limbs in the 19944d4804dSStefan Eßer * number because it is specifically to figure out how many zero limbs after the 20044d4804dSStefan Eßer * decimal place to ignore. If there are zero limbs after non-zero limbs, they 20144d4804dSStefan Eßer * are counted as non-zero limbs. 20244d4804dSStefan Eßer * @param n The number. 20344d4804dSStefan Eßer * @return The number of non-zero limbs after the decimal point. 20444d4804dSStefan Eßer */ 20544d4804dSStefan Eßer static size_t bc_num_nonZeroLen(const BcNum *restrict n) { 206252884aeSStefan Eßer size_t i, len = n->len; 20750696a6eSStefan Eßer assert(len == BC_NUM_RDX_VAL(n)); 208252884aeSStefan Eßer for (i = len - 1; i < len && !n->num[i]; --i); 209252884aeSStefan Eßer assert(i + 1 > 0); 210252884aeSStefan Eßer return i + 1; 211252884aeSStefan Eßer } 212252884aeSStefan Eßer 21344d4804dSStefan Eßer /** 21444d4804dSStefan Eßer * Performs a one-limb add with a carry. 21544d4804dSStefan Eßer * @param a The first limb. 21644d4804dSStefan Eßer * @param b The second limb. 21744d4804dSStefan Eßer * @param carry An in/out parameter; the carry in from the previous add and the 21844d4804dSStefan Eßer * carry out from this add. 21944d4804dSStefan Eßer * @return The resulting limb sum. 22044d4804dSStefan Eßer */ 221252884aeSStefan Eßer static BcDig bc_num_addDigits(BcDig a, BcDig b, bool *carry) { 222252884aeSStefan Eßer 223252884aeSStefan Eßer assert(((BcBigDig) BC_BASE_POW) * 2 == ((BcDig) BC_BASE_POW) * 2); 224252884aeSStefan Eßer assert(a < BC_BASE_POW); 225252884aeSStefan Eßer assert(b < BC_BASE_POW); 226252884aeSStefan Eßer 227252884aeSStefan Eßer a += b + *carry; 228252884aeSStefan Eßer *carry = (a >= BC_BASE_POW); 229252884aeSStefan Eßer if (*carry) a -= BC_BASE_POW; 230252884aeSStefan Eßer 231252884aeSStefan Eßer assert(a >= 0); 232252884aeSStefan Eßer assert(a < BC_BASE_POW); 233252884aeSStefan Eßer 234252884aeSStefan Eßer return a; 235252884aeSStefan Eßer } 236252884aeSStefan Eßer 23744d4804dSStefan Eßer /** 23844d4804dSStefan Eßer * Performs a one-limb subtract with a carry. 23944d4804dSStefan Eßer * @param a The first limb. 24044d4804dSStefan Eßer * @param b The second limb. 24144d4804dSStefan Eßer * @param carry An in/out parameter; the carry in from the previous subtract 24244d4804dSStefan Eßer * and the carry out from this subtract. 24344d4804dSStefan Eßer * @return The resulting limb difference. 24444d4804dSStefan Eßer */ 245252884aeSStefan Eßer static BcDig bc_num_subDigits(BcDig a, BcDig b, bool *carry) { 246252884aeSStefan Eßer 247252884aeSStefan Eßer assert(a < BC_BASE_POW); 248252884aeSStefan Eßer assert(b < BC_BASE_POW); 249252884aeSStefan Eßer 250252884aeSStefan Eßer b += *carry; 251252884aeSStefan Eßer *carry = (a < b); 252252884aeSStefan Eßer if (*carry) a += BC_BASE_POW; 253252884aeSStefan Eßer 254252884aeSStefan Eßer assert(a - b >= 0); 255252884aeSStefan Eßer assert(a - b < BC_BASE_POW); 256252884aeSStefan Eßer 257252884aeSStefan Eßer return a - b; 258252884aeSStefan Eßer } 259252884aeSStefan Eßer 26044d4804dSStefan Eßer /** 26144d4804dSStefan Eßer * Add two BcDig arrays and store the result in the first array. 26244d4804dSStefan Eßer * @param a The first operand and out array. 26344d4804dSStefan Eßer * @param b The second operand. 26444d4804dSStefan Eßer * @param len The length of @a b. 26544d4804dSStefan Eßer */ 266252884aeSStefan Eßer static void bc_num_addArrays(BcDig *restrict a, const BcDig *restrict b, 267252884aeSStefan Eßer size_t len) 268252884aeSStefan Eßer { 269252884aeSStefan Eßer size_t i; 270252884aeSStefan Eßer bool carry = false; 271252884aeSStefan Eßer 272252884aeSStefan Eßer for (i = 0; i < len; ++i) a[i] = bc_num_addDigits(a[i], b[i], &carry); 273252884aeSStefan Eßer 27444d4804dSStefan Eßer // Take care of the extra limbs in the bigger array. 275252884aeSStefan Eßer for (; carry; ++i) a[i] = bc_num_addDigits(a[i], 0, &carry); 276252884aeSStefan Eßer } 277252884aeSStefan Eßer 27844d4804dSStefan Eßer /** 27944d4804dSStefan Eßer * Subtract two BcDig arrays and store the result in the first array. 28044d4804dSStefan Eßer * @param a The first operand and out array. 28144d4804dSStefan Eßer * @param b The second operand. 28244d4804dSStefan Eßer * @param len The length of @a b. 28344d4804dSStefan Eßer */ 284252884aeSStefan Eßer static void bc_num_subArrays(BcDig *restrict a, const BcDig *restrict b, 285252884aeSStefan Eßer size_t len) 286252884aeSStefan Eßer { 287252884aeSStefan Eßer size_t i; 288252884aeSStefan Eßer bool carry = false; 289252884aeSStefan Eßer 290252884aeSStefan Eßer for (i = 0; i < len; ++i) a[i] = bc_num_subDigits(a[i], b[i], &carry); 291252884aeSStefan Eßer 29244d4804dSStefan Eßer // Take care of the extra limbs in the bigger array. 293252884aeSStefan Eßer for (; carry; ++i) a[i] = bc_num_subDigits(a[i], 0, &carry); 294252884aeSStefan Eßer } 295252884aeSStefan Eßer 29644d4804dSStefan Eßer /** 29744d4804dSStefan Eßer * Multiply a BcNum array by a one-limb number. This is a faster version of 29844d4804dSStefan Eßer * multiplication for when we can use it. 29944d4804dSStefan Eßer * @param a The BcNum to multiply by the one-limb number. 30044d4804dSStefan Eßer * @param b The one limb of the one-limb number. 30144d4804dSStefan Eßer * @param c The return parameter. 30244d4804dSStefan Eßer */ 303252884aeSStefan Eßer static void bc_num_mulArray(const BcNum *restrict a, BcBigDig b, 304252884aeSStefan Eßer BcNum *restrict c) 305252884aeSStefan Eßer { 306252884aeSStefan Eßer size_t i; 307252884aeSStefan Eßer BcBigDig carry = 0; 308252884aeSStefan Eßer 309252884aeSStefan Eßer assert(b <= BC_BASE_POW); 310252884aeSStefan Eßer 31144d4804dSStefan Eßer // Make sure the return parameter is big enough. 312252884aeSStefan Eßer if (a->len + 1 > c->cap) bc_num_expand(c, a->len + 1); 313252884aeSStefan Eßer 31444d4804dSStefan Eßer // We want the entire return parameter to be zero for cleaning later. 315252884aeSStefan Eßer memset(c->num, 0, BC_NUM_SIZE(c->cap)); 316252884aeSStefan Eßer 31744d4804dSStefan Eßer // Actual multiplication loop. 318252884aeSStefan Eßer for (i = 0; i < a->len; ++i) { 319252884aeSStefan Eßer BcBigDig in = ((BcBigDig) a->num[i]) * b + carry; 320252884aeSStefan Eßer c->num[i] = in % BC_BASE_POW; 321252884aeSStefan Eßer carry = in / BC_BASE_POW; 322252884aeSStefan Eßer } 323252884aeSStefan Eßer 324252884aeSStefan Eßer assert(carry < BC_BASE_POW); 32544d4804dSStefan Eßer 32644d4804dSStefan Eßer // Finishing touches. 327252884aeSStefan Eßer c->num[i] = (BcDig) carry; 328252884aeSStefan Eßer c->len = a->len; 329252884aeSStefan Eßer c->len += (carry != 0); 330252884aeSStefan Eßer 331252884aeSStefan Eßer bc_num_clean(c); 332252884aeSStefan Eßer 33344d4804dSStefan Eßer // Postconditions. 33450696a6eSStefan Eßer assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c)); 33550696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len); 33650696a6eSStefan Eßer assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len); 337252884aeSStefan Eßer } 338252884aeSStefan Eßer 33944d4804dSStefan Eßer /** 34044d4804dSStefan Eßer * Divide a BcNum array by a one-limb number. This is a faster version of divide 34144d4804dSStefan Eßer * for when we can use it. 34244d4804dSStefan Eßer * @param a The BcNum to multiply by the one-limb number. 34344d4804dSStefan Eßer * @param b The one limb of the one-limb number. 34444d4804dSStefan Eßer * @param c The return parameter for the quotient. 34544d4804dSStefan Eßer * @param rem The return parameter for the remainder. 34644d4804dSStefan Eßer */ 347252884aeSStefan Eßer static void bc_num_divArray(const BcNum *restrict a, BcBigDig b, 348252884aeSStefan Eßer BcNum *restrict c, BcBigDig *rem) 349252884aeSStefan Eßer { 350252884aeSStefan Eßer size_t i; 351252884aeSStefan Eßer BcBigDig carry = 0; 352252884aeSStefan Eßer 353252884aeSStefan Eßer assert(c->cap >= a->len); 354252884aeSStefan Eßer 35544d4804dSStefan Eßer // Actual division loop. 356252884aeSStefan Eßer for (i = a->len - 1; i < a->len; --i) { 357252884aeSStefan Eßer BcBigDig in = ((BcBigDig) a->num[i]) + carry * BC_BASE_POW; 358252884aeSStefan Eßer assert(in / b < BC_BASE_POW); 359252884aeSStefan Eßer c->num[i] = (BcDig) (in / b); 360252884aeSStefan Eßer carry = in % b; 361252884aeSStefan Eßer } 362252884aeSStefan Eßer 36344d4804dSStefan Eßer // Finishing touches. 364252884aeSStefan Eßer c->len = a->len; 365252884aeSStefan Eßer bc_num_clean(c); 366252884aeSStefan Eßer *rem = carry; 367252884aeSStefan Eßer 36844d4804dSStefan Eßer // Postconditions. 36950696a6eSStefan Eßer assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c)); 37050696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len); 37150696a6eSStefan Eßer assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len); 372252884aeSStefan Eßer } 373252884aeSStefan Eßer 37444d4804dSStefan Eßer /** 37544d4804dSStefan Eßer * Compare two BcDig arrays and return >0 if @a b is greater, <0 if @a b is 37644d4804dSStefan Eßer * less, and 0 if equal. Both @a a and @a b must have the same length. 37744d4804dSStefan Eßer * @param a The first array. 37844d4804dSStefan Eßer * @param b The second array. 37944d4804dSStefan Eßer * @param len The minimum length of the arrays. 38044d4804dSStefan Eßer */ 381252884aeSStefan Eßer static ssize_t bc_num_compare(const BcDig *restrict a, const BcDig *restrict b, 382252884aeSStefan Eßer size_t len) 383252884aeSStefan Eßer { 384252884aeSStefan Eßer size_t i; 385252884aeSStefan Eßer BcDig c = 0; 386252884aeSStefan Eßer for (i = len - 1; i < len && !(c = a[i] - b[i]); --i); 387252884aeSStefan Eßer return bc_num_neg(i + 1, c < 0); 388252884aeSStefan Eßer } 389252884aeSStefan Eßer 390252884aeSStefan Eßer ssize_t bc_num_cmp(const BcNum *a, const BcNum *b) { 391252884aeSStefan Eßer 39250696a6eSStefan Eßer size_t i, min, a_int, b_int, diff, ardx, brdx; 393252884aeSStefan Eßer BcDig *max_num, *min_num; 394252884aeSStefan Eßer bool a_max, neg = false; 395252884aeSStefan Eßer ssize_t cmp; 396252884aeSStefan Eßer 397252884aeSStefan Eßer assert(a != NULL && b != NULL); 398252884aeSStefan Eßer 39944d4804dSStefan Eßer // Same num? Equal. 400252884aeSStefan Eßer if (a == b) return 0; 40144d4804dSStefan Eßer 40244d4804dSStefan Eßer // Easy cases. 40350696a6eSStefan Eßer if (BC_NUM_ZERO(a)) return bc_num_neg(b->len != 0, !BC_NUM_NEG(b)); 404252884aeSStefan Eßer if (BC_NUM_ZERO(b)) return bc_num_cmpZero(a); 40550696a6eSStefan Eßer if (BC_NUM_NEG(a)) { 40650696a6eSStefan Eßer if (BC_NUM_NEG(b)) neg = true; 407252884aeSStefan Eßer else return -1; 408252884aeSStefan Eßer } 40950696a6eSStefan Eßer else if (BC_NUM_NEG(b)) return 1; 410252884aeSStefan Eßer 41144d4804dSStefan Eßer // Get the number of int limbs in each number and get the difference. 412252884aeSStefan Eßer a_int = bc_num_int(a); 413252884aeSStefan Eßer b_int = bc_num_int(b); 414252884aeSStefan Eßer a_int -= b_int; 415252884aeSStefan Eßer 41644d4804dSStefan Eßer // If there's a difference, then just return the comparison. 417252884aeSStefan Eßer if (a_int) return neg ? -((ssize_t) a_int) : (ssize_t) a_int; 418252884aeSStefan Eßer 41944d4804dSStefan Eßer // Get the rdx's and figure out the max. 42050696a6eSStefan Eßer ardx = BC_NUM_RDX_VAL(a); 42150696a6eSStefan Eßer brdx = BC_NUM_RDX_VAL(b); 42250696a6eSStefan Eßer a_max = (ardx > brdx); 423252884aeSStefan Eßer 42444d4804dSStefan Eßer // Set variables based on the above. 425252884aeSStefan Eßer if (a_max) { 42650696a6eSStefan Eßer min = brdx; 42750696a6eSStefan Eßer diff = ardx - brdx; 428252884aeSStefan Eßer max_num = a->num + diff; 429252884aeSStefan Eßer min_num = b->num; 430252884aeSStefan Eßer } 431252884aeSStefan Eßer else { 43250696a6eSStefan Eßer min = ardx; 43350696a6eSStefan Eßer diff = brdx - ardx; 434252884aeSStefan Eßer max_num = b->num + diff; 435252884aeSStefan Eßer min_num = a->num; 436252884aeSStefan Eßer } 437252884aeSStefan Eßer 43844d4804dSStefan Eßer // Do a full limb-by-limb comparison. 439252884aeSStefan Eßer cmp = bc_num_compare(max_num, min_num, b_int + min); 440252884aeSStefan Eßer 44144d4804dSStefan Eßer // If we found a difference, return it based on state. 442252884aeSStefan Eßer if (cmp) return bc_num_neg((size_t) cmp, !a_max == !neg); 443252884aeSStefan Eßer 44444d4804dSStefan Eßer // If there was no difference, then the final step is to check which number 44544d4804dSStefan Eßer // has greater or lesser limbs beyond the other's. 446252884aeSStefan Eßer for (max_num -= diff, i = diff - 1; i < diff; --i) { 447252884aeSStefan Eßer if (max_num[i]) return bc_num_neg(1, !a_max == !neg); 448252884aeSStefan Eßer } 449252884aeSStefan Eßer 450252884aeSStefan Eßer return 0; 451252884aeSStefan Eßer } 452252884aeSStefan Eßer 453252884aeSStefan Eßer void bc_num_truncate(BcNum *restrict n, size_t places) { 454252884aeSStefan Eßer 45550696a6eSStefan Eßer size_t nrdx, places_rdx; 456252884aeSStefan Eßer 457252884aeSStefan Eßer if (!places) return; 458252884aeSStefan Eßer 45944d4804dSStefan Eßer // Grab these needed values; places_rdx is the rdx equivalent to places like 46044d4804dSStefan Eßer // rdx is to scale. 46150696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL(n); 46250696a6eSStefan Eßer places_rdx = nrdx ? nrdx - BC_NUM_RDX(n->scale - places) : 0; 46344d4804dSStefan Eßer 46444d4804dSStefan Eßer // We cannot truncate more places than we have. 465252884aeSStefan Eßer assert(places <= n->scale && (BC_NUM_ZERO(n) || places_rdx <= n->len)); 466252884aeSStefan Eßer 467252884aeSStefan Eßer n->scale -= places; 46850696a6eSStefan Eßer BC_NUM_RDX_SET(n, nrdx - places_rdx); 469252884aeSStefan Eßer 47044d4804dSStefan Eßer // Only when the number is nonzero do we need to do the hard stuff. 471252884aeSStefan Eßer if (BC_NUM_NONZERO(n)) { 472252884aeSStefan Eßer 473252884aeSStefan Eßer size_t pow; 474252884aeSStefan Eßer 47544d4804dSStefan Eßer // This calculates how many decimal digits are in the least significant 47644d4804dSStefan Eßer // limb. 477252884aeSStefan Eßer pow = n->scale % BC_BASE_DIGS; 478252884aeSStefan Eßer pow = pow ? BC_BASE_DIGS - pow : 0; 479252884aeSStefan Eßer pow = bc_num_pow10[pow]; 480252884aeSStefan Eßer 481252884aeSStefan Eßer n->len -= places_rdx; 48244d4804dSStefan Eßer 48344d4804dSStefan Eßer // We have to move limbs to maintain invariants. The limbs must begin at 48444d4804dSStefan Eßer // the beginning of the BcNum array. 485252884aeSStefan Eßer memmove(n->num, n->num + places_rdx, BC_NUM_SIZE(n->len)); 486252884aeSStefan Eßer 487252884aeSStefan Eßer // Clear the lower part of the last digit. 488252884aeSStefan Eßer if (BC_NUM_NONZERO(n)) n->num[0] -= n->num[0] % (BcDig) pow; 489252884aeSStefan Eßer 490252884aeSStefan Eßer bc_num_clean(n); 491252884aeSStefan Eßer } 492252884aeSStefan Eßer } 493252884aeSStefan Eßer 49450696a6eSStefan Eßer void bc_num_extend(BcNum *restrict n, size_t places) { 495252884aeSStefan Eßer 49650696a6eSStefan Eßer size_t nrdx, places_rdx; 497252884aeSStefan Eßer 498252884aeSStefan Eßer if (!places) return; 49944d4804dSStefan Eßer 50044d4804dSStefan Eßer // Easy case with zero; set the scale. 501252884aeSStefan Eßer if (BC_NUM_ZERO(n)) { 502252884aeSStefan Eßer n->scale += places; 503252884aeSStefan Eßer return; 504252884aeSStefan Eßer } 505252884aeSStefan Eßer 50644d4804dSStefan Eßer // Grab these needed values; places_rdx is the rdx equivalent to places like 50744d4804dSStefan Eßer // rdx is to scale. 50850696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL(n); 50950696a6eSStefan Eßer places_rdx = BC_NUM_RDX(places + n->scale) - nrdx; 510252884aeSStefan Eßer 51144d4804dSStefan Eßer // This is the hard case. We need to expand the number, move the limbs, and 51244d4804dSStefan Eßer // set the limbs that were just cleared. 513252884aeSStefan Eßer if (places_rdx) { 514252884aeSStefan Eßer bc_num_expand(n, bc_vm_growSize(n->len, places_rdx)); 515252884aeSStefan Eßer memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len)); 516252884aeSStefan Eßer memset(n->num, 0, BC_NUM_SIZE(places_rdx)); 517252884aeSStefan Eßer } 518252884aeSStefan Eßer 51944d4804dSStefan Eßer // Finally, set scale and rdx. 52050696a6eSStefan Eßer BC_NUM_RDX_SET(n, nrdx + places_rdx); 521252884aeSStefan Eßer n->scale += places; 522252884aeSStefan Eßer n->len += places_rdx; 523252884aeSStefan Eßer 52450696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(n) == BC_NUM_RDX(n->scale)); 525252884aeSStefan Eßer } 526252884aeSStefan Eßer 52744d4804dSStefan Eßer /** 52844d4804dSStefan Eßer * Retires (finishes) a multiplication or division operation. 52944d4804dSStefan Eßer */ 530252884aeSStefan Eßer static void bc_num_retireMul(BcNum *restrict n, size_t scale, 531252884aeSStefan Eßer bool neg1, bool neg2) 532252884aeSStefan Eßer { 53344d4804dSStefan Eßer // Make sure scale is correct. 534252884aeSStefan Eßer if (n->scale < scale) bc_num_extend(n, scale - n->scale); 535252884aeSStefan Eßer else bc_num_truncate(n, n->scale - scale); 536252884aeSStefan Eßer 537252884aeSStefan Eßer bc_num_clean(n); 53844d4804dSStefan Eßer 53944d4804dSStefan Eßer // We need to ensure rdx is correct. 54050696a6eSStefan Eßer if (BC_NUM_NONZERO(n)) n->rdx = BC_NUM_NEG_VAL(n, !neg1 != !neg2); 541252884aeSStefan Eßer } 542252884aeSStefan Eßer 54344d4804dSStefan Eßer /** 54444d4804dSStefan Eßer * Splits a number into two BcNum's. This is used in Karatsuba. 54544d4804dSStefan Eßer * @param n The number to split. 54644d4804dSStefan Eßer * @param idx The index to split at. 54744d4804dSStefan Eßer * @param a An out parameter; the low part of @a n. 54844d4804dSStefan Eßer * @param b An out parameter; the high part of @a n. 54944d4804dSStefan Eßer */ 550252884aeSStefan Eßer static void bc_num_split(const BcNum *restrict n, size_t idx, 551252884aeSStefan Eßer BcNum *restrict a, BcNum *restrict b) 552252884aeSStefan Eßer { 55344d4804dSStefan Eßer // We want a and b to be clear. 554252884aeSStefan Eßer assert(BC_NUM_ZERO(a)); 555252884aeSStefan Eßer assert(BC_NUM_ZERO(b)); 556252884aeSStefan Eßer 55744d4804dSStefan Eßer // The usual case. 558252884aeSStefan Eßer if (idx < n->len) { 559252884aeSStefan Eßer 56044d4804dSStefan Eßer // Set the fields first. 561252884aeSStefan Eßer b->len = n->len - idx; 562252884aeSStefan Eßer a->len = idx; 56350696a6eSStefan Eßer a->scale = b->scale = 0; 56450696a6eSStefan Eßer BC_NUM_RDX_SET(a, 0); 56550696a6eSStefan Eßer BC_NUM_RDX_SET(b, 0); 566252884aeSStefan Eßer 567252884aeSStefan Eßer assert(a->cap >= a->len); 568252884aeSStefan Eßer assert(b->cap >= b->len); 569252884aeSStefan Eßer 57044d4804dSStefan Eßer // Copy the arrays. This is not necessary for safety, but it is faster, 57144d4804dSStefan Eßer // for some reason. 572252884aeSStefan Eßer memcpy(b->num, n->num + idx, BC_NUM_SIZE(b->len)); 573252884aeSStefan Eßer memcpy(a->num, n->num, BC_NUM_SIZE(idx)); 574252884aeSStefan Eßer 575252884aeSStefan Eßer bc_num_clean(b); 576252884aeSStefan Eßer } 57744d4804dSStefan Eßer // If the index is weird, just skip the split. 578252884aeSStefan Eßer else bc_num_copy(a, n); 579252884aeSStefan Eßer 580252884aeSStefan Eßer bc_num_clean(a); 581252884aeSStefan Eßer } 582252884aeSStefan Eßer 58344d4804dSStefan Eßer /** 58444d4804dSStefan Eßer * Copies a number into another, but shifts the rdx so that the result number 58544d4804dSStefan Eßer * only sees the integer part of the source number. 58644d4804dSStefan Eßer * @param n The number to copy. 58744d4804dSStefan Eßer * @param r The result number with a shifted rdx, len, and num. 58844d4804dSStefan Eßer */ 58944d4804dSStefan Eßer static void bc_num_shiftRdx(const BcNum *restrict n, BcNum *restrict r) { 59044d4804dSStefan Eßer 59144d4804dSStefan Eßer size_t rdx = BC_NUM_RDX_VAL(n); 59244d4804dSStefan Eßer 59344d4804dSStefan Eßer r->len = n->len - rdx; 59444d4804dSStefan Eßer r->cap = n->cap - rdx; 59544d4804dSStefan Eßer r->num = n->num + rdx; 59644d4804dSStefan Eßer 59744d4804dSStefan Eßer BC_NUM_RDX_SET_NEG(r, 0, BC_NUM_NEG(n)); 59844d4804dSStefan Eßer r->scale = 0; 59944d4804dSStefan Eßer } 60044d4804dSStefan Eßer 60144d4804dSStefan Eßer /** 60244d4804dSStefan Eßer * Shifts a number so that all of the least significant limbs of the number are 60344d4804dSStefan Eßer * skipped. This must be undone by bc_num_unshiftZero(). 60444d4804dSStefan Eßer * @param n The number to shift. 60544d4804dSStefan Eßer */ 606252884aeSStefan Eßer static size_t bc_num_shiftZero(BcNum *restrict n) { 607252884aeSStefan Eßer 608252884aeSStefan Eßer size_t i; 609252884aeSStefan Eßer 61044d4804dSStefan Eßer // If we don't have an integer, that is a problem, but it's also a bug 61144d4804dSStefan Eßer // because the caller should have set everything up right. 61250696a6eSStefan Eßer assert(!BC_NUM_RDX_VAL(n) || BC_NUM_ZERO(n)); 613252884aeSStefan Eßer 614252884aeSStefan Eßer for (i = 0; i < n->len && !n->num[i]; ++i); 615252884aeSStefan Eßer 616252884aeSStefan Eßer n->len -= i; 617252884aeSStefan Eßer n->num += i; 618252884aeSStefan Eßer 619252884aeSStefan Eßer return i; 620252884aeSStefan Eßer } 621252884aeSStefan Eßer 62244d4804dSStefan Eßer /** 62344d4804dSStefan Eßer * Undo the damage done by bc_num_unshiftZero(). This must be called like all 62444d4804dSStefan Eßer * cleanup functions: after a label used by setjmp() and longjmp(). 62544d4804dSStefan Eßer * @param n The number to unshift. 62644d4804dSStefan Eßer * @param places_rdx The amount the number was originally shift. 62744d4804dSStefan Eßer */ 628252884aeSStefan Eßer static void bc_num_unshiftZero(BcNum *restrict n, size_t places_rdx) { 629252884aeSStefan Eßer n->len += places_rdx; 630252884aeSStefan Eßer n->num -= places_rdx; 631252884aeSStefan Eßer } 632252884aeSStefan Eßer 63344d4804dSStefan Eßer /** 63444d4804dSStefan Eßer * Shifts the digits right within a number by no more than BC_BASE_DIGS - 1. 63544d4804dSStefan Eßer * This is the final step on shifting numbers with the shift operators. It 63644d4804dSStefan Eßer * depends on the caller to shift the limbs properly because all it does is 63744d4804dSStefan Eßer * ensure that the rdx point is realigned to be between limbs. 63844d4804dSStefan Eßer * @param n The number to shift digits in. 63944d4804dSStefan Eßer * @param dig The number of places to shift right. 64044d4804dSStefan Eßer */ 641252884aeSStefan Eßer static void bc_num_shift(BcNum *restrict n, BcBigDig dig) { 642252884aeSStefan Eßer 643252884aeSStefan Eßer size_t i, len = n->len; 644252884aeSStefan Eßer BcBigDig carry = 0, pow; 645252884aeSStefan Eßer BcDig *ptr = n->num; 646252884aeSStefan Eßer 647252884aeSStefan Eßer assert(dig < BC_BASE_DIGS); 648252884aeSStefan Eßer 64944d4804dSStefan Eßer // Figure out the parameters for division. 650252884aeSStefan Eßer pow = bc_num_pow10[dig]; 651252884aeSStefan Eßer dig = bc_num_pow10[BC_BASE_DIGS - dig]; 652252884aeSStefan Eßer 65344d4804dSStefan Eßer // Run a series of divisions and mods with carries across the entire number 65444d4804dSStefan Eßer // array. This effectively shifts everything over. 655252884aeSStefan Eßer for (i = len - 1; i < len; --i) { 656252884aeSStefan Eßer BcBigDig in, temp; 657252884aeSStefan Eßer in = ((BcBigDig) ptr[i]); 658252884aeSStefan Eßer temp = carry * dig; 659252884aeSStefan Eßer carry = in % pow; 660252884aeSStefan Eßer ptr[i] = ((BcDig) (in / pow)) + (BcDig) temp; 661252884aeSStefan Eßer } 662252884aeSStefan Eßer 663252884aeSStefan Eßer assert(!carry); 664252884aeSStefan Eßer } 665252884aeSStefan Eßer 66644d4804dSStefan Eßer /** 66744d4804dSStefan Eßer * Shift a number left by a certain number of places. This is the workhorse of 66844d4804dSStefan Eßer * the left shift operator. 66944d4804dSStefan Eßer * @param n The number to shift left. 67044d4804dSStefan Eßer * @param places The amount of places to shift @a n left by. 67144d4804dSStefan Eßer */ 672252884aeSStefan Eßer static void bc_num_shiftLeft(BcNum *restrict n, size_t places) { 673252884aeSStefan Eßer 674252884aeSStefan Eßer BcBigDig dig; 675252884aeSStefan Eßer size_t places_rdx; 676252884aeSStefan Eßer bool shift; 677252884aeSStefan Eßer 678252884aeSStefan Eßer if (!places) return; 67944d4804dSStefan Eßer 68044d4804dSStefan Eßer // Make sure to grow the number if necessary. 681252884aeSStefan Eßer if (places > n->scale) { 682252884aeSStefan Eßer size_t size = bc_vm_growSize(BC_NUM_RDX(places - n->scale), n->len); 68344d4804dSStefan Eßer if (size > SIZE_MAX - 1) bc_err(BC_ERR_MATH_OVERFLOW); 684252884aeSStefan Eßer } 68544d4804dSStefan Eßer 68644d4804dSStefan Eßer // If zero, we can just set the scale and bail. 687252884aeSStefan Eßer if (BC_NUM_ZERO(n)) { 688252884aeSStefan Eßer if (n->scale >= places) n->scale -= places; 689252884aeSStefan Eßer else n->scale = 0; 690252884aeSStefan Eßer return; 691252884aeSStefan Eßer } 692252884aeSStefan Eßer 69344d4804dSStefan Eßer // When I changed bc to have multiple digits per limb, this was the hardest 69444d4804dSStefan Eßer // code to change. This and shift right. Make sure you understand this 69544d4804dSStefan Eßer // before attempting anything. 69644d4804dSStefan Eßer 69744d4804dSStefan Eßer // This is how many limbs we will shift. 698252884aeSStefan Eßer dig = (BcBigDig) (places % BC_BASE_DIGS); 699252884aeSStefan Eßer shift = (dig != 0); 70044d4804dSStefan Eßer 70144d4804dSStefan Eßer // Convert places to a rdx value. 702252884aeSStefan Eßer places_rdx = BC_NUM_RDX(places); 703252884aeSStefan Eßer 70444d4804dSStefan Eßer // If the number is not an integer, we need special care. The reason an 70544d4804dSStefan Eßer // integer doesn't is because left shift would only extend the integer, 70644d4804dSStefan Eßer // whereas a non-integer might have its fractional part eliminated or only 70744d4804dSStefan Eßer // partially eliminated. 708252884aeSStefan Eßer if (n->scale) { 709252884aeSStefan Eßer 71050696a6eSStefan Eßer size_t nrdx = BC_NUM_RDX_VAL(n); 71150696a6eSStefan Eßer 71244d4804dSStefan Eßer // If the number's rdx is bigger, that's the hard case. 71350696a6eSStefan Eßer if (nrdx >= places_rdx) { 714252884aeSStefan Eßer 715252884aeSStefan Eßer size_t mod = n->scale % BC_BASE_DIGS, revdig; 716252884aeSStefan Eßer 71744d4804dSStefan Eßer // We want mod to be in the range [1, BC_BASE_DIGS], not 71844d4804dSStefan Eßer // [0, BC_BASE_DIGS). 719252884aeSStefan Eßer mod = mod ? mod : BC_BASE_DIGS; 72044d4804dSStefan Eßer 72144d4804dSStefan Eßer // We need to reverse dig to get the actual number of digits. 722252884aeSStefan Eßer revdig = dig ? BC_BASE_DIGS - dig : 0; 723252884aeSStefan Eßer 72444d4804dSStefan Eßer // If the two overflow BC_BASE_DIGS, we need to move an extra place. 725252884aeSStefan Eßer if (mod + revdig > BC_BASE_DIGS) places_rdx = 1; 726252884aeSStefan Eßer else places_rdx = 0; 727252884aeSStefan Eßer } 72850696a6eSStefan Eßer else places_rdx -= nrdx; 729252884aeSStefan Eßer } 730252884aeSStefan Eßer 73144d4804dSStefan Eßer // If this is non-zero, we need an extra place, so expand, move, and set. 732252884aeSStefan Eßer if (places_rdx) { 733252884aeSStefan Eßer bc_num_expand(n, bc_vm_growSize(n->len, places_rdx)); 734252884aeSStefan Eßer memmove(n->num + places_rdx, n->num, BC_NUM_SIZE(n->len)); 735252884aeSStefan Eßer memset(n->num, 0, BC_NUM_SIZE(places_rdx)); 736252884aeSStefan Eßer n->len += places_rdx; 737252884aeSStefan Eßer } 738252884aeSStefan Eßer 73944d4804dSStefan Eßer // Set the scale appropriately. 74050696a6eSStefan Eßer if (places > n->scale) { 74150696a6eSStefan Eßer n->scale = 0; 74250696a6eSStefan Eßer BC_NUM_RDX_SET(n, 0); 74350696a6eSStefan Eßer } 744252884aeSStefan Eßer else { 745252884aeSStefan Eßer n->scale -= places; 74650696a6eSStefan Eßer BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale)); 747252884aeSStefan Eßer } 748252884aeSStefan Eßer 74944d4804dSStefan Eßer // Finally, shift within limbs. 750252884aeSStefan Eßer if (shift) bc_num_shift(n, BC_BASE_DIGS - dig); 751252884aeSStefan Eßer 752252884aeSStefan Eßer bc_num_clean(n); 753252884aeSStefan Eßer } 754252884aeSStefan Eßer 75550696a6eSStefan Eßer void bc_num_shiftRight(BcNum *restrict n, size_t places) { 756252884aeSStefan Eßer 757252884aeSStefan Eßer BcBigDig dig; 758252884aeSStefan Eßer size_t places_rdx, scale, scale_mod, int_len, expand; 759252884aeSStefan Eßer bool shift; 760252884aeSStefan Eßer 761252884aeSStefan Eßer if (!places) return; 76244d4804dSStefan Eßer 76344d4804dSStefan Eßer // If zero, we can just set the scale and bail. 764252884aeSStefan Eßer if (BC_NUM_ZERO(n)) { 765252884aeSStefan Eßer n->scale += places; 766252884aeSStefan Eßer bc_num_expand(n, BC_NUM_RDX(n->scale)); 767252884aeSStefan Eßer return; 768252884aeSStefan Eßer } 769252884aeSStefan Eßer 77044d4804dSStefan Eßer // Amount within a limb we have to shift by. 771252884aeSStefan Eßer dig = (BcBigDig) (places % BC_BASE_DIGS); 772252884aeSStefan Eßer shift = (dig != 0); 77344d4804dSStefan Eßer 774252884aeSStefan Eßer scale = n->scale; 77544d4804dSStefan Eßer 77644d4804dSStefan Eßer // Figure out how the scale is affected. 777252884aeSStefan Eßer scale_mod = scale % BC_BASE_DIGS; 778252884aeSStefan Eßer scale_mod = scale_mod ? scale_mod : BC_BASE_DIGS; 77944d4804dSStefan Eßer 78044d4804dSStefan Eßer // We need to know the int length and rdx for places. 781252884aeSStefan Eßer int_len = bc_num_int(n); 782252884aeSStefan Eßer places_rdx = BC_NUM_RDX(places); 783252884aeSStefan Eßer 78444d4804dSStefan Eßer // If we are going to shift past a limb boundary or not, set accordingly. 785252884aeSStefan Eßer if (scale_mod + dig > BC_BASE_DIGS) { 786252884aeSStefan Eßer expand = places_rdx - 1; 787252884aeSStefan Eßer places_rdx = 1; 788252884aeSStefan Eßer } 789252884aeSStefan Eßer else { 790252884aeSStefan Eßer expand = places_rdx; 791252884aeSStefan Eßer places_rdx = 0; 792252884aeSStefan Eßer } 793252884aeSStefan Eßer 79444d4804dSStefan Eßer // Clamp expanding. 795252884aeSStefan Eßer if (expand > int_len) expand -= int_len; 796252884aeSStefan Eßer else expand = 0; 797252884aeSStefan Eßer 79844d4804dSStefan Eßer // Extend, expand, and zero. 799252884aeSStefan Eßer bc_num_extend(n, places_rdx * BC_BASE_DIGS); 800252884aeSStefan Eßer bc_num_expand(n, bc_vm_growSize(expand, n->len)); 801252884aeSStefan Eßer memset(n->num + n->len, 0, BC_NUM_SIZE(expand)); 80244d4804dSStefan Eßer 80344d4804dSStefan Eßer // Set the fields. 804252884aeSStefan Eßer n->len += expand; 80550696a6eSStefan Eßer n->scale = 0; 80650696a6eSStefan Eßer BC_NUM_RDX_SET(n, 0); 807252884aeSStefan Eßer 80844d4804dSStefan Eßer // Finally, shift within limbs. 809252884aeSStefan Eßer if (shift) bc_num_shift(n, dig); 810252884aeSStefan Eßer 811252884aeSStefan Eßer n->scale = scale + places; 81250696a6eSStefan Eßer BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale)); 813252884aeSStefan Eßer 814252884aeSStefan Eßer bc_num_clean(n); 815252884aeSStefan Eßer 81650696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(n) <= n->len && n->len <= n->cap); 81750696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(n) == BC_NUM_RDX(n->scale)); 818252884aeSStefan Eßer } 819252884aeSStefan Eßer 82044d4804dSStefan Eßer /** 82144d4804dSStefan Eßer * Invert @a into @a b at the current scale. 82244d4804dSStefan Eßer * @param a The number to invert. 82344d4804dSStefan Eßer * @param b The return parameter. This must be preallocated. 82444d4804dSStefan Eßer * @param scale The current scale. 82544d4804dSStefan Eßer */ 82644d4804dSStefan Eßer static inline void bc_num_inv(BcNum *a, BcNum *b, size_t scale) { 827252884aeSStefan Eßer assert(BC_NUM_NONZERO(a)); 82844d4804dSStefan Eßer bc_num_div(&vm.one, a, b, scale); 82944d4804dSStefan Eßer } 830252884aeSStefan Eßer 83144d4804dSStefan Eßer /** 83244d4804dSStefan Eßer * Tests if a number is a integer with scale or not. Returns true if the number 83344d4804dSStefan Eßer * is not an integer. If it is, its integer shifted form is copied into the 83444d4804dSStefan Eßer * result parameter for use where only integers are allowed. 83544d4804dSStefan Eßer * @param n The integer to test and shift. 83644d4804dSStefan Eßer * @param r The number to store the shifted result into. This number should 83744d4804dSStefan Eßer * *not* be allocated. 83844d4804dSStefan Eßer * @return True if the number is a non-integer, false otherwise. 83944d4804dSStefan Eßer */ 84044d4804dSStefan Eßer static bool bc_num_nonInt(const BcNum *restrict n, BcNum *restrict r) { 841252884aeSStefan Eßer 84244d4804dSStefan Eßer bool zero; 84344d4804dSStefan Eßer size_t i, rdx = BC_NUM_RDX_VAL(n); 84444d4804dSStefan Eßer 84544d4804dSStefan Eßer if (!rdx) { 84644d4804dSStefan Eßer memcpy(r, n, sizeof(BcNum)); 84744d4804dSStefan Eßer return false; 84844d4804dSStefan Eßer } 84944d4804dSStefan Eßer 85044d4804dSStefan Eßer zero = true; 85144d4804dSStefan Eßer 85244d4804dSStefan Eßer for (i = 0; zero && i < rdx; ++i) zero = (n->num[i] == 0); 85344d4804dSStefan Eßer 85444d4804dSStefan Eßer if (BC_ERR(!zero)) return true; 85544d4804dSStefan Eßer 85644d4804dSStefan Eßer bc_num_shiftRdx(n, r); 85744d4804dSStefan Eßer 85844d4804dSStefan Eßer return false; 859252884aeSStefan Eßer } 860252884aeSStefan Eßer 861252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 86244d4804dSStefan Eßer 86344d4804dSStefan Eßer /** 86444d4804dSStefan Eßer * Execute common code for an operater that needs an integer for the second 86544d4804dSStefan Eßer * operand and return the integer operand as a BcBigDig. 86644d4804dSStefan Eßer * @param a The first operand. 86744d4804dSStefan Eßer * @param b The second operand. 86844d4804dSStefan Eßer * @param c The result operand. 86944d4804dSStefan Eßer * @return The second operand as a hardware integer. 87044d4804dSStefan Eßer */ 87144d4804dSStefan Eßer static BcBigDig bc_num_intop(const BcNum *a, const BcNum *b, BcNum *restrict c) 872252884aeSStefan Eßer { 87344d4804dSStefan Eßer BcNum temp; 87444d4804dSStefan Eßer 87544d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(b, &temp))) bc_err(BC_ERR_MATH_NON_INTEGER); 87644d4804dSStefan Eßer 877252884aeSStefan Eßer bc_num_copy(c, a); 87844d4804dSStefan Eßer 87944d4804dSStefan Eßer return bc_num_bigdig(&temp); 880252884aeSStefan Eßer } 881252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 882252884aeSStefan Eßer 88344d4804dSStefan Eßer /** 88444d4804dSStefan Eßer * This is the actual implementation of add *and* subtract. Since this function 88544d4804dSStefan Eßer * doesn't need to use scale (per the bc spec), I am hijacking it to say whether 88644d4804dSStefan Eßer * it's doing an add or a subtract. And then I convert substraction to addition 88744d4804dSStefan Eßer * of negative second operand. This is a BcNumBinOp function. 88844d4804dSStefan Eßer * @param a The first operand. 88944d4804dSStefan Eßer * @param b The second operand. 89044d4804dSStefan Eßer * @param c The return parameter. 89144d4804dSStefan Eßer * @param sub Non-zero for a subtract, zero for an add. 89244d4804dSStefan Eßer */ 893252884aeSStefan Eßer static void bc_num_as(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) { 894252884aeSStefan Eßer 895252884aeSStefan Eßer BcDig *ptr_c, *ptr_l, *ptr_r; 896252884aeSStefan Eßer size_t i, min_rdx, max_rdx, diff, a_int, b_int, min_len, max_len, max_int; 89750696a6eSStefan Eßer size_t len_l, len_r, ardx, brdx; 89850696a6eSStefan Eßer bool b_neg, do_sub, do_rev_sub, carry, c_neg; 899252884aeSStefan Eßer 900252884aeSStefan Eßer if (BC_NUM_ZERO(b)) { 901252884aeSStefan Eßer bc_num_copy(c, a); 902252884aeSStefan Eßer return; 903252884aeSStefan Eßer } 90444d4804dSStefan Eßer 905252884aeSStefan Eßer if (BC_NUM_ZERO(a)) { 906252884aeSStefan Eßer bc_num_copy(c, b); 90750696a6eSStefan Eßer c->rdx = BC_NUM_NEG_VAL(c, BC_NUM_NEG(b) != sub); 908252884aeSStefan Eßer return; 909252884aeSStefan Eßer } 910252884aeSStefan Eßer 911252884aeSStefan Eßer // Invert sign of b if it is to be subtracted. This operation must 91244d4804dSStefan Eßer // precede the tests for any of the operands being zero. 91350696a6eSStefan Eßer b_neg = (BC_NUM_NEG(b) != sub); 914252884aeSStefan Eßer 91544d4804dSStefan Eßer // Figure out if we will actually add the numbers if their signs are equal 91644d4804dSStefan Eßer // or subtract. 91750696a6eSStefan Eßer do_sub = (BC_NUM_NEG(a) != b_neg); 918252884aeSStefan Eßer 919252884aeSStefan Eßer a_int = bc_num_int(a); 920252884aeSStefan Eßer b_int = bc_num_int(b); 921252884aeSStefan Eßer max_int = BC_MAX(a_int, b_int); 922252884aeSStefan Eßer 92344d4804dSStefan Eßer // Figure out which number will have its last limbs copied (for addition) or 92444d4804dSStefan Eßer // subtracted (for subtraction). 92550696a6eSStefan Eßer ardx = BC_NUM_RDX_VAL(a); 92650696a6eSStefan Eßer brdx = BC_NUM_RDX_VAL(b); 92750696a6eSStefan Eßer min_rdx = BC_MIN(ardx, brdx); 92850696a6eSStefan Eßer max_rdx = BC_MAX(ardx, brdx); 929252884aeSStefan Eßer diff = max_rdx - min_rdx; 930252884aeSStefan Eßer 931252884aeSStefan Eßer max_len = max_int + max_rdx; 932252884aeSStefan Eßer 933252884aeSStefan Eßer if (do_sub) { 934252884aeSStefan Eßer 935252884aeSStefan Eßer // Check whether b has to be subtracted from a or a from b. 936252884aeSStefan Eßer if (a_int != b_int) do_rev_sub = (a_int < b_int); 93750696a6eSStefan Eßer else if (ardx > brdx) 938252884aeSStefan Eßer do_rev_sub = (bc_num_compare(a->num + diff, b->num, b->len) < 0); 939252884aeSStefan Eßer else 940252884aeSStefan Eßer do_rev_sub = (bc_num_compare(a->num, b->num + diff, a->len) <= 0); 941252884aeSStefan Eßer } 942252884aeSStefan Eßer else { 943252884aeSStefan Eßer 944252884aeSStefan Eßer // The result array of the addition might come out one element 945252884aeSStefan Eßer // longer than the bigger of the operand arrays. 946252884aeSStefan Eßer max_len += 1; 947252884aeSStefan Eßer do_rev_sub = (a_int < b_int); 948252884aeSStefan Eßer } 949252884aeSStefan Eßer 950252884aeSStefan Eßer assert(max_len <= c->cap); 951252884aeSStefan Eßer 95244d4804dSStefan Eßer // Cache values for simple code later. 953252884aeSStefan Eßer if (do_rev_sub) { 954252884aeSStefan Eßer ptr_l = b->num; 955252884aeSStefan Eßer ptr_r = a->num; 956252884aeSStefan Eßer len_l = b->len; 957252884aeSStefan Eßer len_r = a->len; 958252884aeSStefan Eßer } 959252884aeSStefan Eßer else { 960252884aeSStefan Eßer ptr_l = a->num; 961252884aeSStefan Eßer ptr_r = b->num; 962252884aeSStefan Eßer len_l = a->len; 963252884aeSStefan Eßer len_r = b->len; 964252884aeSStefan Eßer } 965252884aeSStefan Eßer 966252884aeSStefan Eßer ptr_c = c->num; 967252884aeSStefan Eßer carry = false; 968252884aeSStefan Eßer 96944d4804dSStefan Eßer // This is true if the numbers have a different number of limbs after the 97044d4804dSStefan Eßer // decimal point. 971252884aeSStefan Eßer if (diff) { 972252884aeSStefan Eßer 973252884aeSStefan Eßer // If the rdx values of the operands do not match, the result will 974252884aeSStefan Eßer // have low end elements that are the positive or negative trailing 975252884aeSStefan Eßer // elements of the operand with higher rdx value. 97650696a6eSStefan Eßer if ((ardx > brdx) != do_rev_sub) { 977252884aeSStefan Eßer 97850696a6eSStefan Eßer // !do_rev_sub && ardx > brdx || do_rev_sub && brdx > ardx 979252884aeSStefan Eßer // The left operand has BcDig values that need to be copied, 980252884aeSStefan Eßer // either from a or from b (in case of a reversed subtraction). 981252884aeSStefan Eßer memcpy(ptr_c, ptr_l, BC_NUM_SIZE(diff)); 982252884aeSStefan Eßer ptr_l += diff; 983252884aeSStefan Eßer len_l -= diff; 984252884aeSStefan Eßer } 985252884aeSStefan Eßer else { 986252884aeSStefan Eßer 987252884aeSStefan Eßer // The right operand has BcDig values that need to be copied 988252884aeSStefan Eßer // or subtracted from zero (in case of a subtraction). 989252884aeSStefan Eßer if (do_sub) { 990252884aeSStefan Eßer 99150696a6eSStefan Eßer // do_sub (do_rev_sub && ardx > brdx || 99250696a6eSStefan Eßer // !do_rev_sub && brdx > ardx) 993252884aeSStefan Eßer for (i = 0; i < diff; i++) 994252884aeSStefan Eßer ptr_c[i] = bc_num_subDigits(0, ptr_r[i], &carry); 995252884aeSStefan Eßer } 996252884aeSStefan Eßer else { 997252884aeSStefan Eßer 99850696a6eSStefan Eßer // !do_sub && brdx > ardx 999252884aeSStefan Eßer memcpy(ptr_c, ptr_r, BC_NUM_SIZE(diff)); 1000252884aeSStefan Eßer } 1001252884aeSStefan Eßer 100244d4804dSStefan Eßer // Future code needs to ignore the limbs we just did. 1003252884aeSStefan Eßer ptr_r += diff; 1004252884aeSStefan Eßer len_r -= diff; 1005252884aeSStefan Eßer } 1006252884aeSStefan Eßer 100744d4804dSStefan Eßer // The return value pointer needs to ignore what we just did. 1008252884aeSStefan Eßer ptr_c += diff; 1009252884aeSStefan Eßer } 1010252884aeSStefan Eßer 101144d4804dSStefan Eßer // This is the length that can be directly added/subtracted. 1012252884aeSStefan Eßer min_len = BC_MIN(len_l, len_r); 1013252884aeSStefan Eßer 1014252884aeSStefan Eßer // After dealing with possible low array elements that depend on only one 101544d4804dSStefan Eßer // operand above, the actual add or subtract can be performed as if the rdx 101644d4804dSStefan Eßer // of both operands was the same. 101744d4804dSStefan Eßer // 1018252884aeSStefan Eßer // Inlining takes care of eliminating constant zero arguments to 1019252884aeSStefan Eßer // addDigit/subDigit (checked in disassembly of resulting bc binary 1020252884aeSStefan Eßer // compiled with gcc and clang). 1021252884aeSStefan Eßer if (do_sub) { 102244d4804dSStefan Eßer 102344d4804dSStefan Eßer // Actual subtraction. 1024252884aeSStefan Eßer for (i = 0; i < min_len; ++i) 1025252884aeSStefan Eßer ptr_c[i] = bc_num_subDigits(ptr_l[i], ptr_r[i], &carry); 102644d4804dSStefan Eßer 102744d4804dSStefan Eßer // Finishing the limbs beyond the direct subtraction. 1028252884aeSStefan Eßer for (; i < len_l; ++i) ptr_c[i] = bc_num_subDigits(ptr_l[i], 0, &carry); 1029252884aeSStefan Eßer } 1030252884aeSStefan Eßer else { 103144d4804dSStefan Eßer 103244d4804dSStefan Eßer // Actual addition. 1033252884aeSStefan Eßer for (i = 0; i < min_len; ++i) 1034252884aeSStefan Eßer ptr_c[i] = bc_num_addDigits(ptr_l[i], ptr_r[i], &carry); 103544d4804dSStefan Eßer 103644d4804dSStefan Eßer // Finishing the limbs beyond the direct addition. 1037252884aeSStefan Eßer for (; i < len_l; ++i) ptr_c[i] = bc_num_addDigits(ptr_l[i], 0, &carry); 103844d4804dSStefan Eßer 103944d4804dSStefan Eßer // Addition can create an extra limb. We take care of that here. 1040252884aeSStefan Eßer ptr_c[i] = bc_num_addDigits(0, 0, &carry); 1041252884aeSStefan Eßer } 1042252884aeSStefan Eßer 1043252884aeSStefan Eßer assert(carry == false); 1044252884aeSStefan Eßer 1045252884aeSStefan Eßer // The result has the same sign as a, unless the operation was a 1046252884aeSStefan Eßer // reverse subtraction (b - a). 104750696a6eSStefan Eßer c_neg = BC_NUM_NEG(a) != (do_sub && do_rev_sub); 104850696a6eSStefan Eßer BC_NUM_RDX_SET_NEG(c, max_rdx, c_neg); 1049252884aeSStefan Eßer c->len = max_len; 1050252884aeSStefan Eßer c->scale = BC_MAX(a->scale, b->scale); 1051252884aeSStefan Eßer 1052252884aeSStefan Eßer bc_num_clean(c); 1053252884aeSStefan Eßer } 1054252884aeSStefan Eßer 105544d4804dSStefan Eßer /** 105644d4804dSStefan Eßer * The simple multiplication that karatsuba dishes out to when the length of the 105744d4804dSStefan Eßer * numbers gets low enough. This doesn't use scale because it treats the 105844d4804dSStefan Eßer * operands as though they are integers. 105944d4804dSStefan Eßer * @param a The first operand. 106044d4804dSStefan Eßer * @param b The second operand. 106144d4804dSStefan Eßer * @param c The return parameter. 106244d4804dSStefan Eßer */ 106344d4804dSStefan Eßer static void bc_num_m_simp(const BcNum *a, const BcNum *b, BcNum *restrict c) { 106444d4804dSStefan Eßer 1065252884aeSStefan Eßer size_t i, alen = a->len, blen = b->len, clen; 1066252884aeSStefan Eßer BcDig *ptr_a = a->num, *ptr_b = b->num, *ptr_c; 1067252884aeSStefan Eßer BcBigDig sum = 0, carry = 0; 1068252884aeSStefan Eßer 1069252884aeSStefan Eßer assert(sizeof(sum) >= sizeof(BcDig) * 2); 107050696a6eSStefan Eßer assert(!BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b)); 1071252884aeSStefan Eßer 107244d4804dSStefan Eßer // Make sure c is big enough. 1073252884aeSStefan Eßer clen = bc_vm_growSize(alen, blen); 1074252884aeSStefan Eßer bc_num_expand(c, bc_vm_growSize(clen, 1)); 1075252884aeSStefan Eßer 107644d4804dSStefan Eßer // If we don't memset, then we might have uninitialized data use later. 1077252884aeSStefan Eßer ptr_c = c->num; 1078252884aeSStefan Eßer memset(ptr_c, 0, BC_NUM_SIZE(c->cap)); 1079252884aeSStefan Eßer 108044d4804dSStefan Eßer // This is the actual multiplication loop. It uses the lattice form of long 108144d4804dSStefan Eßer // multiplication (see the explanation on the web page at 108244d4804dSStefan Eßer // https://knilt.arcc.albany.edu/What_is_Lattice_Multiplication or the 108344d4804dSStefan Eßer // explanation at Wikipedia). 1084252884aeSStefan Eßer for (i = 0; i < clen; ++i) { 1085252884aeSStefan Eßer 1086252884aeSStefan Eßer ssize_t sidx = (ssize_t) (i - blen + 1); 108744d4804dSStefan Eßer size_t j, k; 1088252884aeSStefan Eßer 108944d4804dSStefan Eßer // These are the start indices. 109044d4804dSStefan Eßer j = (size_t) BC_MAX(0, sidx); 109144d4804dSStefan Eßer k = BC_MIN(i, blen - 1); 109244d4804dSStefan Eßer 109344d4804dSStefan Eßer // On every iteration of this loop, a multiplication happens, then the 109444d4804dSStefan Eßer // sum is automatically calculated. 1095252884aeSStefan Eßer for (; j < alen && k < blen; ++j, --k) { 1096252884aeSStefan Eßer 1097252884aeSStefan Eßer sum += ((BcBigDig) ptr_a[j]) * ((BcBigDig) ptr_b[k]); 1098252884aeSStefan Eßer 1099252884aeSStefan Eßer if (sum >= ((BcBigDig) BC_BASE_POW) * BC_BASE_POW) { 1100252884aeSStefan Eßer carry += sum / BC_BASE_POW; 1101252884aeSStefan Eßer sum %= BC_BASE_POW; 1102252884aeSStefan Eßer } 1103252884aeSStefan Eßer } 1104252884aeSStefan Eßer 110544d4804dSStefan Eßer // Calculate the carry. 1106252884aeSStefan Eßer if (sum >= BC_BASE_POW) { 1107252884aeSStefan Eßer carry += sum / BC_BASE_POW; 1108252884aeSStefan Eßer sum %= BC_BASE_POW; 1109252884aeSStefan Eßer } 1110252884aeSStefan Eßer 111144d4804dSStefan Eßer // Store and set up for next iteration. 1112252884aeSStefan Eßer ptr_c[i] = (BcDig) sum; 1113252884aeSStefan Eßer assert(ptr_c[i] < BC_BASE_POW); 1114252884aeSStefan Eßer sum = carry; 1115252884aeSStefan Eßer carry = 0; 1116252884aeSStefan Eßer } 1117252884aeSStefan Eßer 1118252884aeSStefan Eßer // This should always be true because there should be no carry on the last 1119252884aeSStefan Eßer // digit; multiplication never goes above the sum of both lengths. 1120252884aeSStefan Eßer assert(!sum); 1121252884aeSStefan Eßer 1122252884aeSStefan Eßer c->len = clen; 1123252884aeSStefan Eßer } 1124252884aeSStefan Eßer 112544d4804dSStefan Eßer /** 112644d4804dSStefan Eßer * Does a shifted add or subtract for Karatsuba below. This calls either 112744d4804dSStefan Eßer * bc_num_addArrays() or bc_num_subArrays(). 112844d4804dSStefan Eßer * @param n An in/out parameter; the first operand and return parameter. 112944d4804dSStefan Eßer * @param a The second operand. 113044d4804dSStefan Eßer * @param shift The amount to shift @a n by when adding/subtracting. 113144d4804dSStefan Eßer * @param op The function to call, either bc_num_addArrays() or 113244d4804dSStefan Eßer * bc_num_subArrays(). 113344d4804dSStefan Eßer */ 1134252884aeSStefan Eßer static void bc_num_shiftAddSub(BcNum *restrict n, const BcNum *restrict a, 1135252884aeSStefan Eßer size_t shift, BcNumShiftAddOp op) 1136252884aeSStefan Eßer { 1137252884aeSStefan Eßer assert(n->len >= shift + a->len); 113850696a6eSStefan Eßer assert(!BC_NUM_RDX_VAL(n) && !BC_NUM_RDX_VAL(a)); 1139252884aeSStefan Eßer op(n->num + shift, a->num, a->len); 1140252884aeSStefan Eßer } 1141252884aeSStefan Eßer 114244d4804dSStefan Eßer /** 114344d4804dSStefan Eßer * Implements the Karatsuba algorithm. 114444d4804dSStefan Eßer */ 114544d4804dSStefan Eßer static void bc_num_k(const BcNum *a, const BcNum *b, BcNum *restrict c) { 1146252884aeSStefan Eßer 1147252884aeSStefan Eßer size_t max, max2, total; 1148252884aeSStefan Eßer BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp; 1149252884aeSStefan Eßer BcDig *digs, *dig_ptr; 1150252884aeSStefan Eßer BcNumShiftAddOp op; 1151252884aeSStefan Eßer bool aone = BC_NUM_ONE(a); 1152252884aeSStefan Eßer 1153252884aeSStefan Eßer assert(BC_NUM_ZERO(c)); 1154252884aeSStefan Eßer 1155252884aeSStefan Eßer if (BC_NUM_ZERO(a) || BC_NUM_ZERO(b)) return; 115644d4804dSStefan Eßer 1157252884aeSStefan Eßer if (aone || BC_NUM_ONE(b)) { 1158252884aeSStefan Eßer bc_num_copy(c, aone ? b : a); 115950696a6eSStefan Eßer if ((aone && BC_NUM_NEG(a)) || BC_NUM_NEG(b)) BC_NUM_NEG_TGL(c); 1160252884aeSStefan Eßer return; 1161252884aeSStefan Eßer } 116244d4804dSStefan Eßer 116344d4804dSStefan Eßer // Shell out to the simple algorithm with certain conditions. 1164252884aeSStefan Eßer if (a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN) { 1165252884aeSStefan Eßer bc_num_m_simp(a, b, c); 1166252884aeSStefan Eßer return; 1167252884aeSStefan Eßer } 1168252884aeSStefan Eßer 116944d4804dSStefan Eßer // We need to calculate the max size of the numbers that can result from the 117044d4804dSStefan Eßer // operations. 1171252884aeSStefan Eßer max = BC_MAX(a->len, b->len); 1172252884aeSStefan Eßer max = BC_MAX(max, BC_NUM_DEF_SIZE); 1173252884aeSStefan Eßer max2 = (max + 1) / 2; 1174252884aeSStefan Eßer 117544d4804dSStefan Eßer // Calculate the space needed for all of the temporary allocations. We do 117644d4804dSStefan Eßer // this to just allocate once. 1177252884aeSStefan Eßer total = bc_vm_arraySize(BC_NUM_KARATSUBA_ALLOCS, max); 1178252884aeSStefan Eßer 1179252884aeSStefan Eßer BC_SIG_LOCK; 1180252884aeSStefan Eßer 118144d4804dSStefan Eßer // Allocate space for all of the temporaries. 1182252884aeSStefan Eßer digs = dig_ptr = bc_vm_malloc(BC_NUM_SIZE(total)); 1183252884aeSStefan Eßer 118444d4804dSStefan Eßer // Set up the temporaries. 1185252884aeSStefan Eßer bc_num_setup(&l1, dig_ptr, max); 1186252884aeSStefan Eßer dig_ptr += max; 1187252884aeSStefan Eßer bc_num_setup(&h1, dig_ptr, max); 1188252884aeSStefan Eßer dig_ptr += max; 1189252884aeSStefan Eßer bc_num_setup(&l2, dig_ptr, max); 1190252884aeSStefan Eßer dig_ptr += max; 1191252884aeSStefan Eßer bc_num_setup(&h2, dig_ptr, max); 1192252884aeSStefan Eßer dig_ptr += max; 1193252884aeSStefan Eßer bc_num_setup(&m1, dig_ptr, max); 1194252884aeSStefan Eßer dig_ptr += max; 1195252884aeSStefan Eßer bc_num_setup(&m2, dig_ptr, max); 119644d4804dSStefan Eßer 119744d4804dSStefan Eßer // Some temporaries need the ability to grow, so we allocate them 119844d4804dSStefan Eßer // separately. 1199252884aeSStefan Eßer max = bc_vm_growSize(max, 1); 1200252884aeSStefan Eßer bc_num_init(&z0, max); 1201252884aeSStefan Eßer bc_num_init(&z1, max); 1202252884aeSStefan Eßer bc_num_init(&z2, max); 1203252884aeSStefan Eßer max = bc_vm_growSize(max, max) + 1; 1204252884aeSStefan Eßer bc_num_init(&temp, max); 1205252884aeSStefan Eßer 1206252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 1207252884aeSStefan Eßer 1208252884aeSStefan Eßer BC_SIG_UNLOCK; 1209252884aeSStefan Eßer 121044d4804dSStefan Eßer // First, set up c. 1211252884aeSStefan Eßer bc_num_expand(c, max); 1212252884aeSStefan Eßer c->len = max; 1213252884aeSStefan Eßer memset(c->num, 0, BC_NUM_SIZE(c->len)); 1214252884aeSStefan Eßer 121544d4804dSStefan Eßer // Split the parameters. 121644d4804dSStefan Eßer bc_num_split(a, max2, &l1, &h1); 121744d4804dSStefan Eßer bc_num_split(b, max2, &l2, &h2); 121844d4804dSStefan Eßer 121944d4804dSStefan Eßer // Do the subtraction. 1220252884aeSStefan Eßer bc_num_sub(&h1, &l1, &m1, 0); 1221252884aeSStefan Eßer bc_num_sub(&l2, &h2, &m2, 0); 1222252884aeSStefan Eßer 122344d4804dSStefan Eßer // The if statements below are there for efficiency reasons. The best way to 122444d4804dSStefan Eßer // understand them is to understand the Karatsuba algorithm because now that 122544d4804dSStefan Eßer // the ollocations and splits are done, the algorithm is pretty 122644d4804dSStefan Eßer // straightforward. 122744d4804dSStefan Eßer 1228252884aeSStefan Eßer if (BC_NUM_NONZERO(&h1) && BC_NUM_NONZERO(&h2)) { 1229252884aeSStefan Eßer 123050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(h1)); 123150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(h2)); 123250696a6eSStefan Eßer 1233252884aeSStefan Eßer bc_num_m(&h1, &h2, &z2, 0); 1234252884aeSStefan Eßer bc_num_clean(&z2); 1235252884aeSStefan Eßer 1236252884aeSStefan Eßer bc_num_shiftAddSub(c, &z2, max2 * 2, bc_num_addArrays); 1237252884aeSStefan Eßer bc_num_shiftAddSub(c, &z2, max2, bc_num_addArrays); 1238252884aeSStefan Eßer } 1239252884aeSStefan Eßer 1240252884aeSStefan Eßer if (BC_NUM_NONZERO(&l1) && BC_NUM_NONZERO(&l2)) { 1241252884aeSStefan Eßer 124250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(l1)); 124350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(l2)); 124450696a6eSStefan Eßer 1245252884aeSStefan Eßer bc_num_m(&l1, &l2, &z0, 0); 1246252884aeSStefan Eßer bc_num_clean(&z0); 1247252884aeSStefan Eßer 1248252884aeSStefan Eßer bc_num_shiftAddSub(c, &z0, max2, bc_num_addArrays); 1249252884aeSStefan Eßer bc_num_shiftAddSub(c, &z0, 0, bc_num_addArrays); 1250252884aeSStefan Eßer } 1251252884aeSStefan Eßer 1252252884aeSStefan Eßer if (BC_NUM_NONZERO(&m1) && BC_NUM_NONZERO(&m2)) { 1253252884aeSStefan Eßer 125450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(m1)); 125550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(m1)); 125650696a6eSStefan Eßer 1257252884aeSStefan Eßer bc_num_m(&m1, &m2, &z1, 0); 1258252884aeSStefan Eßer bc_num_clean(&z1); 1259252884aeSStefan Eßer 126050696a6eSStefan Eßer op = (BC_NUM_NEG_NP(m1) != BC_NUM_NEG_NP(m2)) ? 126150696a6eSStefan Eßer bc_num_subArrays : bc_num_addArrays; 1262252884aeSStefan Eßer bc_num_shiftAddSub(c, &z1, max2, op); 1263252884aeSStefan Eßer } 1264252884aeSStefan Eßer 1265252884aeSStefan Eßer err: 1266252884aeSStefan Eßer BC_SIG_MAYLOCK; 1267252884aeSStefan Eßer free(digs); 1268252884aeSStefan Eßer bc_num_free(&temp); 1269252884aeSStefan Eßer bc_num_free(&z2); 1270252884aeSStefan Eßer bc_num_free(&z1); 1271252884aeSStefan Eßer bc_num_free(&z0); 1272252884aeSStefan Eßer BC_LONGJMP_CONT; 1273252884aeSStefan Eßer } 1274252884aeSStefan Eßer 127544d4804dSStefan Eßer /** 127644d4804dSStefan Eßer * Does checks for Karatsuba. It also changes things to ensure that the 127744d4804dSStefan Eßer * Karatsuba and simple multiplication can treat the numbers as integers. This 127844d4804dSStefan Eßer * is a BcNumBinOp function. 127944d4804dSStefan Eßer * @param a The first operand. 128044d4804dSStefan Eßer * @param b The second operand. 128144d4804dSStefan Eßer * @param c The return parameter. 128244d4804dSStefan Eßer * @param scale The current scale. 128344d4804dSStefan Eßer */ 1284252884aeSStefan Eßer static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1285252884aeSStefan Eßer 1286252884aeSStefan Eßer BcNum cpa, cpb; 1287252884aeSStefan Eßer size_t ascale, bscale, ardx, brdx, azero = 0, bzero = 0, zero, len, rscale; 1288252884aeSStefan Eßer 128950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 129050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 129150696a6eSStefan Eßer 1292252884aeSStefan Eßer bc_num_zero(c); 129344d4804dSStefan Eßer 1294252884aeSStefan Eßer ascale = a->scale; 1295252884aeSStefan Eßer bscale = b->scale; 129644d4804dSStefan Eßer 129744d4804dSStefan Eßer // This sets the final scale according to the bc spec. 1298252884aeSStefan Eßer scale = BC_MAX(scale, ascale); 1299252884aeSStefan Eßer scale = BC_MAX(scale, bscale); 1300252884aeSStefan Eßer rscale = ascale + bscale; 1301252884aeSStefan Eßer scale = BC_MIN(rscale, scale); 1302252884aeSStefan Eßer 130344d4804dSStefan Eßer // If this condition is true, we can use bc_num_mulArray(), which would be 130444d4804dSStefan Eßer // much faster. 1305252884aeSStefan Eßer if ((a->len == 1 || b->len == 1) && !a->rdx && !b->rdx) { 1306252884aeSStefan Eßer 1307252884aeSStefan Eßer BcNum *operand; 1308252884aeSStefan Eßer BcBigDig dig; 1309252884aeSStefan Eßer 131044d4804dSStefan Eßer // Set the correct operands. 1311252884aeSStefan Eßer if (a->len == 1) { 1312252884aeSStefan Eßer dig = (BcBigDig) a->num[0]; 1313252884aeSStefan Eßer operand = b; 1314252884aeSStefan Eßer } 1315252884aeSStefan Eßer else { 1316252884aeSStefan Eßer dig = (BcBigDig) b->num[0]; 1317252884aeSStefan Eßer operand = a; 1318252884aeSStefan Eßer } 1319252884aeSStefan Eßer 1320252884aeSStefan Eßer bc_num_mulArray(operand, dig, c); 1321252884aeSStefan Eßer 132244d4804dSStefan Eßer // Need to make sure the sign is correct. 132350696a6eSStefan Eßer if (BC_NUM_NONZERO(c)) 132450696a6eSStefan Eßer c->rdx = BC_NUM_NEG_VAL(c, BC_NUM_NEG(a) != BC_NUM_NEG(b)); 1325252884aeSStefan Eßer 1326252884aeSStefan Eßer return; 1327252884aeSStefan Eßer } 1328252884aeSStefan Eßer 132950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 133050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 133150696a6eSStefan Eßer 1332252884aeSStefan Eßer BC_SIG_LOCK; 1333252884aeSStefan Eßer 133444d4804dSStefan Eßer // We need copies because of all of the mutation needed to make Karatsuba 133544d4804dSStefan Eßer // think the numbers are integers. 133650696a6eSStefan Eßer bc_num_init(&cpa, a->len + BC_NUM_RDX_VAL(a)); 133750696a6eSStefan Eßer bc_num_init(&cpb, b->len + BC_NUM_RDX_VAL(b)); 1338252884aeSStefan Eßer 1339252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 1340252884aeSStefan Eßer 1341252884aeSStefan Eßer BC_SIG_UNLOCK; 1342252884aeSStefan Eßer 1343252884aeSStefan Eßer bc_num_copy(&cpa, a); 1344252884aeSStefan Eßer bc_num_copy(&cpb, b); 1345252884aeSStefan Eßer 134650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(cpa)); 134750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(cpb)); 1348252884aeSStefan Eßer 134950696a6eSStefan Eßer BC_NUM_NEG_CLR_NP(cpa); 135050696a6eSStefan Eßer BC_NUM_NEG_CLR_NP(cpb); 135150696a6eSStefan Eßer 135250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(cpa)); 135350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(cpb)); 135450696a6eSStefan Eßer 135544d4804dSStefan Eßer // These are what makes them appear like integers. 135650696a6eSStefan Eßer ardx = BC_NUM_RDX_VAL_NP(cpa) * BC_BASE_DIGS; 1357252884aeSStefan Eßer bc_num_shiftLeft(&cpa, ardx); 1358252884aeSStefan Eßer 135950696a6eSStefan Eßer brdx = BC_NUM_RDX_VAL_NP(cpb) * BC_BASE_DIGS; 1360252884aeSStefan Eßer bc_num_shiftLeft(&cpb, brdx); 1361252884aeSStefan Eßer 1362252884aeSStefan Eßer // We need to reset the jump here because azero and bzero are used in the 1363252884aeSStefan Eßer // cleanup, and local variables are not guaranteed to be the same after a 1364252884aeSStefan Eßer // jump. 1365252884aeSStefan Eßer BC_SIG_LOCK; 1366252884aeSStefan Eßer 1367252884aeSStefan Eßer BC_UNSETJMP; 1368252884aeSStefan Eßer 136944d4804dSStefan Eßer // We want to ignore zero limbs. 1370252884aeSStefan Eßer azero = bc_num_shiftZero(&cpa); 1371252884aeSStefan Eßer bzero = bc_num_shiftZero(&cpb); 1372252884aeSStefan Eßer 1373252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 1374252884aeSStefan Eßer 1375252884aeSStefan Eßer BC_SIG_UNLOCK; 1376252884aeSStefan Eßer 1377252884aeSStefan Eßer bc_num_clean(&cpa); 1378252884aeSStefan Eßer bc_num_clean(&cpb); 1379252884aeSStefan Eßer 1380252884aeSStefan Eßer bc_num_k(&cpa, &cpb, c); 1381252884aeSStefan Eßer 138244d4804dSStefan Eßer // The return parameter needs to have its scale set. This is the start. It 138344d4804dSStefan Eßer // also needs to be shifted by the same amount as a and b have limbs after 138444d4804dSStefan Eßer // the decimal point. 1385252884aeSStefan Eßer zero = bc_vm_growSize(azero, bzero); 1386252884aeSStefan Eßer len = bc_vm_growSize(c->len, zero); 1387252884aeSStefan Eßer 1388252884aeSStefan Eßer bc_num_expand(c, len); 138944d4804dSStefan Eßer 139044d4804dSStefan Eßer // Shift c based on the limbs after the decimal point in a and b. 1391252884aeSStefan Eßer bc_num_shiftLeft(c, (len - c->len) * BC_BASE_DIGS); 1392252884aeSStefan Eßer bc_num_shiftRight(c, ardx + brdx); 1393252884aeSStefan Eßer 139450696a6eSStefan Eßer bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b)); 1395252884aeSStefan Eßer 1396252884aeSStefan Eßer err: 1397252884aeSStefan Eßer BC_SIG_MAYLOCK; 1398252884aeSStefan Eßer bc_num_unshiftZero(&cpb, bzero); 1399252884aeSStefan Eßer bc_num_free(&cpb); 1400252884aeSStefan Eßer bc_num_unshiftZero(&cpa, azero); 1401252884aeSStefan Eßer bc_num_free(&cpa); 1402252884aeSStefan Eßer BC_LONGJMP_CONT; 1403252884aeSStefan Eßer } 1404252884aeSStefan Eßer 140544d4804dSStefan Eßer /** 140644d4804dSStefan Eßer * Returns true if the BcDig array has non-zero limbs, false otherwise. 140744d4804dSStefan Eßer * @param a The array to test. 140844d4804dSStefan Eßer * @param len The length of the array. 140944d4804dSStefan Eßer * @return True if @a has any non-zero limbs, false otherwise. 141044d4804dSStefan Eßer */ 1411252884aeSStefan Eßer static bool bc_num_nonZeroDig(BcDig *restrict a, size_t len) { 1412252884aeSStefan Eßer size_t i; 1413252884aeSStefan Eßer bool nonzero = false; 1414252884aeSStefan Eßer for (i = len - 1; !nonzero && i < len; --i) nonzero = (a[i] != 0); 1415252884aeSStefan Eßer return nonzero; 1416252884aeSStefan Eßer } 1417252884aeSStefan Eßer 141844d4804dSStefan Eßer /** 141944d4804dSStefan Eßer * Compares a BcDig array against a BcNum. This is especially suited for 142044d4804dSStefan Eßer * division. Returns >0 if @a a is greater than @a b, <0 if it is less, and =0 142144d4804dSStefan Eßer * if they are equal. 142244d4804dSStefan Eßer * @param a The array. 142344d4804dSStefan Eßer * @param b The number. 142444d4804dSStefan Eßer * @param len The length to assume the arrays are. This is always less than the 142544d4804dSStefan Eßer * actual length because of how this is implemented. 142644d4804dSStefan Eßer */ 1427252884aeSStefan Eßer static ssize_t bc_num_divCmp(const BcDig *a, const BcNum *b, size_t len) { 1428252884aeSStefan Eßer 1429252884aeSStefan Eßer ssize_t cmp; 1430252884aeSStefan Eßer 1431252884aeSStefan Eßer if (b->len > len && a[len]) cmp = bc_num_compare(a, b->num, len + 1); 1432252884aeSStefan Eßer else if (b->len <= len) { 1433252884aeSStefan Eßer if (a[len]) cmp = 1; 1434252884aeSStefan Eßer else cmp = bc_num_compare(a, b->num, len); 1435252884aeSStefan Eßer } 1436252884aeSStefan Eßer else cmp = -1; 1437252884aeSStefan Eßer 1438252884aeSStefan Eßer return cmp; 1439252884aeSStefan Eßer } 1440252884aeSStefan Eßer 144144d4804dSStefan Eßer /** 144244d4804dSStefan Eßer * Extends the two operands of a division by BC_BASE_DIGS minus the number of 144344d4804dSStefan Eßer * digits in the divisor estimate. In other words, it is shifting the numbers in 144444d4804dSStefan Eßer * order to force the divisor estimate to fill the limb. 144544d4804dSStefan Eßer * @param a The first operand. 144644d4804dSStefan Eßer * @param b The second operand. 144744d4804dSStefan Eßer * @param divisor The divisor estimate. 144844d4804dSStefan Eßer */ 1449252884aeSStefan Eßer static void bc_num_divExtend(BcNum *restrict a, BcNum *restrict b, 1450252884aeSStefan Eßer BcBigDig divisor) 1451252884aeSStefan Eßer { 1452252884aeSStefan Eßer size_t pow; 1453252884aeSStefan Eßer 1454252884aeSStefan Eßer assert(divisor < BC_BASE_POW); 1455252884aeSStefan Eßer 1456252884aeSStefan Eßer pow = BC_BASE_DIGS - bc_num_log10((size_t) divisor); 1457252884aeSStefan Eßer 1458252884aeSStefan Eßer bc_num_shiftLeft(a, pow); 1459252884aeSStefan Eßer bc_num_shiftLeft(b, pow); 1460252884aeSStefan Eßer } 1461252884aeSStefan Eßer 146244d4804dSStefan Eßer /** 146344d4804dSStefan Eßer * Actually does division. This is a rewrite of my original code by Stefan Esser 146444d4804dSStefan Eßer * from FreeBSD. 146544d4804dSStefan Eßer * @param a The first operand. 146644d4804dSStefan Eßer * @param b The second operand. 146744d4804dSStefan Eßer * @param c The return parameter. 146844d4804dSStefan Eßer * @param scale The current scale. 146944d4804dSStefan Eßer */ 1470252884aeSStefan Eßer static void bc_num_d_long(BcNum *restrict a, BcNum *restrict b, 1471252884aeSStefan Eßer BcNum *restrict c, size_t scale) 1472252884aeSStefan Eßer { 1473252884aeSStefan Eßer BcBigDig divisor; 1474252884aeSStefan Eßer size_t len, end, i, rdx; 1475252884aeSStefan Eßer BcNum cpb; 1476252884aeSStefan Eßer bool nonzero = false; 1477252884aeSStefan Eßer 1478252884aeSStefan Eßer assert(b->len < a->len); 147944d4804dSStefan Eßer 1480252884aeSStefan Eßer len = b->len; 1481252884aeSStefan Eßer end = a->len - len; 148244d4804dSStefan Eßer 1483252884aeSStefan Eßer assert(len >= 1); 1484252884aeSStefan Eßer 148544d4804dSStefan Eßer // This is a final time to make sure c is big enough and that its array is 148644d4804dSStefan Eßer // properly zeroed. 1487252884aeSStefan Eßer bc_num_expand(c, a->len); 1488252884aeSStefan Eßer memset(c->num, 0, c->cap * sizeof(BcDig)); 1489252884aeSStefan Eßer 149044d4804dSStefan Eßer // Setup. 149150696a6eSStefan Eßer BC_NUM_RDX_SET(c, BC_NUM_RDX_VAL(a)); 1492252884aeSStefan Eßer c->scale = a->scale; 1493252884aeSStefan Eßer c->len = a->len; 1494252884aeSStefan Eßer 149544d4804dSStefan Eßer // This is pulling the most significant limb of b in order to establish a 149644d4804dSStefan Eßer // good "estimate" for the actual divisor. 1497252884aeSStefan Eßer divisor = (BcBigDig) b->num[len - 1]; 1498252884aeSStefan Eßer 149944d4804dSStefan Eßer // The entire bit of code in this if statement is to tighten the estimate of 150044d4804dSStefan Eßer // the divisor. The condition asks if b has any other non-zero limbs. 1501252884aeSStefan Eßer if (len > 1 && bc_num_nonZeroDig(b->num, len - 1)) { 1502252884aeSStefan Eßer 150344d4804dSStefan Eßer // This takes a little bit of understanding. The "10*BC_BASE_DIGS/6+1" 150444d4804dSStefan Eßer // results in either 16 for 64-bit 9-digit limbs or 7 for 32-bit 4-digit 150544d4804dSStefan Eßer // limbs. Then it shifts a 1 by that many, which in both cases, puts the 150644d4804dSStefan Eßer // result above *half* of the max value a limb can store. Basically, 150744d4804dSStefan Eßer // this quickly calculates if the divisor is greater than half the max 150844d4804dSStefan Eßer // of a limb. 1509252884aeSStefan Eßer nonzero = (divisor > 1 << ((10 * BC_BASE_DIGS) / 6 + 1)); 1510252884aeSStefan Eßer 151144d4804dSStefan Eßer // If the divisor is *not* greater than half the limb... 1512252884aeSStefan Eßer if (!nonzero) { 1513252884aeSStefan Eßer 151444d4804dSStefan Eßer // Extend the parameters by the number of missing digits in the 151544d4804dSStefan Eßer // divisor. 1516252884aeSStefan Eßer bc_num_divExtend(a, b, divisor); 1517252884aeSStefan Eßer 151844d4804dSStefan Eßer // Check bc_num_d(). In there, we grow a again and again. We do it 151944d4804dSStefan Eßer // again here; we *always* want to be sure it is big enough. 1520252884aeSStefan Eßer len = BC_MAX(a->len, b->len); 1521252884aeSStefan Eßer bc_num_expand(a, len + 1); 1522252884aeSStefan Eßer 152344d4804dSStefan Eßer // Make a have a zero most significant limb to match the len. 1524252884aeSStefan Eßer if (len + 1 > a->len) a->len = len + 1; 1525252884aeSStefan Eßer 152644d4804dSStefan Eßer // Grab the new divisor estimate, new because the shift has made it 152744d4804dSStefan Eßer // different. 1528252884aeSStefan Eßer len = b->len; 1529252884aeSStefan Eßer end = a->len - len; 1530252884aeSStefan Eßer divisor = (BcBigDig) b->num[len - 1]; 1531252884aeSStefan Eßer 1532252884aeSStefan Eßer nonzero = bc_num_nonZeroDig(b->num, len - 1); 1533252884aeSStefan Eßer } 1534252884aeSStefan Eßer } 1535252884aeSStefan Eßer 153644d4804dSStefan Eßer // If b has other nonzero limbs, we want the divisor to be one higher, so 153744d4804dSStefan Eßer // that it is an upper bound. 1538252884aeSStefan Eßer divisor += nonzero; 1539252884aeSStefan Eßer 154044d4804dSStefan Eßer // Make sure c can fit the new length. 1541252884aeSStefan Eßer bc_num_expand(c, a->len); 1542252884aeSStefan Eßer memset(c->num, 0, BC_NUM_SIZE(c->cap)); 1543252884aeSStefan Eßer 1544252884aeSStefan Eßer assert(c->scale >= scale); 154550696a6eSStefan Eßer rdx = BC_NUM_RDX_VAL(c) - BC_NUM_RDX(scale); 1546252884aeSStefan Eßer 1547252884aeSStefan Eßer BC_SIG_LOCK; 1548252884aeSStefan Eßer 1549252884aeSStefan Eßer bc_num_init(&cpb, len + 1); 1550252884aeSStefan Eßer 1551252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 1552252884aeSStefan Eßer 1553252884aeSStefan Eßer BC_SIG_UNLOCK; 1554252884aeSStefan Eßer 155544d4804dSStefan Eßer // This is the actual division loop. 155644d4804dSStefan Eßer for (i = end - 1; i < end && i >= rdx && BC_NUM_NONZERO(a); --i) { 1557252884aeSStefan Eßer 1558252884aeSStefan Eßer ssize_t cmp; 1559252884aeSStefan Eßer BcDig *n; 1560252884aeSStefan Eßer BcBigDig result; 1561252884aeSStefan Eßer 1562252884aeSStefan Eßer n = a->num + i; 1563252884aeSStefan Eßer assert(n >= a->num); 1564252884aeSStefan Eßer result = 0; 1565252884aeSStefan Eßer 1566252884aeSStefan Eßer cmp = bc_num_divCmp(n, b, len); 1567252884aeSStefan Eßer 156844d4804dSStefan Eßer // This is true if n is greater than b, which means that division can 156944d4804dSStefan Eßer // proceed, so this inner loop is the part that implements one instance 157044d4804dSStefan Eßer // of the division. 1571252884aeSStefan Eßer while (cmp >= 0) { 1572252884aeSStefan Eßer 157344d4804dSStefan Eßer BcBigDig n1, dividend, quotient; 1574252884aeSStefan Eßer 157544d4804dSStefan Eßer // These should be named obviously enough. Just imagine that it's a 157644d4804dSStefan Eßer // division of one limb. Because that's what it is. 1577252884aeSStefan Eßer n1 = (BcBigDig) n[len]; 1578252884aeSStefan Eßer dividend = n1 * BC_BASE_POW + (BcBigDig) n[len - 1]; 157944d4804dSStefan Eßer quotient = (dividend / divisor); 1580252884aeSStefan Eßer 158144d4804dSStefan Eßer // If this is true, then we can just subtract. Remember: setting 158244d4804dSStefan Eßer // quotient to 1 is not bad because we already know that n is 158344d4804dSStefan Eßer // greater than b. 158444d4804dSStefan Eßer if (quotient <= 1) { 158544d4804dSStefan Eßer quotient = 1; 1586252884aeSStefan Eßer bc_num_subArrays(n, b->num, len); 1587252884aeSStefan Eßer } 1588252884aeSStefan Eßer else { 1589252884aeSStefan Eßer 159044d4804dSStefan Eßer assert(quotient <= BC_BASE_POW); 1591252884aeSStefan Eßer 159244d4804dSStefan Eßer // We need to multiply and subtract for a quotient above 1. 159344d4804dSStefan Eßer bc_num_mulArray(b, (BcBigDig) quotient, &cpb); 1594252884aeSStefan Eßer bc_num_subArrays(n, cpb.num, cpb.len); 1595252884aeSStefan Eßer } 1596252884aeSStefan Eßer 159744d4804dSStefan Eßer // The result is the *real* quotient, by the way, but it might take 159844d4804dSStefan Eßer // multiple trips around this loop to get it. 159944d4804dSStefan Eßer result += quotient; 1600252884aeSStefan Eßer assert(result <= BC_BASE_POW); 1601252884aeSStefan Eßer 160244d4804dSStefan Eßer // And here's why it might take multiple trips: n might *still* be 160344d4804dSStefan Eßer // greater than b. So we have to loop again. That's what this is 160444d4804dSStefan Eßer // setting up for: the condition of the while loop. 1605252884aeSStefan Eßer if (nonzero) cmp = bc_num_divCmp(n, b, len); 1606252884aeSStefan Eßer else cmp = -1; 1607252884aeSStefan Eßer } 1608252884aeSStefan Eßer 1609252884aeSStefan Eßer assert(result < BC_BASE_POW); 1610252884aeSStefan Eßer 161144d4804dSStefan Eßer // Store the actual limb quotient. 1612252884aeSStefan Eßer c->num[i] = (BcDig) result; 1613252884aeSStefan Eßer } 1614252884aeSStefan Eßer 1615252884aeSStefan Eßer err: 1616252884aeSStefan Eßer BC_SIG_MAYLOCK; 1617252884aeSStefan Eßer bc_num_free(&cpb); 1618252884aeSStefan Eßer BC_LONGJMP_CONT; 1619252884aeSStefan Eßer } 1620252884aeSStefan Eßer 162144d4804dSStefan Eßer /** 162244d4804dSStefan Eßer * Implements division. This is a BcNumBinOp function. 162344d4804dSStefan Eßer * @param a The first operand. 162444d4804dSStefan Eßer * @param b The second operand. 162544d4804dSStefan Eßer * @param c The return parameter. 162644d4804dSStefan Eßer * @param scale The current scale. 162744d4804dSStefan Eßer */ 1628252884aeSStefan Eßer static void bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1629252884aeSStefan Eßer 163050696a6eSStefan Eßer size_t len, cpardx; 1631252884aeSStefan Eßer BcNum cpa, cpb; 1632252884aeSStefan Eßer 163344d4804dSStefan Eßer if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); 163444d4804dSStefan Eßer 1635252884aeSStefan Eßer if (BC_NUM_ZERO(a)) { 1636252884aeSStefan Eßer bc_num_setToZero(c, scale); 1637252884aeSStefan Eßer return; 1638252884aeSStefan Eßer } 163944d4804dSStefan Eßer 1640252884aeSStefan Eßer if (BC_NUM_ONE(b)) { 1641252884aeSStefan Eßer bc_num_copy(c, a); 164250696a6eSStefan Eßer bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b)); 1643252884aeSStefan Eßer return; 1644252884aeSStefan Eßer } 164544d4804dSStefan Eßer 164644d4804dSStefan Eßer // If this is true, we can use bc_num_divArray(), which would be faster. 164750696a6eSStefan Eßer if (!BC_NUM_RDX_VAL(a) && !BC_NUM_RDX_VAL(b) && b->len == 1 && !scale) { 1648252884aeSStefan Eßer BcBigDig rem; 1649252884aeSStefan Eßer bc_num_divArray(a, (BcBigDig) b->num[0], c, &rem); 165050696a6eSStefan Eßer bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b)); 1651252884aeSStefan Eßer return; 1652252884aeSStefan Eßer } 1653252884aeSStefan Eßer 165450696a6eSStefan Eßer len = bc_num_divReq(a, b, scale); 1655252884aeSStefan Eßer 1656252884aeSStefan Eßer BC_SIG_LOCK; 1657252884aeSStefan Eßer 165844d4804dSStefan Eßer // Initialize copies of the parameters. We want the length of the first 165944d4804dSStefan Eßer // operand copy to be as big as the result because of the way the division 166044d4804dSStefan Eßer // is implemented. 1661252884aeSStefan Eßer bc_num_init(&cpa, len); 1662252884aeSStefan Eßer bc_num_copy(&cpa, a); 1663252884aeSStefan Eßer bc_num_createCopy(&cpb, b); 1664252884aeSStefan Eßer 1665252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 1666252884aeSStefan Eßer 1667252884aeSStefan Eßer BC_SIG_UNLOCK; 1668252884aeSStefan Eßer 1669252884aeSStefan Eßer len = b->len; 1670252884aeSStefan Eßer 167144d4804dSStefan Eßer // Like the above comment, we want the copy of the first parameter to be 167244d4804dSStefan Eßer // larger than the second parameter. 1673252884aeSStefan Eßer if (len > cpa.len) { 1674252884aeSStefan Eßer bc_num_expand(&cpa, bc_vm_growSize(len, 2)); 1675252884aeSStefan Eßer bc_num_extend(&cpa, (len - cpa.len) * BC_BASE_DIGS); 1676252884aeSStefan Eßer } 1677252884aeSStefan Eßer 167850696a6eSStefan Eßer cpardx = BC_NUM_RDX_VAL_NP(cpa); 167950696a6eSStefan Eßer cpa.scale = cpardx * BC_BASE_DIGS; 1680252884aeSStefan Eßer 168144d4804dSStefan Eßer // This is just setting up the scale in preparation for the division. 1682252884aeSStefan Eßer bc_num_extend(&cpa, b->scale); 168350696a6eSStefan Eßer cpardx = BC_NUM_RDX_VAL_NP(cpa) - BC_NUM_RDX(b->scale); 168450696a6eSStefan Eßer BC_NUM_RDX_SET_NP(cpa, cpardx); 168550696a6eSStefan Eßer cpa.scale = cpardx * BC_BASE_DIGS; 1686252884aeSStefan Eßer 168744d4804dSStefan Eßer // Once again, just setting things up, this time to match scale. 1688252884aeSStefan Eßer if (scale > cpa.scale) { 1689252884aeSStefan Eßer bc_num_extend(&cpa, scale); 169050696a6eSStefan Eßer cpardx = BC_NUM_RDX_VAL_NP(cpa); 169150696a6eSStefan Eßer cpa.scale = cpardx * BC_BASE_DIGS; 1692252884aeSStefan Eßer } 1693252884aeSStefan Eßer 169444d4804dSStefan Eßer // Grow if necessary. 1695252884aeSStefan Eßer if (cpa.cap == cpa.len) bc_num_expand(&cpa, bc_vm_growSize(cpa.len, 1)); 1696252884aeSStefan Eßer 1697252884aeSStefan Eßer // We want an extra zero in front to make things simpler. 1698252884aeSStefan Eßer cpa.num[cpa.len++] = 0; 1699252884aeSStefan Eßer 170044d4804dSStefan Eßer // Still setting things up. Why all of these things are needed is not 170144d4804dSStefan Eßer // something that can be easily explained, but it has to do with making the 170244d4804dSStefan Eßer // actual algorithm easier to understand because it can assume a lot of 170344d4804dSStefan Eßer // things. Thus, you should view all of this setup code as establishing 170444d4804dSStefan Eßer // assumptions for bc_num_d_long(), where the actual division happens. 170544d4804dSStefan Eßer if (cpardx == cpa.len) cpa.len = bc_num_nonZeroLen(&cpa); 170644d4804dSStefan Eßer if (BC_NUM_RDX_VAL_NP(cpb) == cpb.len) cpb.len = bc_num_nonZeroLen(&cpb); 170750696a6eSStefan Eßer cpb.scale = 0; 170850696a6eSStefan Eßer BC_NUM_RDX_SET_NP(cpb, 0); 1709252884aeSStefan Eßer 1710252884aeSStefan Eßer bc_num_d_long(&cpa, &cpb, c, scale); 1711252884aeSStefan Eßer 171250696a6eSStefan Eßer bc_num_retireMul(c, scale, BC_NUM_NEG(a), BC_NUM_NEG(b)); 1713252884aeSStefan Eßer 1714252884aeSStefan Eßer err: 1715252884aeSStefan Eßer BC_SIG_MAYLOCK; 1716252884aeSStefan Eßer bc_num_free(&cpb); 1717252884aeSStefan Eßer bc_num_free(&cpa); 1718252884aeSStefan Eßer BC_LONGJMP_CONT; 1719252884aeSStefan Eßer } 1720252884aeSStefan Eßer 172144d4804dSStefan Eßer /** 172244d4804dSStefan Eßer * Implements divmod. This is the actual modulus function; since modulus 172344d4804dSStefan Eßer * requires a division anyway, this returns the quotient and modulus. Either can 172444d4804dSStefan Eßer * be thrown out as desired. 172544d4804dSStefan Eßer * @param a The first operand. 172644d4804dSStefan Eßer * @param b The second operand. 172744d4804dSStefan Eßer * @param c The return parameter for the quotient. 172844d4804dSStefan Eßer * @param d The return parameter for the modulus. 172944d4804dSStefan Eßer * @param scale The current scale. 173044d4804dSStefan Eßer * @param ts The scale that the operation should be done to. Yes, it's not 173144d4804dSStefan Eßer * necessarily the same as scale, per the bc spec. 173244d4804dSStefan Eßer */ 1733252884aeSStefan Eßer static void bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c, 1734252884aeSStefan Eßer BcNum *restrict d, size_t scale, size_t ts) 1735252884aeSStefan Eßer { 1736252884aeSStefan Eßer BcNum temp; 1737252884aeSStefan Eßer bool neg; 1738252884aeSStefan Eßer 173944d4804dSStefan Eßer if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); 174044d4804dSStefan Eßer 1741252884aeSStefan Eßer if (BC_NUM_ZERO(a)) { 1742252884aeSStefan Eßer bc_num_setToZero(c, ts); 1743252884aeSStefan Eßer bc_num_setToZero(d, ts); 1744252884aeSStefan Eßer return; 1745252884aeSStefan Eßer } 1746252884aeSStefan Eßer 1747252884aeSStefan Eßer BC_SIG_LOCK; 1748252884aeSStefan Eßer 1749252884aeSStefan Eßer bc_num_init(&temp, d->cap); 1750252884aeSStefan Eßer 1751252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 1752252884aeSStefan Eßer 1753252884aeSStefan Eßer BC_SIG_UNLOCK; 1754252884aeSStefan Eßer 175544d4804dSStefan Eßer // Division. 1756252884aeSStefan Eßer bc_num_d(a, b, c, scale); 1757252884aeSStefan Eßer 175844d4804dSStefan Eßer // We want an extra digit so we can safely truncate. 1759252884aeSStefan Eßer if (scale) scale = ts + 1; 1760252884aeSStefan Eßer 176150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(c)); 176250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 176350696a6eSStefan Eßer 176444d4804dSStefan Eßer // Implement the rest of the (a - (a / b) * b) formula. 1765252884aeSStefan Eßer bc_num_m(c, b, &temp, scale); 1766252884aeSStefan Eßer bc_num_sub(a, &temp, d, scale); 1767252884aeSStefan Eßer 176844d4804dSStefan Eßer // Extend if necessary. 1769252884aeSStefan Eßer if (ts > d->scale && BC_NUM_NONZERO(d)) bc_num_extend(d, ts - d->scale); 1770252884aeSStefan Eßer 177150696a6eSStefan Eßer neg = BC_NUM_NEG(d); 177250696a6eSStefan Eßer bc_num_retireMul(d, ts, BC_NUM_NEG(a), BC_NUM_NEG(b)); 177350696a6eSStefan Eßer d->rdx = BC_NUM_NEG_VAL(d, BC_NUM_NONZERO(d) ? neg : false); 1774252884aeSStefan Eßer 1775252884aeSStefan Eßer err: 1776252884aeSStefan Eßer BC_SIG_MAYLOCK; 1777252884aeSStefan Eßer bc_num_free(&temp); 1778252884aeSStefan Eßer BC_LONGJMP_CONT; 1779252884aeSStefan Eßer } 1780252884aeSStefan Eßer 178144d4804dSStefan Eßer /** 178244d4804dSStefan Eßer * Implements modulus/remainder. (Yes, I know they are different, but not in the 178344d4804dSStefan Eßer * context of bc.) This is a BcNumBinOp function. 178444d4804dSStefan Eßer * @param a The first operand. 178544d4804dSStefan Eßer * @param b The second operand. 178644d4804dSStefan Eßer * @param c The return parameter. 178744d4804dSStefan Eßer * @param scale The current scale. 178844d4804dSStefan Eßer */ 1789252884aeSStefan Eßer static void bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1790252884aeSStefan Eßer 1791252884aeSStefan Eßer BcNum c1; 1792252884aeSStefan Eßer size_t ts; 1793252884aeSStefan Eßer 1794252884aeSStefan Eßer ts = bc_vm_growSize(scale, b->scale); 1795252884aeSStefan Eßer ts = BC_MAX(ts, a->scale); 1796252884aeSStefan Eßer 1797252884aeSStefan Eßer BC_SIG_LOCK; 1798252884aeSStefan Eßer 179944d4804dSStefan Eßer // Need a temp for the quotient. 1800252884aeSStefan Eßer bc_num_init(&c1, bc_num_mulReq(a, b, ts)); 1801252884aeSStefan Eßer 1802252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 1803252884aeSStefan Eßer 1804252884aeSStefan Eßer BC_SIG_UNLOCK; 1805252884aeSStefan Eßer 1806252884aeSStefan Eßer bc_num_r(a, b, &c1, c, scale, ts); 1807252884aeSStefan Eßer 1808252884aeSStefan Eßer err: 1809252884aeSStefan Eßer BC_SIG_MAYLOCK; 1810252884aeSStefan Eßer bc_num_free(&c1); 1811252884aeSStefan Eßer BC_LONGJMP_CONT; 1812252884aeSStefan Eßer } 1813252884aeSStefan Eßer 181444d4804dSStefan Eßer /** 181544d4804dSStefan Eßer * Implements power (exponentiation). This is a BcNumBinOp function. 181644d4804dSStefan Eßer * @param a The first operand. 181744d4804dSStefan Eßer * @param b The second operand. 181844d4804dSStefan Eßer * @param c The return parameter. 181944d4804dSStefan Eßer * @param scale The current scale. 182044d4804dSStefan Eßer */ 1821252884aeSStefan Eßer static void bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1822252884aeSStefan Eßer 182344d4804dSStefan Eßer BcNum copy, btemp; 182444d4804dSStefan Eßer BcBigDig exp; 182544d4804dSStefan Eßer size_t powrdx, resrdx; 182644d4804dSStefan Eßer bool neg; 1827252884aeSStefan Eßer 182844d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(b, &btemp))) bc_err(BC_ERR_MATH_NON_INTEGER); 1829252884aeSStefan Eßer 183044d4804dSStefan Eßer if (BC_NUM_ZERO(&btemp)) { 1831252884aeSStefan Eßer bc_num_one(c); 1832252884aeSStefan Eßer return; 1833252884aeSStefan Eßer } 183444d4804dSStefan Eßer 1835252884aeSStefan Eßer if (BC_NUM_ZERO(a)) { 183644d4804dSStefan Eßer if (BC_NUM_NEG_NP(btemp)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); 1837252884aeSStefan Eßer bc_num_setToZero(c, scale); 1838252884aeSStefan Eßer return; 1839252884aeSStefan Eßer } 184044d4804dSStefan Eßer 184144d4804dSStefan Eßer if (BC_NUM_ONE(&btemp)) { 184244d4804dSStefan Eßer if (!BC_NUM_NEG_NP(btemp)) bc_num_copy(c, a); 1843252884aeSStefan Eßer else bc_num_inv(a, c, scale); 1844252884aeSStefan Eßer return; 1845252884aeSStefan Eßer } 1846252884aeSStefan Eßer 184744d4804dSStefan Eßer neg = BC_NUM_NEG_NP(btemp); 184844d4804dSStefan Eßer BC_NUM_NEG_CLR_NP(btemp); 1849252884aeSStefan Eßer 185044d4804dSStefan Eßer exp = bc_num_bigdig(&btemp); 185144d4804dSStefan Eßer 185244d4804dSStefan Eßer BC_SIG_LOCK; 1853252884aeSStefan Eßer 1854252884aeSStefan Eßer bc_num_createCopy(©, a); 1855252884aeSStefan Eßer 1856252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 1857252884aeSStefan Eßer 1858252884aeSStefan Eßer BC_SIG_UNLOCK; 1859252884aeSStefan Eßer 186044d4804dSStefan Eßer // If this is true, then we do not have to do a division, and we need to 186144d4804dSStefan Eßer // set scale accordingly. 1862252884aeSStefan Eßer if (!neg) { 186344d4804dSStefan Eßer size_t max = BC_MAX(scale, a->scale), scalepow; 186444d4804dSStefan Eßer scalepow = bc_num_mulOverflow(a->scale, exp); 1865252884aeSStefan Eßer scale = BC_MIN(scalepow, max); 1866252884aeSStefan Eßer } 1867252884aeSStefan Eßer 186844d4804dSStefan Eßer // This is only implementing the first exponentiation by squaring, until it 186944d4804dSStefan Eßer // reaches the first time where the square is actually used. 187044d4804dSStefan Eßer for (powrdx = a->scale; !(exp & 1); exp >>= 1) { 1871252884aeSStefan Eßer powrdx <<= 1; 187250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(copy)); 1873252884aeSStefan Eßer bc_num_mul(©, ©, ©, powrdx); 1874252884aeSStefan Eßer } 1875252884aeSStefan Eßer 187644d4804dSStefan Eßer // Make c a copy of copy for the purpose of saving the squares that should 187744d4804dSStefan Eßer // be saved. 1878252884aeSStefan Eßer bc_num_copy(c, ©); 1879252884aeSStefan Eßer resrdx = powrdx; 1880252884aeSStefan Eßer 188144d4804dSStefan Eßer // Now finish the exponentiation by squaring, this time saving the squares 188244d4804dSStefan Eßer // as necessary. 188344d4804dSStefan Eßer while (exp >>= 1) { 1884252884aeSStefan Eßer 1885252884aeSStefan Eßer powrdx <<= 1; 188650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(copy)); 1887252884aeSStefan Eßer bc_num_mul(©, ©, ©, powrdx); 1888252884aeSStefan Eßer 188944d4804dSStefan Eßer // If this is true, we want to save that particular square. This does 189044d4804dSStefan Eßer // that by multiplying c with copy. 189144d4804dSStefan Eßer if (exp & 1) { 1892252884aeSStefan Eßer resrdx += powrdx; 189350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(c)); 189450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(copy)); 1895252884aeSStefan Eßer bc_num_mul(c, ©, c, resrdx); 1896252884aeSStefan Eßer } 1897252884aeSStefan Eßer } 1898252884aeSStefan Eßer 189944d4804dSStefan Eßer // Invert if necessary. 1900252884aeSStefan Eßer if (neg) bc_num_inv(c, c, scale); 1901252884aeSStefan Eßer 190244d4804dSStefan Eßer // Truncate if necessary. 1903252884aeSStefan Eßer if (c->scale > scale) bc_num_truncate(c, c->scale - scale); 1904252884aeSStefan Eßer 190544d4804dSStefan Eßer bc_num_clean(c); 1906252884aeSStefan Eßer 1907252884aeSStefan Eßer err: 1908252884aeSStefan Eßer BC_SIG_MAYLOCK; 1909252884aeSStefan Eßer bc_num_free(©); 1910252884aeSStefan Eßer BC_LONGJMP_CONT; 1911252884aeSStefan Eßer } 1912252884aeSStefan Eßer 1913252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 191444d4804dSStefan Eßer /** 191544d4804dSStefan Eßer * Implements the places operator. This is a BcNumBinOp function. 191644d4804dSStefan Eßer * @param a The first operand. 191744d4804dSStefan Eßer * @param b The second operand. 191844d4804dSStefan Eßer * @param c The return parameter. 191944d4804dSStefan Eßer * @param scale The current scale. 192044d4804dSStefan Eßer */ 1921252884aeSStefan Eßer static void bc_num_place(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1922252884aeSStefan Eßer 192344d4804dSStefan Eßer BcBigDig val; 1924252884aeSStefan Eßer 1925252884aeSStefan Eßer BC_UNUSED(scale); 1926252884aeSStefan Eßer 192744d4804dSStefan Eßer val = bc_num_intop(a, b, c); 1928252884aeSStefan Eßer 192944d4804dSStefan Eßer // Just truncate or extend as appropriate. 1930252884aeSStefan Eßer if (val < c->scale) bc_num_truncate(c, c->scale - val); 1931252884aeSStefan Eßer else if (val > c->scale) bc_num_extend(c, val - c->scale); 1932252884aeSStefan Eßer } 1933252884aeSStefan Eßer 193444d4804dSStefan Eßer /** 193544d4804dSStefan Eßer * Implements the left shift operator. This is a BcNumBinOp function. 193644d4804dSStefan Eßer */ 1937252884aeSStefan Eßer static void bc_num_left(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1938252884aeSStefan Eßer 193944d4804dSStefan Eßer BcBigDig val; 1940252884aeSStefan Eßer 1941252884aeSStefan Eßer BC_UNUSED(scale); 1942252884aeSStefan Eßer 194344d4804dSStefan Eßer val = bc_num_intop(a, b, c); 1944252884aeSStefan Eßer 1945252884aeSStefan Eßer bc_num_shiftLeft(c, (size_t) val); 1946252884aeSStefan Eßer } 1947252884aeSStefan Eßer 194844d4804dSStefan Eßer /** 194944d4804dSStefan Eßer * Implements the right shift operator. This is a BcNumBinOp function. 195044d4804dSStefan Eßer */ 1951252884aeSStefan Eßer static void bc_num_right(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1952252884aeSStefan Eßer 195344d4804dSStefan Eßer BcBigDig val; 1954252884aeSStefan Eßer 1955252884aeSStefan Eßer BC_UNUSED(scale); 1956252884aeSStefan Eßer 195744d4804dSStefan Eßer val = bc_num_intop(a, b, c); 1958252884aeSStefan Eßer 1959252884aeSStefan Eßer if (BC_NUM_ZERO(c)) return; 1960252884aeSStefan Eßer 1961252884aeSStefan Eßer bc_num_shiftRight(c, (size_t) val); 1962252884aeSStefan Eßer } 1963252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 1964252884aeSStefan Eßer 196544d4804dSStefan Eßer /** 196644d4804dSStefan Eßer * Prepares for, and calls, a binary operator function. This is probably the 196744d4804dSStefan Eßer * most important function in the entire file because it establishes assumptions 196844d4804dSStefan Eßer * that make the rest of the code so easy. Those assumptions include: 196944d4804dSStefan Eßer * 197044d4804dSStefan Eßer * - a is not the same pointer as c. 197144d4804dSStefan Eßer * - b is not the same pointer as c. 197244d4804dSStefan Eßer * - there is enough room in c for the result. 197344d4804dSStefan Eßer * 197444d4804dSStefan Eßer * Without these, this whole function would basically have to be duplicated for 197544d4804dSStefan Eßer * *all* binary operators. 197644d4804dSStefan Eßer * 197744d4804dSStefan Eßer * @param a The first operand. 197844d4804dSStefan Eßer * @param b The second operand. 197944d4804dSStefan Eßer * @param c The return parameter. 198044d4804dSStefan Eßer * @param scale The current scale. 198144d4804dSStefan Eßer * @param req The number of limbs needed to fit the result. 198244d4804dSStefan Eßer */ 1983252884aeSStefan Eßer static void bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale, 19847e5c51e5SStefan Eßer BcNumBinOp op, size_t req) 1985252884aeSStefan Eßer { 198650696a6eSStefan Eßer BcNum *ptr_a, *ptr_b, num2; 1987252884aeSStefan Eßer bool init = false; 1988252884aeSStefan Eßer 1989252884aeSStefan Eßer assert(a != NULL && b != NULL && c != NULL && op != NULL); 1990252884aeSStefan Eßer 199150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 199250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 199350696a6eSStefan Eßer 1994252884aeSStefan Eßer BC_SIG_LOCK; 1995252884aeSStefan Eßer 199644d4804dSStefan Eßer // Reallocate if c == a. 1997252884aeSStefan Eßer if (c == a) { 1998252884aeSStefan Eßer 1999252884aeSStefan Eßer ptr_a = &num2; 2000252884aeSStefan Eßer 2001252884aeSStefan Eßer memcpy(ptr_a, c, sizeof(BcNum)); 2002252884aeSStefan Eßer init = true; 2003252884aeSStefan Eßer } 200450696a6eSStefan Eßer else { 200550696a6eSStefan Eßer ptr_a = a; 200650696a6eSStefan Eßer } 2007252884aeSStefan Eßer 200844d4804dSStefan Eßer // Also reallocate if c == b. 2009252884aeSStefan Eßer if (c == b) { 2010252884aeSStefan Eßer 2011252884aeSStefan Eßer ptr_b = &num2; 2012252884aeSStefan Eßer 2013252884aeSStefan Eßer if (c != a) { 2014252884aeSStefan Eßer memcpy(ptr_b, c, sizeof(BcNum)); 2015252884aeSStefan Eßer init = true; 2016252884aeSStefan Eßer } 2017252884aeSStefan Eßer } 201850696a6eSStefan Eßer else { 201950696a6eSStefan Eßer ptr_b = b; 202050696a6eSStefan Eßer } 2021252884aeSStefan Eßer 202244d4804dSStefan Eßer // Actually reallocate. If we don't reallocate, we want to expand at the 202344d4804dSStefan Eßer // very least. 2024252884aeSStefan Eßer if (init) { 2025252884aeSStefan Eßer 2026252884aeSStefan Eßer bc_num_init(c, req); 2027252884aeSStefan Eßer 202844d4804dSStefan Eßer // Must prepare for cleanup. We want this here so that locals that got 202944d4804dSStefan Eßer // set stay set since a longjmp() is not guaranteed to preserve locals. 2030252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 2031252884aeSStefan Eßer BC_SIG_UNLOCK; 2032252884aeSStefan Eßer } 2033252884aeSStefan Eßer else { 2034252884aeSStefan Eßer BC_SIG_UNLOCK; 2035252884aeSStefan Eßer bc_num_expand(c, req); 2036252884aeSStefan Eßer } 2037252884aeSStefan Eßer 203844d4804dSStefan Eßer // It is okay for a and b to be the same. If a binary operator function does 203944d4804dSStefan Eßer // need them to be different, the binary operator function is responsible 204044d4804dSStefan Eßer // for that. 204144d4804dSStefan Eßer 204244d4804dSStefan Eßer // Call the actual binary operator function. 2043252884aeSStefan Eßer op(ptr_a, ptr_b, c, scale); 2044252884aeSStefan Eßer 204550696a6eSStefan Eßer assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c)); 204650696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len); 204750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(c)); 204850696a6eSStefan Eßer assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len); 2049252884aeSStefan Eßer 2050252884aeSStefan Eßer err: 205144d4804dSStefan Eßer // Cleanup only needed if we initialized c to a new number. 2052252884aeSStefan Eßer if (init) { 2053252884aeSStefan Eßer BC_SIG_MAYLOCK; 2054252884aeSStefan Eßer bc_num_free(&num2); 2055252884aeSStefan Eßer BC_LONGJMP_CONT; 2056252884aeSStefan Eßer } 2057252884aeSStefan Eßer } 2058252884aeSStefan Eßer 205950696a6eSStefan Eßer #if !defined(NDEBUG) || BC_ENABLE_LIBRARY 206044d4804dSStefan Eßer 206144d4804dSStefan Eßer /** 206244d4804dSStefan Eßer * Tests a number string for validity. This function has a history; I originally 206344d4804dSStefan Eßer * wrote it because I did not trust my parser. Over time, however, I came to 206444d4804dSStefan Eßer * trust it, so I was able to relegate this function to debug builds only, and I 206544d4804dSStefan Eßer * used it in assert()'s. But then I created the library, and well, I can't 206644d4804dSStefan Eßer * trust users, so I reused this for yelling at users. 206744d4804dSStefan Eßer * @param val The string to check to see if it's a valid number string. 206844d4804dSStefan Eßer * @return True if the string is a valid number string, false otherwise. 206944d4804dSStefan Eßer */ 207050696a6eSStefan Eßer bool bc_num_strValid(const char *restrict val) { 2071252884aeSStefan Eßer 2072252884aeSStefan Eßer bool radix = false; 2073252884aeSStefan Eßer size_t i, len = strlen(val); 2074252884aeSStefan Eßer 207544d4804dSStefan Eßer // Notice that I don't check if there is a negative sign. That is not part 207644d4804dSStefan Eßer // of a valid number, except in the library. The library-specific code takes 207744d4804dSStefan Eßer // care of that part. 207844d4804dSStefan Eßer 207944d4804dSStefan Eßer // Nothing in the string is okay. 2080252884aeSStefan Eßer if (!len) return true; 2081252884aeSStefan Eßer 208244d4804dSStefan Eßer // Loop through the characters. 2083252884aeSStefan Eßer for (i = 0; i < len; ++i) { 2084252884aeSStefan Eßer 2085252884aeSStefan Eßer BcDig c = val[i]; 2086252884aeSStefan Eßer 208744d4804dSStefan Eßer // If we have found a radix point... 2088252884aeSStefan Eßer if (c == '.') { 2089252884aeSStefan Eßer 209044d4804dSStefan Eßer // We don't allow two radices. 2091252884aeSStefan Eßer if (radix) return false; 2092252884aeSStefan Eßer 2093252884aeSStefan Eßer radix = true; 2094252884aeSStefan Eßer continue; 2095252884aeSStefan Eßer } 2096252884aeSStefan Eßer 209744d4804dSStefan Eßer // We only allow digits and uppercase letters. 2098252884aeSStefan Eßer if (!(isdigit(c) || isupper(c))) return false; 2099252884aeSStefan Eßer } 2100252884aeSStefan Eßer 2101252884aeSStefan Eßer return true; 2102252884aeSStefan Eßer } 210350696a6eSStefan Eßer #endif // !defined(NDEBUG) || BC_ENABLE_LIBRARY 2104252884aeSStefan Eßer 210544d4804dSStefan Eßer /** 210644d4804dSStefan Eßer * Parses one character and returns the digit that corresponds to that 210744d4804dSStefan Eßer * character according to the base. 210844d4804dSStefan Eßer * @param c The character to parse. 210944d4804dSStefan Eßer * @param base The base. 211044d4804dSStefan Eßer * @return The character as a digit. 211144d4804dSStefan Eßer */ 211244d4804dSStefan Eßer static BcBigDig bc_num_parseChar(char c, size_t base) { 2113252884aeSStefan Eßer 211444d4804dSStefan Eßer assert(isupper(c) || isdigit(c)); 211544d4804dSStefan Eßer 211644d4804dSStefan Eßer // If a letter... 2117252884aeSStefan Eßer if (isupper(c)) { 211844d4804dSStefan Eßer 211944d4804dSStefan Eßer // This returns the digit that directly corresponds with the letter. 2120252884aeSStefan Eßer c = BC_NUM_NUM_LETTER(c); 212144d4804dSStefan Eßer 212244d4804dSStefan Eßer // If the digit is greater than the base, we clamp. 212344d4804dSStefan Eßer c = ((size_t) c) >= base ? (char) base - 1 : c; 2124252884aeSStefan Eßer } 212544d4804dSStefan Eßer // Straight convert the digit to a number. 2126252884aeSStefan Eßer else c -= '0'; 2127252884aeSStefan Eßer 2128252884aeSStefan Eßer return (BcBigDig) (uchar) c; 2129252884aeSStefan Eßer } 2130252884aeSStefan Eßer 213144d4804dSStefan Eßer /** 213244d4804dSStefan Eßer * Parses a string as a decimal number. This is separate because it's going to 213344d4804dSStefan Eßer * be the most used, and it can be heavily optimized for decimal only. 213444d4804dSStefan Eßer * @param n The number to parse into and return. Must be preallocated. 213544d4804dSStefan Eßer * @param val The string to parse. 213644d4804dSStefan Eßer */ 2137252884aeSStefan Eßer static void bc_num_parseDecimal(BcNum *restrict n, const char *restrict val) { 2138252884aeSStefan Eßer 2139252884aeSStefan Eßer size_t len, i, temp, mod; 2140252884aeSStefan Eßer const char *ptr; 2141252884aeSStefan Eßer bool zero = true, rdx; 2142252884aeSStefan Eßer 214344d4804dSStefan Eßer // Eat leading zeroes. 2144252884aeSStefan Eßer for (i = 0; val[i] == '0'; ++i); 2145252884aeSStefan Eßer 2146252884aeSStefan Eßer val += i; 2147252884aeSStefan Eßer assert(!val[0] || isalnum(val[0]) || val[0] == '.'); 2148252884aeSStefan Eßer 214944d4804dSStefan Eßer // All 0's. We can just return, since this procedure expects a virgin 215044d4804dSStefan Eßer // (already 0) BcNum. 2151252884aeSStefan Eßer if (!val[0]) return; 2152252884aeSStefan Eßer 215344d4804dSStefan Eßer // The length of the string is the length of the number, except it might be 215444d4804dSStefan Eßer // one bigger because of a decimal point. 2155252884aeSStefan Eßer len = strlen(val); 2156252884aeSStefan Eßer 215744d4804dSStefan Eßer // Find the location of the decimal point. 2158252884aeSStefan Eßer ptr = strchr(val, '.'); 2159252884aeSStefan Eßer rdx = (ptr != NULL); 2160252884aeSStefan Eßer 216144d4804dSStefan Eßer // We eat leading zeroes again. These leading zeroes are different because 216244d4804dSStefan Eßer // they will come after the decimal point if they exist, and since that's 216344d4804dSStefan Eßer // the case, they must be preserved. 2164252884aeSStefan Eßer for (i = 0; i < len && (zero = (val[i] == '0' || val[i] == '.')); ++i); 2165252884aeSStefan Eßer 216644d4804dSStefan Eßer // Set the scale of the number based on the location of the decimal point. 216744d4804dSStefan Eßer // The casts to uintptr_t is to ensure that bc does not hit undefined 216844d4804dSStefan Eßer // behavior when doing math on the values. 2169d213476dSStefan Eßer n->scale = (size_t) (rdx * (((uintptr_t) (val + len)) - 2170d213476dSStefan Eßer (((uintptr_t) ptr) + 1))); 2171252884aeSStefan Eßer 217244d4804dSStefan Eßer // Set rdx. 217350696a6eSStefan Eßer BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale)); 217444d4804dSStefan Eßer 217544d4804dSStefan Eßer // Calculate length. First, the length of the integer, then the number of 217644d4804dSStefan Eßer // digits in the last limb, then the length. 2177252884aeSStefan Eßer i = len - (ptr == val ? 0 : i) - rdx; 2178252884aeSStefan Eßer temp = BC_NUM_ROUND_POW(i); 2179252884aeSStefan Eßer mod = n->scale % BC_BASE_DIGS; 2180252884aeSStefan Eßer i = mod ? BC_BASE_DIGS - mod : 0; 2181252884aeSStefan Eßer n->len = ((temp + i) / BC_BASE_DIGS); 2182252884aeSStefan Eßer 218344d4804dSStefan Eßer // Expand and zero. 2184252884aeSStefan Eßer bc_num_expand(n, n->len); 2185252884aeSStefan Eßer memset(n->num, 0, BC_NUM_SIZE(n->len)); 2186252884aeSStefan Eßer 218750696a6eSStefan Eßer if (zero) { 218850696a6eSStefan Eßer // I think I can set rdx directly to zero here because n should be a 218950696a6eSStefan Eßer // new number with sign set to false. 219050696a6eSStefan Eßer n->len = n->rdx = 0; 219150696a6eSStefan Eßer } 2192252884aeSStefan Eßer else { 2193252884aeSStefan Eßer 219444d4804dSStefan Eßer // There is actually stuff to parse if we make it here. Yay... 2195252884aeSStefan Eßer BcBigDig exp, pow; 2196252884aeSStefan Eßer 2197252884aeSStefan Eßer assert(i <= BC_NUM_BIGDIG_MAX); 2198252884aeSStefan Eßer 219944d4804dSStefan Eßer // The exponent and power. 2200252884aeSStefan Eßer exp = (BcBigDig) i; 2201252884aeSStefan Eßer pow = bc_num_pow10[exp]; 2202252884aeSStefan Eßer 220344d4804dSStefan Eßer // Parse loop. We parse backwards because numbers are stored little 220444d4804dSStefan Eßer // endian. 2205252884aeSStefan Eßer for (i = len - 1; i < len; --i, ++exp) { 2206252884aeSStefan Eßer 2207252884aeSStefan Eßer char c = val[i]; 2208252884aeSStefan Eßer 220944d4804dSStefan Eßer // Skip the decimal point. 2210252884aeSStefan Eßer if (c == '.') exp -= 1; 2211252884aeSStefan Eßer else { 2212252884aeSStefan Eßer 221344d4804dSStefan Eßer // The index of the limb. 2214252884aeSStefan Eßer size_t idx = exp / BC_BASE_DIGS; 2215252884aeSStefan Eßer 221644d4804dSStefan Eßer // Clamp for the base. 2217252884aeSStefan Eßer if (isupper(c)) c = '9'; 221844d4804dSStefan Eßer 221944d4804dSStefan Eßer // Add the digit to the limb. 2220252884aeSStefan Eßer n->num[idx] += (((BcBigDig) c) - '0') * pow; 2221252884aeSStefan Eßer 222244d4804dSStefan Eßer // Adjust the power and exponent. 2223252884aeSStefan Eßer if ((exp + 1) % BC_BASE_DIGS == 0) pow = 1; 2224252884aeSStefan Eßer else pow *= BC_BASE; 2225252884aeSStefan Eßer } 2226252884aeSStefan Eßer } 2227252884aeSStefan Eßer } 2228252884aeSStefan Eßer } 2229252884aeSStefan Eßer 223044d4804dSStefan Eßer /** 223144d4804dSStefan Eßer * Parse a number in any base (besides decimal). 223244d4804dSStefan Eßer * @param n The number to parse into and return. Must be preallocated. 223344d4804dSStefan Eßer * @param val The string to parse. 223444d4804dSStefan Eßer * @param base The base to parse as. 223544d4804dSStefan Eßer */ 2236252884aeSStefan Eßer static void bc_num_parseBase(BcNum *restrict n, const char *restrict val, 2237252884aeSStefan Eßer BcBigDig base) 2238252884aeSStefan Eßer { 2239252884aeSStefan Eßer BcNum temp, mult1, mult2, result1, result2, *m1, *m2, *ptr; 2240252884aeSStefan Eßer char c = 0; 2241252884aeSStefan Eßer bool zero = true; 2242252884aeSStefan Eßer BcBigDig v; 2243252884aeSStefan Eßer size_t i, digs, len = strlen(val); 2244252884aeSStefan Eßer 224544d4804dSStefan Eßer // If zero, just return because the number should be virgin (already 0). 2246252884aeSStefan Eßer for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0'); 2247252884aeSStefan Eßer if (zero) return; 2248252884aeSStefan Eßer 2249252884aeSStefan Eßer BC_SIG_LOCK; 2250252884aeSStefan Eßer 2251252884aeSStefan Eßer bc_num_init(&temp, BC_NUM_BIGDIG_LOG10); 2252252884aeSStefan Eßer bc_num_init(&mult1, BC_NUM_BIGDIG_LOG10); 2253252884aeSStefan Eßer 2254252884aeSStefan Eßer BC_SETJMP_LOCKED(int_err); 2255252884aeSStefan Eßer 2256252884aeSStefan Eßer BC_SIG_UNLOCK; 2257252884aeSStefan Eßer 225844d4804dSStefan Eßer // We split parsing into parsing the integer and parsing the fractional 225944d4804dSStefan Eßer // part. 226044d4804dSStefan Eßer 226144d4804dSStefan Eßer // Parse the integer part. This is the easy part because we just multiply 226244d4804dSStefan Eßer // the number by the base, then add the digit. 2263252884aeSStefan Eßer for (i = 0; i < len && (c = val[i]) && c != '.'; ++i) { 2264252884aeSStefan Eßer 226544d4804dSStefan Eßer // Convert the character to a digit. 2266252884aeSStefan Eßer v = bc_num_parseChar(c, base); 2267252884aeSStefan Eßer 226844d4804dSStefan Eßer // Multiply the number. 2269252884aeSStefan Eßer bc_num_mulArray(n, base, &mult1); 227044d4804dSStefan Eßer 227144d4804dSStefan Eßer // Convert the digit to a number and add. 2272252884aeSStefan Eßer bc_num_bigdig2num(&temp, v); 2273252884aeSStefan Eßer bc_num_add(&mult1, &temp, n, 0); 2274252884aeSStefan Eßer } 2275252884aeSStefan Eßer 227644d4804dSStefan Eßer // If this condition is true, then we are done. We still need to do cleanup 227744d4804dSStefan Eßer // though. 227810328f8bSStefan Eßer if (i == len && !val[i]) goto int_err; 2279252884aeSStefan Eßer 228044d4804dSStefan Eßer // If we get here, we *must* be at the radix point. 228110328f8bSStefan Eßer assert(val[i] == '.'); 2282252884aeSStefan Eßer 2283252884aeSStefan Eßer BC_SIG_LOCK; 2284252884aeSStefan Eßer 228544d4804dSStefan Eßer // Unset the jump to reset in for these new initializations. 2286252884aeSStefan Eßer BC_UNSETJMP; 2287252884aeSStefan Eßer 2288252884aeSStefan Eßer bc_num_init(&mult2, BC_NUM_BIGDIG_LOG10); 2289252884aeSStefan Eßer bc_num_init(&result1, BC_NUM_DEF_SIZE); 2290252884aeSStefan Eßer bc_num_init(&result2, BC_NUM_DEF_SIZE); 2291252884aeSStefan Eßer bc_num_one(&mult1); 2292252884aeSStefan Eßer 2293252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 2294252884aeSStefan Eßer 2295252884aeSStefan Eßer BC_SIG_UNLOCK; 2296252884aeSStefan Eßer 229744d4804dSStefan Eßer // Pointers for easy switching. 2298252884aeSStefan Eßer m1 = &mult1; 2299252884aeSStefan Eßer m2 = &mult2; 2300252884aeSStefan Eßer 230144d4804dSStefan Eßer // Parse the fractional part. This is the hard part. 2302252884aeSStefan Eßer for (i += 1, digs = 0; i < len && (c = val[i]); ++i, ++digs) { 2303252884aeSStefan Eßer 230450696a6eSStefan Eßer size_t rdx; 230550696a6eSStefan Eßer 230644d4804dSStefan Eßer // Convert the character to a digit. 2307252884aeSStefan Eßer v = bc_num_parseChar(c, base); 2308252884aeSStefan Eßer 230944d4804dSStefan Eßer // We keep growing result2 according to the base because the more digits 231044d4804dSStefan Eßer // after the radix, the more significant the digits close to the radix 231144d4804dSStefan Eßer // should be. 2312252884aeSStefan Eßer bc_num_mulArray(&result1, base, &result2); 2313252884aeSStefan Eßer 231444d4804dSStefan Eßer // Convert the digit to a number. 2315252884aeSStefan Eßer bc_num_bigdig2num(&temp, v); 231644d4804dSStefan Eßer 231744d4804dSStefan Eßer // Add the digit into the fraction part. 2318252884aeSStefan Eßer bc_num_add(&result2, &temp, &result1, 0); 231944d4804dSStefan Eßer 232044d4804dSStefan Eßer // Keep growing m1 and m2 for use after the loop. 2321252884aeSStefan Eßer bc_num_mulArray(m1, base, m2); 2322252884aeSStefan Eßer 232350696a6eSStefan Eßer rdx = BC_NUM_RDX_VAL(m2); 232450696a6eSStefan Eßer 232550696a6eSStefan Eßer if (m2->len < rdx) m2->len = rdx; 2326252884aeSStefan Eßer 232744d4804dSStefan Eßer // Switch. 2328252884aeSStefan Eßer ptr = m1; 2329252884aeSStefan Eßer m1 = m2; 2330252884aeSStefan Eßer m2 = ptr; 2331252884aeSStefan Eßer } 2332252884aeSStefan Eßer 2333252884aeSStefan Eßer // This one cannot be a divide by 0 because mult starts out at 1, then is 233444d4804dSStefan Eßer // multiplied by base, and base cannot be 0, so mult cannot be 0. And this 233544d4804dSStefan Eßer // is the reason we keep growing m1 and m2; this division is what converts 233644d4804dSStefan Eßer // the parsed fractional part from an integer to a fractional part. 2337252884aeSStefan Eßer bc_num_div(&result1, m1, &result2, digs * 2); 233844d4804dSStefan Eßer 233944d4804dSStefan Eßer // Pretruncate. 2340252884aeSStefan Eßer bc_num_truncate(&result2, digs); 234144d4804dSStefan Eßer 234244d4804dSStefan Eßer // The final add of the integer part to the fractional part. 2343252884aeSStefan Eßer bc_num_add(n, &result2, n, digs); 2344252884aeSStefan Eßer 234544d4804dSStefan Eßer // Basic cleanup. 2346252884aeSStefan Eßer if (BC_NUM_NONZERO(n)) { 2347252884aeSStefan Eßer if (n->scale < digs) bc_num_extend(n, digs - n->scale); 2348252884aeSStefan Eßer } 2349252884aeSStefan Eßer else bc_num_zero(n); 2350252884aeSStefan Eßer 2351252884aeSStefan Eßer err: 2352252884aeSStefan Eßer BC_SIG_MAYLOCK; 2353252884aeSStefan Eßer bc_num_free(&result2); 2354252884aeSStefan Eßer bc_num_free(&result1); 2355252884aeSStefan Eßer bc_num_free(&mult2); 2356252884aeSStefan Eßer int_err: 2357252884aeSStefan Eßer BC_SIG_MAYLOCK; 2358252884aeSStefan Eßer bc_num_free(&mult1); 2359252884aeSStefan Eßer bc_num_free(&temp); 2360252884aeSStefan Eßer BC_LONGJMP_CONT; 2361252884aeSStefan Eßer } 2362252884aeSStefan Eßer 236344d4804dSStefan Eßer /** 236444d4804dSStefan Eßer * Prints a backslash+newline combo if the number of characters needs it. This 236544d4804dSStefan Eßer * is really a convenience function. 236644d4804dSStefan Eßer */ 236750696a6eSStefan Eßer static inline void bc_num_printNewline(void) { 236850696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY 2369*d43fa8efSStefan Eßer if (vm.nchars >= vm.line_len - 1 && vm.line_len) { 23707e5c51e5SStefan Eßer bc_vm_putchar('\\', bc_flush_none); 23717e5c51e5SStefan Eßer bc_vm_putchar('\n', bc_flush_err); 2372252884aeSStefan Eßer } 237350696a6eSStefan Eßer #endif // !BC_ENABLE_LIBRARY 2374252884aeSStefan Eßer } 2375252884aeSStefan Eßer 237644d4804dSStefan Eßer /** 237744d4804dSStefan Eßer * Prints a character after a backslash+newline, if needed. 237844d4804dSStefan Eßer * @param c The character to print. 237944d4804dSStefan Eßer * @param bslash Whether to print a backslash+newline. 238044d4804dSStefan Eßer */ 238144d4804dSStefan Eßer static void bc_num_putchar(int c, bool bslash) { 238244d4804dSStefan Eßer if (c != '\n' && bslash) bc_num_printNewline(); 23837e5c51e5SStefan Eßer bc_vm_putchar(c, bc_flush_save); 2384252884aeSStefan Eßer } 2385252884aeSStefan Eßer 238644d4804dSStefan Eßer #if !BC_ENABLE_LIBRARY 238744d4804dSStefan Eßer 238844d4804dSStefan Eßer /** 238944d4804dSStefan Eßer * Prints a character for a number's digit. This is for printing for dc's P 239044d4804dSStefan Eßer * command. This function does not need to worry about radix points. This is a 239144d4804dSStefan Eßer * BcNumDigitOp. 239244d4804dSStefan Eßer * @param n The "digit" to print. 239344d4804dSStefan Eßer * @param len The "length" of the digit, or number of characters that will 239444d4804dSStefan Eßer * need to be printed for the digit. 239544d4804dSStefan Eßer * @param rdx True if a decimal (radix) point should be printed. 239644d4804dSStefan Eßer * @param bslash True if a backslash+newline should be printed if the character 239744d4804dSStefan Eßer * limit for the line is reached, false otherwise. 239844d4804dSStefan Eßer */ 239944d4804dSStefan Eßer static void bc_num_printChar(size_t n, size_t len, bool rdx, bool bslash) { 2400252884aeSStefan Eßer BC_UNUSED(rdx); 2401252884aeSStefan Eßer BC_UNUSED(len); 240244d4804dSStefan Eßer BC_UNUSED(bslash); 2403252884aeSStefan Eßer assert(len == 1); 24047e5c51e5SStefan Eßer bc_vm_putchar((uchar) n, bc_flush_save); 2405252884aeSStefan Eßer } 2406252884aeSStefan Eßer 240744d4804dSStefan Eßer #endif // !BC_ENABLE_LIBRARY 240844d4804dSStefan Eßer 240944d4804dSStefan Eßer /** 241044d4804dSStefan Eßer * Prints a series of characters for large bases. This is for printing in bases 241144d4804dSStefan Eßer * above hexadecimal. This is a BcNumDigitOp. 241244d4804dSStefan Eßer * @param n The "digit" to print. 241344d4804dSStefan Eßer * @param len The "length" of the digit, or number of characters that will 241444d4804dSStefan Eßer * need to be printed for the digit. 241544d4804dSStefan Eßer * @param rdx True if a decimal (radix) point should be printed. 241644d4804dSStefan Eßer * @param bslash True if a backslash+newline should be printed if the character 241744d4804dSStefan Eßer * limit for the line is reached, false otherwise. 241844d4804dSStefan Eßer */ 241944d4804dSStefan Eßer static void bc_num_printDigits(size_t n, size_t len, bool rdx, bool bslash) { 2420252884aeSStefan Eßer 2421252884aeSStefan Eßer size_t exp, pow; 2422252884aeSStefan Eßer 242344d4804dSStefan Eßer // If needed, print the radix; otherwise, print a space to separate digits. 242444d4804dSStefan Eßer bc_num_putchar(rdx ? '.' : ' ', true); 2425252884aeSStefan Eßer 242644d4804dSStefan Eßer // Calculate the exponent and power. 2427252884aeSStefan Eßer for (exp = 0, pow = 1; exp < len - 1; ++exp, pow *= BC_BASE); 2428252884aeSStefan Eßer 242944d4804dSStefan Eßer // Print each character individually. 2430252884aeSStefan Eßer for (exp = 0; exp < len; pow /= BC_BASE, ++exp) { 243144d4804dSStefan Eßer 243244d4804dSStefan Eßer // The individual subdigit. 2433252884aeSStefan Eßer size_t dig = n / pow; 243444d4804dSStefan Eßer 243544d4804dSStefan Eßer // Take the subdigit away. 2436252884aeSStefan Eßer n -= dig * pow; 243744d4804dSStefan Eßer 243844d4804dSStefan Eßer // Print the subdigit. 243944d4804dSStefan Eßer bc_num_putchar(((uchar) dig) + '0', bslash || exp != len - 1); 2440252884aeSStefan Eßer } 2441252884aeSStefan Eßer } 2442252884aeSStefan Eßer 244344d4804dSStefan Eßer /** 244444d4804dSStefan Eßer * Prints a character for a number's digit. This is for printing in bases for 244544d4804dSStefan Eßer * hexadecimal and below because they always print only one character at a time. 244644d4804dSStefan Eßer * This is a BcNumDigitOp. 244744d4804dSStefan Eßer * @param n The "digit" to print. 244844d4804dSStefan Eßer * @param len The "length" of the digit, or number of characters that will 244944d4804dSStefan Eßer * need to be printed for the digit. 245044d4804dSStefan Eßer * @param rdx True if a decimal (radix) point should be printed. 245144d4804dSStefan Eßer * @param bslash True if a backslash+newline should be printed if the character 245244d4804dSStefan Eßer * limit for the line is reached, false otherwise. 245344d4804dSStefan Eßer */ 245444d4804dSStefan Eßer static void bc_num_printHex(size_t n, size_t len, bool rdx, bool bslash) { 2455252884aeSStefan Eßer 2456252884aeSStefan Eßer BC_UNUSED(len); 245744d4804dSStefan Eßer BC_UNUSED(bslash); 2458252884aeSStefan Eßer 2459252884aeSStefan Eßer assert(len == 1); 2460252884aeSStefan Eßer 246144d4804dSStefan Eßer if (rdx) bc_num_putchar('.', true); 2462252884aeSStefan Eßer 246344d4804dSStefan Eßer bc_num_putchar(bc_num_hex_digits[n], bslash); 2464252884aeSStefan Eßer } 2465252884aeSStefan Eßer 246644d4804dSStefan Eßer /** 246744d4804dSStefan Eßer * Prints a decimal number. This is specially written for optimization since 246844d4804dSStefan Eßer * this will be used the most and because bc's numbers are already in decimal. 246944d4804dSStefan Eßer * @param n The number to print. 247044d4804dSStefan Eßer * @param newline Whether to print backslash+newlines on long enough lines. 247144d4804dSStefan Eßer */ 247244d4804dSStefan Eßer static void bc_num_printDecimal(const BcNum *restrict n, bool newline) { 2473252884aeSStefan Eßer 247450696a6eSStefan Eßer size_t i, j, rdx = BC_NUM_RDX_VAL(n); 2475252884aeSStefan Eßer bool zero = true; 2476252884aeSStefan Eßer size_t buffer[BC_BASE_DIGS]; 2477252884aeSStefan Eßer 247844d4804dSStefan Eßer // Print loop. 2479252884aeSStefan Eßer for (i = n->len - 1; i < n->len; --i) { 2480252884aeSStefan Eßer 2481252884aeSStefan Eßer BcDig n9 = n->num[i]; 2482252884aeSStefan Eßer size_t temp; 2483252884aeSStefan Eßer bool irdx = (i == rdx - 1); 2484252884aeSStefan Eßer 248544d4804dSStefan Eßer // Calculate the number of digits in the limb. 2486252884aeSStefan Eßer zero = (zero & !irdx); 2487252884aeSStefan Eßer temp = n->scale % BC_BASE_DIGS; 2488252884aeSStefan Eßer temp = i || !temp ? 0 : BC_BASE_DIGS - temp; 2489252884aeSStefan Eßer 2490252884aeSStefan Eßer memset(buffer, 0, BC_BASE_DIGS * sizeof(size_t)); 2491252884aeSStefan Eßer 249244d4804dSStefan Eßer // Fill the buffer with individual digits. 2493252884aeSStefan Eßer for (j = 0; n9 && j < BC_BASE_DIGS; ++j) { 2494d213476dSStefan Eßer buffer[j] = ((size_t) n9) % BC_BASE; 2495252884aeSStefan Eßer n9 /= BC_BASE; 2496252884aeSStefan Eßer } 2497252884aeSStefan Eßer 249844d4804dSStefan Eßer // Print the digits in the buffer. 2499252884aeSStefan Eßer for (j = BC_BASE_DIGS - 1; j < BC_BASE_DIGS && j >= temp; --j) { 250044d4804dSStefan Eßer 250144d4804dSStefan Eßer // Figure out whether to print the decimal point. 2502252884aeSStefan Eßer bool print_rdx = (irdx & (j == BC_BASE_DIGS - 1)); 250344d4804dSStefan Eßer 250444d4804dSStefan Eßer // The zero variable helps us skip leading zero digits in the limb. 2505252884aeSStefan Eßer zero = (zero && buffer[j] == 0); 250644d4804dSStefan Eßer 250744d4804dSStefan Eßer if (!zero) { 250844d4804dSStefan Eßer 250944d4804dSStefan Eßer // While the first three arguments should be self-explanatory, 251044d4804dSStefan Eßer // the last needs explaining. I don't want to print a newline 251144d4804dSStefan Eßer // when the last digit to be printed could take the place of the 251244d4804dSStefan Eßer // backslash rather than being pushed, as a single character, to 251344d4804dSStefan Eßer // the next line. That's what that last argument does for bc. 251444d4804dSStefan Eßer bc_num_printHex(buffer[j], 1, print_rdx, 251544d4804dSStefan Eßer !newline || (j > temp || i != 0)); 251644d4804dSStefan Eßer } 2517252884aeSStefan Eßer } 2518252884aeSStefan Eßer } 2519252884aeSStefan Eßer } 2520252884aeSStefan Eßer 2521252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 2522252884aeSStefan Eßer 252344d4804dSStefan Eßer /** 252444d4804dSStefan Eßer * Prints a number in scientific or engineering format. When doing this, we are 252544d4804dSStefan Eßer * always printing in decimal. 252644d4804dSStefan Eßer * @param n The number to print. 252744d4804dSStefan Eßer * @param eng True if we are in engineering mode. 252844d4804dSStefan Eßer * @param newline Whether to print backslash+newlines on long enough lines. 252944d4804dSStefan Eßer */ 253044d4804dSStefan Eßer static void bc_num_printExponent(const BcNum *restrict n, 253144d4804dSStefan Eßer bool eng, bool newline) 253244d4804dSStefan Eßer { 253350696a6eSStefan Eßer size_t places, mod, nrdx = BC_NUM_RDX_VAL(n); 253450696a6eSStefan Eßer bool neg = (n->len <= nrdx); 2535252884aeSStefan Eßer BcNum temp, exp; 2536252884aeSStefan Eßer BcDig digs[BC_NUM_BIGDIG_LOG10]; 2537252884aeSStefan Eßer 2538252884aeSStefan Eßer BC_SIG_LOCK; 2539252884aeSStefan Eßer 2540252884aeSStefan Eßer bc_num_createCopy(&temp, n); 2541252884aeSStefan Eßer 2542252884aeSStefan Eßer BC_SETJMP_LOCKED(exit); 2543252884aeSStefan Eßer 2544252884aeSStefan Eßer BC_SIG_UNLOCK; 2545252884aeSStefan Eßer 254644d4804dSStefan Eßer // We need to calculate the exponents, and they change based on whether the 254744d4804dSStefan Eßer // number is all fractional or not, obviously. 2548252884aeSStefan Eßer if (neg) { 2549252884aeSStefan Eßer 255044d4804dSStefan Eßer // Figure out how many limbs after the decimal point is zero. 255144d4804dSStefan Eßer size_t i, idx = bc_num_nonZeroLen(n) - 1; 2552252884aeSStefan Eßer 2553252884aeSStefan Eßer places = 1; 2554252884aeSStefan Eßer 255544d4804dSStefan Eßer // Figure out how much in the last limb is zero. 2556252884aeSStefan Eßer for (i = BC_BASE_DIGS - 1; i < BC_BASE_DIGS; --i) { 2557252884aeSStefan Eßer if (bc_num_pow10[i] > (BcBigDig) n->num[idx]) places += 1; 2558252884aeSStefan Eßer else break; 2559252884aeSStefan Eßer } 2560252884aeSStefan Eßer 256144d4804dSStefan Eßer // Calculate the combination of zero limbs and zero digits in the last 256244d4804dSStefan Eßer // limb. 256350696a6eSStefan Eßer places += (nrdx - (idx + 1)) * BC_BASE_DIGS; 2564252884aeSStefan Eßer mod = places % 3; 2565252884aeSStefan Eßer 256644d4804dSStefan Eßer // Calculate places if we are in engineering mode. 2567252884aeSStefan Eßer if (eng && mod != 0) places += 3 - mod; 256844d4804dSStefan Eßer 256944d4804dSStefan Eßer // Shift the temp to the right place. 2570252884aeSStefan Eßer bc_num_shiftLeft(&temp, places); 2571252884aeSStefan Eßer } 2572252884aeSStefan Eßer else { 257344d4804dSStefan Eßer 257444d4804dSStefan Eßer // This is the number of digits that we are supposed to put behind the 257544d4804dSStefan Eßer // decimal point. 2576252884aeSStefan Eßer places = bc_num_intDigits(n) - 1; 257744d4804dSStefan Eßer 257844d4804dSStefan Eßer // Calculate the true number based on whether engineering mode is 257944d4804dSStefan Eßer // activated. 2580252884aeSStefan Eßer mod = places % 3; 2581252884aeSStefan Eßer if (eng && mod != 0) places -= 3 - (3 - mod); 258244d4804dSStefan Eßer 258344d4804dSStefan Eßer // Shift the temp to the right place. 2584252884aeSStefan Eßer bc_num_shiftRight(&temp, places); 2585252884aeSStefan Eßer } 2586252884aeSStefan Eßer 258744d4804dSStefan Eßer // Print the shifted number. 258844d4804dSStefan Eßer bc_num_printDecimal(&temp, newline); 2589252884aeSStefan Eßer 259044d4804dSStefan Eßer // Print the e. 259144d4804dSStefan Eßer bc_num_putchar('e', !newline); 259244d4804dSStefan Eßer 259344d4804dSStefan Eßer // Need to explicitly print a zero exponent. 2594252884aeSStefan Eßer if (!places) { 259544d4804dSStefan Eßer bc_num_printHex(0, 1, false, !newline); 2596252884aeSStefan Eßer goto exit; 2597252884aeSStefan Eßer } 2598252884aeSStefan Eßer 259944d4804dSStefan Eßer // Need to print sign for the exponent. 260044d4804dSStefan Eßer if (neg) bc_num_putchar('-', true); 2601252884aeSStefan Eßer 260244d4804dSStefan Eßer // Create a temporary for the exponent... 2603252884aeSStefan Eßer bc_num_setup(&exp, digs, BC_NUM_BIGDIG_LOG10); 2604252884aeSStefan Eßer bc_num_bigdig2num(&exp, (BcBigDig) places); 2605252884aeSStefan Eßer 260644d4804dSStefan Eßer /// ..and print it. 260744d4804dSStefan Eßer bc_num_printDecimal(&exp, newline); 2608252884aeSStefan Eßer 2609252884aeSStefan Eßer exit: 2610252884aeSStefan Eßer BC_SIG_MAYLOCK; 2611252884aeSStefan Eßer bc_num_free(&temp); 2612252884aeSStefan Eßer BC_LONGJMP_CONT; 2613252884aeSStefan Eßer } 2614252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 2615252884aeSStefan Eßer 261644d4804dSStefan Eßer /** 261744d4804dSStefan Eßer * Converts a number from limbs with base BC_BASE_POW to base @a pow, where 261844d4804dSStefan Eßer * @a pow is obase^N. 261944d4804dSStefan Eßer * @param n The number to convert. 262044d4804dSStefan Eßer * @param rem BC_BASE_POW - @a pow. 262144d4804dSStefan Eßer * @param pow The power of obase we will convert the number to. 262244d4804dSStefan Eßer * @param idx The index of the number to start converting at. Doing the 262344d4804dSStefan Eßer * conversion is O(n^2); we have to sweep through starting at the 262444d4804dSStefan Eßer * least significant limb 262544d4804dSStefan Eßer */ 2626252884aeSStefan Eßer static void bc_num_printFixup(BcNum *restrict n, BcBigDig rem, 2627252884aeSStefan Eßer BcBigDig pow, size_t idx) 2628252884aeSStefan Eßer { 2629252884aeSStefan Eßer size_t i, len = n->len - idx; 2630252884aeSStefan Eßer BcBigDig acc; 2631252884aeSStefan Eßer BcDig *a = n->num + idx; 2632252884aeSStefan Eßer 263344d4804dSStefan Eßer // Ignore if there's just one limb left. This is the part that requires the 263444d4804dSStefan Eßer // extra loop after the one calling this function in bc_num_printPrepare(). 2635252884aeSStefan Eßer if (len < 2) return; 2636252884aeSStefan Eßer 263744d4804dSStefan Eßer // Loop through the remaining limbs and convert. We start at the second limb 263844d4804dSStefan Eßer // because we pull the value from the previous one as well. 2639252884aeSStefan Eßer for (i = len - 1; i > 0; --i) { 2640252884aeSStefan Eßer 264144d4804dSStefan Eßer // Get the limb and add it to the previous, along with multiplying by 264244d4804dSStefan Eßer // the remainder because that's the proper overflow. "acc" means 264344d4804dSStefan Eßer // "accumulator," by the way. 2644252884aeSStefan Eßer acc = ((BcBigDig) a[i]) * rem + ((BcBigDig) a[i - 1]); 264544d4804dSStefan Eßer 264644d4804dSStefan Eßer // Store a value in base pow in the previous limb. 2647252884aeSStefan Eßer a[i - 1] = (BcDig) (acc % pow); 264844d4804dSStefan Eßer 264944d4804dSStefan Eßer // Divide by the base and accumulate the remaining value in the limb. 2650252884aeSStefan Eßer acc /= pow; 2651252884aeSStefan Eßer acc += (BcBigDig) a[i]; 2652252884aeSStefan Eßer 265344d4804dSStefan Eßer // If the accumulator is greater than the base... 2654252884aeSStefan Eßer if (acc >= BC_BASE_POW) { 2655252884aeSStefan Eßer 265644d4804dSStefan Eßer // Do we need to grow? 2657252884aeSStefan Eßer if (i == len - 1) { 265844d4804dSStefan Eßer 265944d4804dSStefan Eßer // Grow. 2660252884aeSStefan Eßer len = bc_vm_growSize(len, 1); 2661252884aeSStefan Eßer bc_num_expand(n, bc_vm_growSize(len, idx)); 266244d4804dSStefan Eßer 266344d4804dSStefan Eßer // Update the pointer because it may have moved. 2664252884aeSStefan Eßer a = n->num + idx; 266544d4804dSStefan Eßer 266644d4804dSStefan Eßer // Zero out the last limb. 2667252884aeSStefan Eßer a[len - 1] = 0; 2668252884aeSStefan Eßer } 2669252884aeSStefan Eßer 267044d4804dSStefan Eßer // Overflow into the next limb since we are over the base. 2671252884aeSStefan Eßer a[i + 1] += acc / BC_BASE_POW; 2672252884aeSStefan Eßer acc %= BC_BASE_POW; 2673252884aeSStefan Eßer } 2674252884aeSStefan Eßer 2675252884aeSStefan Eßer assert(acc < BC_BASE_POW); 267644d4804dSStefan Eßer 267744d4804dSStefan Eßer // Set the limb. 2678252884aeSStefan Eßer a[i] = (BcDig) acc; 2679252884aeSStefan Eßer } 2680252884aeSStefan Eßer 268144d4804dSStefan Eßer // We may have grown the number, so adjust the length. 2682252884aeSStefan Eßer n->len = len + idx; 2683252884aeSStefan Eßer } 2684252884aeSStefan Eßer 268544d4804dSStefan Eßer /** 268644d4804dSStefan Eßer * Prepares a number for printing in a base that is not a divisor of 268744d4804dSStefan Eßer * BC_BASE_POW. This basically converts the number from having limbs of base 268844d4804dSStefan Eßer * BC_BASE_POW to limbs of pow, where pow is obase^N. 268944d4804dSStefan Eßer * @param n The number to prepare for printing. 269044d4804dSStefan Eßer * @param rem The remainder of BC_BASE_POW when divided by a power of the base. 269144d4804dSStefan Eßer * @param pow The power of the base. 269244d4804dSStefan Eßer */ 269344d4804dSStefan Eßer static void bc_num_printPrepare(BcNum *restrict n, BcBigDig rem, BcBigDig pow) { 269444d4804dSStefan Eßer 2695252884aeSStefan Eßer size_t i; 2696252884aeSStefan Eßer 269744d4804dSStefan Eßer // Loop from the least significant limb to the most significant limb and 269844d4804dSStefan Eßer // convert limbs in each pass. 2699252884aeSStefan Eßer for (i = 0; i < n->len; ++i) bc_num_printFixup(n, rem, pow, i); 2700252884aeSStefan Eßer 270144d4804dSStefan Eßer // bc_num_printFixup() does not do everything it is supposed to, so we do 270244d4804dSStefan Eßer // the last bit of cleanup here. That cleanup is to ensure that each limb 270344d4804dSStefan Eßer // is less than pow and to expand the number to fit new limbs as necessary. 2704252884aeSStefan Eßer for (i = 0; i < n->len; ++i) { 2705252884aeSStefan Eßer 2706252884aeSStefan Eßer assert(pow == ((BcBigDig) ((BcDig) pow))); 2707252884aeSStefan Eßer 270844d4804dSStefan Eßer // If the limb needs fixing... 2709252884aeSStefan Eßer if (n->num[i] >= (BcDig) pow) { 2710252884aeSStefan Eßer 271144d4804dSStefan Eßer // Do we need to grow? 2712252884aeSStefan Eßer if (i + 1 == n->len) { 271344d4804dSStefan Eßer 271444d4804dSStefan Eßer // Grow the number. 2715252884aeSStefan Eßer n->len = bc_vm_growSize(n->len, 1); 2716252884aeSStefan Eßer bc_num_expand(n, n->len); 271744d4804dSStefan Eßer 271844d4804dSStefan Eßer // Without this, we might use uninitialized data. 2719252884aeSStefan Eßer n->num[i + 1] = 0; 2720252884aeSStefan Eßer } 2721252884aeSStefan Eßer 2722252884aeSStefan Eßer assert(pow < BC_BASE_POW); 272344d4804dSStefan Eßer 272444d4804dSStefan Eßer // Overflow into the next limb. 2725252884aeSStefan Eßer n->num[i + 1] += n->num[i] / ((BcDig) pow); 2726252884aeSStefan Eßer n->num[i] %= (BcDig) pow; 2727252884aeSStefan Eßer } 2728252884aeSStefan Eßer } 2729252884aeSStefan Eßer } 2730252884aeSStefan Eßer 273144d4804dSStefan Eßer static void bc_num_printNum(BcNum *restrict n, BcBigDig base, size_t len, 273244d4804dSStefan Eßer BcNumDigitOp print, bool newline) 2733252884aeSStefan Eßer { 2734252884aeSStefan Eßer BcVec stack; 2735252884aeSStefan Eßer BcNum intp, fracp1, fracp2, digit, flen1, flen2, *n1, *n2, *temp; 2736252884aeSStefan Eßer BcBigDig dig = 0, *ptr, acc, exp; 273744d4804dSStefan Eßer size_t i, j, nrdx, idigits; 2738252884aeSStefan Eßer bool radix; 2739252884aeSStefan Eßer BcDig digit_digs[BC_NUM_BIGDIG_LOG10 + 1]; 2740252884aeSStefan Eßer 2741252884aeSStefan Eßer assert(base > 1); 2742252884aeSStefan Eßer 274344d4804dSStefan Eßer // Easy case. Even with scale, we just print this. 2744252884aeSStefan Eßer if (BC_NUM_ZERO(n)) { 274544d4804dSStefan Eßer print(0, len, false, !newline); 2746252884aeSStefan Eßer return; 2747252884aeSStefan Eßer } 2748252884aeSStefan Eßer 2749252884aeSStefan Eßer // This function uses an algorithm that Stefan Esser <se@freebsd.org> came 2750252884aeSStefan Eßer // up with to print the integer part of a number. What it does is convert 2751252884aeSStefan Eßer // intp into a number of the specified base, but it does it directly, 2752252884aeSStefan Eßer // instead of just doing a series of divisions and printing the remainders 2753252884aeSStefan Eßer // in reverse order. 2754252884aeSStefan Eßer // 2755252884aeSStefan Eßer // Let me explain in a bit more detail: 2756252884aeSStefan Eßer // 275744d4804dSStefan Eßer // The algorithm takes the current least significant limb (after intp has 275844d4804dSStefan Eßer // been converted to an integer) and the next to least significant limb, and 275944d4804dSStefan Eßer // it converts the least significant limb into one of the specified base, 276044d4804dSStefan Eßer // putting any overflow into the next to least significant limb. It iterates 276144d4804dSStefan Eßer // through the whole number, from least significant to most significant, 276244d4804dSStefan Eßer // doing this conversion. At the end of that iteration, the least 276344d4804dSStefan Eßer // significant limb is converted, but the others are not, so it iterates 276444d4804dSStefan Eßer // again, starting at the next to least significant limb. It keeps doing 276544d4804dSStefan Eßer // that conversion, skipping one more limb than the last time, until all 276644d4804dSStefan Eßer // limbs have been converted. Then it prints them in reverse order. 2767252884aeSStefan Eßer // 2768252884aeSStefan Eßer // That is the gist of the algorithm. It leaves out several things, such as 276944d4804dSStefan Eßer // the fact that limbs are not always converted into the specified base, but 277044d4804dSStefan Eßer // into something close, basically a power of the specified base. In 2771252884aeSStefan Eßer // Stefan's words, "You could consider BcDigs to be of base 10^BC_BASE_DIGS 2772252884aeSStefan Eßer // in the normal case and obase^N for the largest value of N that satisfies 2773252884aeSStefan Eßer // obase^N <= 10^BC_BASE_DIGS. [This means that] the result is not in base 2774252884aeSStefan Eßer // "obase", but in base "obase^N", which happens to be printable as a number 2775252884aeSStefan Eßer // of base "obase" without consideration for neighbouring BcDigs." This fact 2776252884aeSStefan Eßer // is what necessitates the existence of the loop later in this function. 2777252884aeSStefan Eßer // 2778252884aeSStefan Eßer // The conversion happens in bc_num_printPrepare() where the outer loop 2779252884aeSStefan Eßer // happens and bc_num_printFixup() where the inner loop, or actual 278044d4804dSStefan Eßer // conversion, happens. In other words, bc_num_printPrepare() is where the 278144d4804dSStefan Eßer // loop that starts at the least significant limb and goes to the most 278244d4804dSStefan Eßer // significant limb. Then, on every iteration of its loop, it calls 278344d4804dSStefan Eßer // bc_num_printFixup(), which has the inner loop of actually converting 278444d4804dSStefan Eßer // the limbs it passes into limbs of base obase^N rather than base 278544d4804dSStefan Eßer // BC_BASE_POW. 2786252884aeSStefan Eßer 278750696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL(n); 278850696a6eSStefan Eßer 2789252884aeSStefan Eßer BC_SIG_LOCK; 2790252884aeSStefan Eßer 279144d4804dSStefan Eßer // The stack is what allows us to reverse the digits for printing. 279244d4804dSStefan Eßer bc_vec_init(&stack, sizeof(BcBigDig), BC_DTOR_NONE); 279350696a6eSStefan Eßer bc_num_init(&fracp1, nrdx); 2794252884aeSStefan Eßer 279544d4804dSStefan Eßer // intp will be the "integer part" of the number, so copy it. 2796252884aeSStefan Eßer bc_num_createCopy(&intp, n); 2797252884aeSStefan Eßer 2798252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 2799252884aeSStefan Eßer 2800252884aeSStefan Eßer BC_SIG_UNLOCK; 2801252884aeSStefan Eßer 280244d4804dSStefan Eßer // Make intp an integer. 2803252884aeSStefan Eßer bc_num_truncate(&intp, intp.scale); 2804252884aeSStefan Eßer 280544d4804dSStefan Eßer // Get the fractional part out. 2806252884aeSStefan Eßer bc_num_sub(n, &intp, &fracp1, 0); 2807252884aeSStefan Eßer 280844d4804dSStefan Eßer // If the base is not the same as the last base used for printing, we need 280944d4804dSStefan Eßer // to update the cached exponent and power. Yes, we cache the values of the 281044d4804dSStefan Eßer // exponent and power. That is to prevent us from calculating them every 281144d4804dSStefan Eßer // time because printing will probably happen multiple times on the same 281244d4804dSStefan Eßer // base. 2813252884aeSStefan Eßer if (base != vm.last_base) { 2814252884aeSStefan Eßer 2815252884aeSStefan Eßer vm.last_pow = 1; 2816252884aeSStefan Eßer vm.last_exp = 0; 2817252884aeSStefan Eßer 281844d4804dSStefan Eßer // Calculate the exponent and power. 2819252884aeSStefan Eßer while (vm.last_pow * base <= BC_BASE_POW) { 2820252884aeSStefan Eßer vm.last_pow *= base; 2821252884aeSStefan Eßer vm.last_exp += 1; 2822252884aeSStefan Eßer } 2823252884aeSStefan Eßer 282444d4804dSStefan Eßer // Also, the remainder and base itself. 2825252884aeSStefan Eßer vm.last_rem = BC_BASE_POW - vm.last_pow; 2826252884aeSStefan Eßer vm.last_base = base; 2827252884aeSStefan Eßer } 2828252884aeSStefan Eßer 2829252884aeSStefan Eßer exp = vm.last_exp; 2830252884aeSStefan Eßer 283144d4804dSStefan Eßer // If vm.last_rem is 0, then the base we are printing in is a divisor of 283244d4804dSStefan Eßer // BC_BASE_POW, which is the easy case because it means that BC_BASE_POW is 283344d4804dSStefan Eßer // a power of obase, and no conversion is needed. If it *is* 0, then we have 283444d4804dSStefan Eßer // the hard case, and we have to prepare the number for the base. 2835252884aeSStefan Eßer if (vm.last_rem != 0) bc_num_printPrepare(&intp, vm.last_rem, vm.last_pow); 2836252884aeSStefan Eßer 283744d4804dSStefan Eßer // After the conversion comes the surprisingly easy part. From here on out, 283844d4804dSStefan Eßer // this is basically naive code that I wrote, adjusted for the larger bases. 283944d4804dSStefan Eßer 284044d4804dSStefan Eßer // Fill the stack of digits for the integer part. 2841252884aeSStefan Eßer for (i = 0; i < intp.len; ++i) { 2842252884aeSStefan Eßer 284344d4804dSStefan Eßer // Get the limb. 2844252884aeSStefan Eßer acc = (BcBigDig) intp.num[i]; 2845252884aeSStefan Eßer 284644d4804dSStefan Eßer // Turn the limb into digits of base obase. 2847252884aeSStefan Eßer for (j = 0; j < exp && (i < intp.len - 1 || acc != 0); ++j) 2848252884aeSStefan Eßer { 284944d4804dSStefan Eßer // This condition is true if we are not at the last digit. 2850252884aeSStefan Eßer if (j != exp - 1) { 2851252884aeSStefan Eßer dig = acc % base; 2852252884aeSStefan Eßer acc /= base; 2853252884aeSStefan Eßer } 2854252884aeSStefan Eßer else { 2855252884aeSStefan Eßer dig = acc; 2856252884aeSStefan Eßer acc = 0; 2857252884aeSStefan Eßer } 2858252884aeSStefan Eßer 2859252884aeSStefan Eßer assert(dig < base); 2860252884aeSStefan Eßer 286144d4804dSStefan Eßer // Push the digit onto the stack. 2862252884aeSStefan Eßer bc_vec_push(&stack, &dig); 2863252884aeSStefan Eßer } 2864252884aeSStefan Eßer 2865252884aeSStefan Eßer assert(acc == 0); 2866252884aeSStefan Eßer } 2867252884aeSStefan Eßer 286844d4804dSStefan Eßer // Go through the stack backwards and print each digit. 2869252884aeSStefan Eßer for (i = 0; i < stack.len; ++i) { 287044d4804dSStefan Eßer 2871252884aeSStefan Eßer ptr = bc_vec_item_rev(&stack, i); 287244d4804dSStefan Eßer 2873252884aeSStefan Eßer assert(ptr != NULL); 287444d4804dSStefan Eßer 287544d4804dSStefan Eßer // While the first three arguments should be self-explanatory, the last 287644d4804dSStefan Eßer // needs explaining. I don't want to print a newline when the last digit 287744d4804dSStefan Eßer // to be printed could take the place of the backslash rather than being 287844d4804dSStefan Eßer // pushed, as a single character, to the next line. That's what that 287944d4804dSStefan Eßer // last argument does for bc. 288044d4804dSStefan Eßer print(*ptr, len, false, !newline || 288144d4804dSStefan Eßer (n->scale != 0 || i == stack.len - 1)); 2882252884aeSStefan Eßer } 2883252884aeSStefan Eßer 288444d4804dSStefan Eßer // We are done if there is no fractional part. 2885252884aeSStefan Eßer if (!n->scale) goto err; 2886252884aeSStefan Eßer 2887252884aeSStefan Eßer BC_SIG_LOCK; 2888252884aeSStefan Eßer 288944d4804dSStefan Eßer // Reset the jump because some locals are changing. 2890252884aeSStefan Eßer BC_UNSETJMP; 2891252884aeSStefan Eßer 289250696a6eSStefan Eßer bc_num_init(&fracp2, nrdx); 2893252884aeSStefan Eßer bc_num_setup(&digit, digit_digs, sizeof(digit_digs) / sizeof(BcDig)); 2894252884aeSStefan Eßer bc_num_init(&flen1, BC_NUM_BIGDIG_LOG10); 2895252884aeSStefan Eßer bc_num_init(&flen2, BC_NUM_BIGDIG_LOG10); 2896252884aeSStefan Eßer 2897252884aeSStefan Eßer BC_SETJMP_LOCKED(frac_err); 2898252884aeSStefan Eßer 2899252884aeSStefan Eßer BC_SIG_UNLOCK; 2900252884aeSStefan Eßer 2901252884aeSStefan Eßer bc_num_one(&flen1); 2902252884aeSStefan Eßer 2903252884aeSStefan Eßer radix = true; 290444d4804dSStefan Eßer 290544d4804dSStefan Eßer // Pointers for easy switching. 2906252884aeSStefan Eßer n1 = &flen1; 2907252884aeSStefan Eßer n2 = &flen2; 2908252884aeSStefan Eßer 2909252884aeSStefan Eßer fracp2.scale = n->scale; 291050696a6eSStefan Eßer BC_NUM_RDX_SET_NP(fracp2, BC_NUM_RDX(fracp2.scale)); 2911252884aeSStefan Eßer 291244d4804dSStefan Eßer // As long as we have not reached the scale of the number, keep printing. 291344d4804dSStefan Eßer while ((idigits = bc_num_intDigits(n1)) <= n->scale) { 2914252884aeSStefan Eßer 291544d4804dSStefan Eßer // These numbers will keep growing. 2916252884aeSStefan Eßer bc_num_expand(&fracp2, fracp1.len + 1); 2917252884aeSStefan Eßer bc_num_mulArray(&fracp1, base, &fracp2); 291850696a6eSStefan Eßer 291950696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL_NP(fracp2); 292050696a6eSStefan Eßer 292144d4804dSStefan Eßer // Ensure an invariant. 292250696a6eSStefan Eßer if (fracp2.len < nrdx) fracp2.len = nrdx; 2923252884aeSStefan Eßer 2924252884aeSStefan Eßer // fracp is guaranteed to be non-negative and small enough. 292544d4804dSStefan Eßer dig = bc_num_bigdig2(&fracp2); 2926252884aeSStefan Eßer 292744d4804dSStefan Eßer // Convert the digit to a number and subtract it from the number. 2928252884aeSStefan Eßer bc_num_bigdig2num(&digit, dig); 2929252884aeSStefan Eßer bc_num_sub(&fracp2, &digit, &fracp1, 0); 2930252884aeSStefan Eßer 293144d4804dSStefan Eßer // While the first three arguments should be self-explanatory, the last 293244d4804dSStefan Eßer // needs explaining. I don't want to print a newline when the last digit 293344d4804dSStefan Eßer // to be printed could take the place of the backslash rather than being 293444d4804dSStefan Eßer // pushed, as a single character, to the next line. That's what that 293544d4804dSStefan Eßer // last argument does for bc. 293644d4804dSStefan Eßer print(dig, len, radix, !newline || idigits != n->scale); 293744d4804dSStefan Eßer 293844d4804dSStefan Eßer // Update the multipliers. 2939252884aeSStefan Eßer bc_num_mulArray(n1, base, n2); 2940252884aeSStefan Eßer 2941252884aeSStefan Eßer radix = false; 294244d4804dSStefan Eßer 294344d4804dSStefan Eßer // Switch. 2944252884aeSStefan Eßer temp = n1; 2945252884aeSStefan Eßer n1 = n2; 2946252884aeSStefan Eßer n2 = temp; 2947252884aeSStefan Eßer } 2948252884aeSStefan Eßer 2949252884aeSStefan Eßer frac_err: 2950252884aeSStefan Eßer BC_SIG_MAYLOCK; 2951252884aeSStefan Eßer bc_num_free(&flen2); 2952252884aeSStefan Eßer bc_num_free(&flen1); 2953252884aeSStefan Eßer bc_num_free(&fracp2); 2954252884aeSStefan Eßer err: 2955252884aeSStefan Eßer BC_SIG_MAYLOCK; 2956252884aeSStefan Eßer bc_num_free(&fracp1); 2957252884aeSStefan Eßer bc_num_free(&intp); 2958252884aeSStefan Eßer bc_vec_free(&stack); 2959252884aeSStefan Eßer BC_LONGJMP_CONT; 2960252884aeSStefan Eßer } 2961252884aeSStefan Eßer 296244d4804dSStefan Eßer /** 296344d4804dSStefan Eßer * Prints a number in the specified base, or rather, figures out which function 296444d4804dSStefan Eßer * to call to print the number in the specified base and calls it. 296544d4804dSStefan Eßer * @param n The number to print. 296644d4804dSStefan Eßer * @param base The base to print in. 296744d4804dSStefan Eßer * @param newline Whether to print backslash+newlines on long enough lines. 296844d4804dSStefan Eßer */ 296944d4804dSStefan Eßer static void bc_num_printBase(BcNum *restrict n, BcBigDig base, bool newline) { 2970252884aeSStefan Eßer 2971252884aeSStefan Eßer size_t width; 2972252884aeSStefan Eßer BcNumDigitOp print; 297350696a6eSStefan Eßer bool neg = BC_NUM_NEG(n); 2974252884aeSStefan Eßer 297544d4804dSStefan Eßer // Clear the sign because it makes the actual printing easier when we have 297644d4804dSStefan Eßer // to do math. 297750696a6eSStefan Eßer BC_NUM_NEG_CLR(n); 2978252884aeSStefan Eßer 297944d4804dSStefan Eßer // Bases at hexadecimal and below are printed as one character, larger bases 298044d4804dSStefan Eßer // are printed as a series of digits separated by spaces. 2981252884aeSStefan Eßer if (base <= BC_NUM_MAX_POSIX_IBASE) { 2982252884aeSStefan Eßer width = 1; 2983252884aeSStefan Eßer print = bc_num_printHex; 2984252884aeSStefan Eßer } 2985252884aeSStefan Eßer else { 2986252884aeSStefan Eßer assert(base <= BC_BASE_POW); 2987252884aeSStefan Eßer width = bc_num_log10(base - 1); 2988252884aeSStefan Eßer print = bc_num_printDigits; 2989252884aeSStefan Eßer } 2990252884aeSStefan Eßer 299144d4804dSStefan Eßer // Print. 299244d4804dSStefan Eßer bc_num_printNum(n, base, width, print, newline); 299344d4804dSStefan Eßer 299444d4804dSStefan Eßer // Reset the sign. 299550696a6eSStefan Eßer n->rdx = BC_NUM_NEG_VAL(n, neg); 2996252884aeSStefan Eßer } 2997252884aeSStefan Eßer 299844d4804dSStefan Eßer #if !BC_ENABLE_LIBRARY 299944d4804dSStefan Eßer 300044d4804dSStefan Eßer void bc_num_stream(BcNum *restrict n) { 300144d4804dSStefan Eßer bc_num_printNum(n, BC_NUM_STREAM_BASE, 1, bc_num_printChar, false); 3002252884aeSStefan Eßer } 300344d4804dSStefan Eßer 300444d4804dSStefan Eßer #endif // !BC_ENABLE_LIBRARY 3005252884aeSStefan Eßer 3006252884aeSStefan Eßer void bc_num_setup(BcNum *restrict n, BcDig *restrict num, size_t cap) { 3007252884aeSStefan Eßer assert(n != NULL); 3008252884aeSStefan Eßer n->num = num; 3009252884aeSStefan Eßer n->cap = cap; 3010252884aeSStefan Eßer bc_num_zero(n); 3011252884aeSStefan Eßer } 3012252884aeSStefan Eßer 3013252884aeSStefan Eßer void bc_num_init(BcNum *restrict n, size_t req) { 3014252884aeSStefan Eßer 3015252884aeSStefan Eßer BcDig *num; 3016252884aeSStefan Eßer 3017252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 3018252884aeSStefan Eßer 3019252884aeSStefan Eßer assert(n != NULL); 3020252884aeSStefan Eßer 302144d4804dSStefan Eßer // BC_NUM_DEF_SIZE is set to be about the smallest allocation size that 302244d4804dSStefan Eßer // malloc() returns in practice, so just use it. 3023252884aeSStefan Eßer req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; 3024252884aeSStefan Eßer 302544d4804dSStefan Eßer // If we can't use a temp, allocate. 302644d4804dSStefan Eßer if (req != BC_NUM_DEF_SIZE || (num = bc_vm_takeTemp()) == NULL) 302744d4804dSStefan Eßer num = bc_vm_malloc(BC_NUM_SIZE(req)); 3028252884aeSStefan Eßer 3029252884aeSStefan Eßer bc_num_setup(n, num, req); 3030252884aeSStefan Eßer } 3031252884aeSStefan Eßer 3032252884aeSStefan Eßer void bc_num_clear(BcNum *restrict n) { 3033252884aeSStefan Eßer n->num = NULL; 3034252884aeSStefan Eßer n->cap = 0; 3035252884aeSStefan Eßer } 3036252884aeSStefan Eßer 3037252884aeSStefan Eßer void bc_num_free(void *num) { 3038252884aeSStefan Eßer 3039252884aeSStefan Eßer BcNum *n = (BcNum*) num; 3040252884aeSStefan Eßer 3041252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 3042252884aeSStefan Eßer 3043252884aeSStefan Eßer assert(n != NULL); 3044252884aeSStefan Eßer 304544d4804dSStefan Eßer if (n->cap == BC_NUM_DEF_SIZE) bc_vm_addTemp(n->num); 3046252884aeSStefan Eßer else free(n->num); 3047252884aeSStefan Eßer } 3048252884aeSStefan Eßer 3049252884aeSStefan Eßer void bc_num_copy(BcNum *d, const BcNum *s) { 305044d4804dSStefan Eßer 3051252884aeSStefan Eßer assert(d != NULL && s != NULL); 305244d4804dSStefan Eßer 3053252884aeSStefan Eßer if (d == s) return; 305444d4804dSStefan Eßer 3055252884aeSStefan Eßer bc_num_expand(d, s->len); 3056252884aeSStefan Eßer d->len = s->len; 305744d4804dSStefan Eßer 305844d4804dSStefan Eßer // I can just copy directly here because the sign *and* rdx will be 305944d4804dSStefan Eßer // properly preserved. 3060252884aeSStefan Eßer d->rdx = s->rdx; 3061252884aeSStefan Eßer d->scale = s->scale; 3062252884aeSStefan Eßer memcpy(d->num, s->num, BC_NUM_SIZE(d->len)); 3063252884aeSStefan Eßer } 3064252884aeSStefan Eßer 3065252884aeSStefan Eßer void bc_num_createCopy(BcNum *d, const BcNum *s) { 3066252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 3067252884aeSStefan Eßer bc_num_init(d, s->len); 3068252884aeSStefan Eßer bc_num_copy(d, s); 3069252884aeSStefan Eßer } 3070252884aeSStefan Eßer 307144d4804dSStefan Eßer void bc_num_createFromBigdig(BcNum *restrict n, BcBigDig val) { 3072252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 307350696a6eSStefan Eßer bc_num_init(n, BC_NUM_BIGDIG_LOG10); 3074252884aeSStefan Eßer bc_num_bigdig2num(n, val); 3075252884aeSStefan Eßer } 3076252884aeSStefan Eßer 3077252884aeSStefan Eßer size_t bc_num_scale(const BcNum *restrict n) { 3078252884aeSStefan Eßer return n->scale; 3079252884aeSStefan Eßer } 3080252884aeSStefan Eßer 3081252884aeSStefan Eßer size_t bc_num_len(const BcNum *restrict n) { 3082252884aeSStefan Eßer 3083252884aeSStefan Eßer size_t len = n->len; 3084252884aeSStefan Eßer 308544d4804dSStefan Eßer // Always return at least 1. 3086028616d0SStefan Eßer if (BC_NUM_ZERO(n)) return n->scale ? n->scale : 1; 3087252884aeSStefan Eßer 308844d4804dSStefan Eßer // If this is true, there is no integer portion of the number. 308950696a6eSStefan Eßer if (BC_NUM_RDX_VAL(n) == len) { 3090252884aeSStefan Eßer 309144d4804dSStefan Eßer // We have to take into account the fact that some of the digits right 309244d4804dSStefan Eßer // after the decimal could be zero. If that is the case, we need to 309344d4804dSStefan Eßer // ignore them until we hit the first non-zero digit. 309444d4804dSStefan Eßer 3095252884aeSStefan Eßer size_t zero, scale; 3096252884aeSStefan Eßer 309744d4804dSStefan Eßer // The number of limbs with non-zero digits. 309844d4804dSStefan Eßer len = bc_num_nonZeroLen(n); 3099252884aeSStefan Eßer 310044d4804dSStefan Eßer // Get the number of digits in the last limb. 3101252884aeSStefan Eßer scale = n->scale % BC_BASE_DIGS; 3102252884aeSStefan Eßer scale = scale ? scale : BC_BASE_DIGS; 3103252884aeSStefan Eßer 310444d4804dSStefan Eßer // Get the number of zero digits. 3105252884aeSStefan Eßer zero = bc_num_zeroDigits(n->num + len - 1); 3106252884aeSStefan Eßer 310744d4804dSStefan Eßer // Calculate the true length. 3108252884aeSStefan Eßer len = len * BC_BASE_DIGS - zero - (BC_BASE_DIGS - scale); 3109252884aeSStefan Eßer } 311044d4804dSStefan Eßer // Otherwise, count the number of int digits and return that plus the scale. 3111252884aeSStefan Eßer else len = bc_num_intDigits(n) + n->scale; 3112252884aeSStefan Eßer 3113252884aeSStefan Eßer return len; 3114252884aeSStefan Eßer } 3115252884aeSStefan Eßer 311650696a6eSStefan Eßer void bc_num_parse(BcNum *restrict n, const char *restrict val, BcBigDig base) { 311750696a6eSStefan Eßer 3118252884aeSStefan Eßer assert(n != NULL && val != NULL && base); 3119252884aeSStefan Eßer assert(base >= BC_NUM_MIN_BASE && base <= vm.maxes[BC_PROG_GLOBALS_IBASE]); 3120252884aeSStefan Eßer assert(bc_num_strValid(val)); 3121252884aeSStefan Eßer 312244d4804dSStefan Eßer // A one character number is *always* parsed as though the base was the 312344d4804dSStefan Eßer // maximum allowed ibase, per the bc spec. 312450696a6eSStefan Eßer if (!val[1]) { 3125252884aeSStefan Eßer BcBigDig dig = bc_num_parseChar(val[0], BC_NUM_MAX_LBASE); 3126252884aeSStefan Eßer bc_num_bigdig2num(n, dig); 3127252884aeSStefan Eßer } 3128252884aeSStefan Eßer else if (base == BC_BASE) bc_num_parseDecimal(n, val); 3129252884aeSStefan Eßer else bc_num_parseBase(n, val, base); 313050696a6eSStefan Eßer 313150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(n)); 3132252884aeSStefan Eßer } 3133252884aeSStefan Eßer 3134252884aeSStefan Eßer void bc_num_print(BcNum *restrict n, BcBigDig base, bool newline) { 3135252884aeSStefan Eßer 3136252884aeSStefan Eßer assert(n != NULL); 3137252884aeSStefan Eßer assert(BC_ENABLE_EXTRA_MATH || base >= BC_NUM_MIN_BASE); 3138252884aeSStefan Eßer 313944d4804dSStefan Eßer // We may need a newline, just to start. 3140252884aeSStefan Eßer bc_num_printNewline(); 3141252884aeSStefan Eßer 3142*d43fa8efSStefan Eßer if (BC_NUM_NONZERO(n)) { 3143*d43fa8efSStefan Eßer 3144*d43fa8efSStefan Eßer // Print the sign. 3145*d43fa8efSStefan Eßer if (BC_NUM_NEG(n)) bc_num_putchar('-', true); 3146*d43fa8efSStefan Eßer 3147*d43fa8efSStefan Eßer // Print the leading zero if necessary. 3148*d43fa8efSStefan Eßer if (BC_Z && BC_NUM_RDX_VAL(n) == n->len) 3149*d43fa8efSStefan Eßer bc_num_printHex(0, 1, false, !newline); 3150*d43fa8efSStefan Eßer } 3151*d43fa8efSStefan Eßer 315244d4804dSStefan Eßer // Short-circuit 0. 315344d4804dSStefan Eßer if (BC_NUM_ZERO(n)) bc_num_printHex(0, 1, false, !newline); 315444d4804dSStefan Eßer else if (base == BC_BASE) bc_num_printDecimal(n, newline); 3155252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 315644d4804dSStefan Eßer else if (base == 0 || base == 1) 315744d4804dSStefan Eßer bc_num_printExponent(n, base != 0, newline); 3158252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 315944d4804dSStefan Eßer else bc_num_printBase(n, base, newline); 3160252884aeSStefan Eßer 316144d4804dSStefan Eßer if (newline) bc_num_putchar('\n', false); 3162252884aeSStefan Eßer } 3163252884aeSStefan Eßer 316444d4804dSStefan Eßer BcBigDig bc_num_bigdig2(const BcNum *restrict n) { 3165252884aeSStefan Eßer 3166252884aeSStefan Eßer // This function returns no errors because it's guaranteed to succeed if 316744d4804dSStefan Eßer // its preconditions are met. Those preconditions include both n needs to 316844d4804dSStefan Eßer // be non-NULL, n being non-negative, and n being less than vm.max. If all 316944d4804dSStefan Eßer // of that is true, then we can just convert without worrying about negative 317044d4804dSStefan Eßer // errors or overflow. 3171252884aeSStefan Eßer 3172252884aeSStefan Eßer BcBigDig r = 0; 317350696a6eSStefan Eßer size_t nrdx = BC_NUM_RDX_VAL(n); 3174252884aeSStefan Eßer 317544d4804dSStefan Eßer assert(n != NULL); 317650696a6eSStefan Eßer assert(!BC_NUM_NEG(n)); 3177252884aeSStefan Eßer assert(bc_num_cmp(n, &vm.max) < 0); 317850696a6eSStefan Eßer assert(n->len - nrdx <= 3); 3179252884aeSStefan Eßer 3180252884aeSStefan Eßer // There is a small speed win from unrolling the loop here, and since it 3181252884aeSStefan Eßer // only adds 53 bytes, I decided that it was worth it. 318250696a6eSStefan Eßer switch (n->len - nrdx) { 318350696a6eSStefan Eßer 3184252884aeSStefan Eßer case 3: 318550696a6eSStefan Eßer { 318650696a6eSStefan Eßer r = (BcBigDig) n->num[nrdx + 2]; 318750696a6eSStefan Eßer } 3188252884aeSStefan Eßer // Fallthrough. 318950696a6eSStefan Eßer BC_FALLTHROUGH 319050696a6eSStefan Eßer 3191252884aeSStefan Eßer case 2: 319250696a6eSStefan Eßer { 319350696a6eSStefan Eßer r = r * BC_BASE_POW + (BcBigDig) n->num[nrdx + 1]; 319450696a6eSStefan Eßer } 3195252884aeSStefan Eßer // Fallthrough. 319650696a6eSStefan Eßer BC_FALLTHROUGH 319750696a6eSStefan Eßer 3198252884aeSStefan Eßer case 1: 319950696a6eSStefan Eßer { 320050696a6eSStefan Eßer r = r * BC_BASE_POW + (BcBigDig) n->num[nrdx]; 320150696a6eSStefan Eßer } 3202252884aeSStefan Eßer } 3203252884aeSStefan Eßer 320444d4804dSStefan Eßer return r; 3205252884aeSStefan Eßer } 3206252884aeSStefan Eßer 320744d4804dSStefan Eßer BcBigDig bc_num_bigdig(const BcNum *restrict n) { 3208252884aeSStefan Eßer 320944d4804dSStefan Eßer assert(n != NULL); 3210252884aeSStefan Eßer 321144d4804dSStefan Eßer // This error checking is extremely important, and if you do not have a 321244d4804dSStefan Eßer // guarantee that converting a number will always succeed in a particular 321344d4804dSStefan Eßer // case, you *must* call this function to get these error checks. This 321444d4804dSStefan Eßer // includes all instances of numbers inputted by the user or calculated by 321544d4804dSStefan Eßer // the user. Otherwise, you can call the faster bc_num_bigdig2(). 321644d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(n))) bc_err(BC_ERR_MATH_NEGATIVE); 321744d4804dSStefan Eßer if (BC_ERR(bc_num_cmp(n, &vm.max) >= 0)) bc_err(BC_ERR_MATH_OVERFLOW); 3218252884aeSStefan Eßer 321944d4804dSStefan Eßer return bc_num_bigdig2(n); 3220252884aeSStefan Eßer } 3221252884aeSStefan Eßer 3222252884aeSStefan Eßer void bc_num_bigdig2num(BcNum *restrict n, BcBigDig val) { 3223252884aeSStefan Eßer 3224252884aeSStefan Eßer BcDig *ptr; 3225252884aeSStefan Eßer size_t i; 3226252884aeSStefan Eßer 3227252884aeSStefan Eßer assert(n != NULL); 3228252884aeSStefan Eßer 3229252884aeSStefan Eßer bc_num_zero(n); 3230252884aeSStefan Eßer 323144d4804dSStefan Eßer // Already 0. 3232252884aeSStefan Eßer if (!val) return; 3233252884aeSStefan Eßer 323444d4804dSStefan Eßer // Expand first. This is the only way this function can fail, and it's a 323544d4804dSStefan Eßer // fatal error. 3236252884aeSStefan Eßer bc_num_expand(n, BC_NUM_BIGDIG_LOG10); 3237252884aeSStefan Eßer 323844d4804dSStefan Eßer // The conversion is easy because numbers are laid out in little-endian 323944d4804dSStefan Eßer // order. 3240252884aeSStefan Eßer for (ptr = n->num, i = 0; val; ++i, val /= BC_BASE_POW) 3241252884aeSStefan Eßer ptr[i] = val % BC_BASE_POW; 3242252884aeSStefan Eßer 3243252884aeSStefan Eßer n->len = i; 3244252884aeSStefan Eßer } 3245252884aeSStefan Eßer 324644d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 324744d4804dSStefan Eßer 3248252884aeSStefan Eßer void bc_num_rng(const BcNum *restrict n, BcRNG *rng) { 3249252884aeSStefan Eßer 325050696a6eSStefan Eßer BcNum temp, temp2, intn, frac; 3251252884aeSStefan Eßer BcRand state1, state2, inc1, inc2; 325250696a6eSStefan Eßer size_t nrdx = BC_NUM_RDX_VAL(n); 3253252884aeSStefan Eßer 325444d4804dSStefan Eßer // This function holds the secret of how I interpret a seed number for the 325544d4804dSStefan Eßer // PRNG. Well, it's actually in the development manual 325644d4804dSStefan Eßer // (manuals/development.md#pseudo-random-number-generator), so look there 325744d4804dSStefan Eßer // before you try to understand this. 325844d4804dSStefan Eßer 3259252884aeSStefan Eßer BC_SIG_LOCK; 3260252884aeSStefan Eßer 3261252884aeSStefan Eßer bc_num_init(&temp, n->len); 3262252884aeSStefan Eßer bc_num_init(&temp2, n->len); 326350696a6eSStefan Eßer bc_num_init(&frac, nrdx); 3264252884aeSStefan Eßer bc_num_init(&intn, bc_num_int(n)); 3265252884aeSStefan Eßer 3266252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3267252884aeSStefan Eßer 3268252884aeSStefan Eßer BC_SIG_UNLOCK; 3269252884aeSStefan Eßer 327050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(vm.max)); 3271252884aeSStefan Eßer 327250696a6eSStefan Eßer memcpy(frac.num, n->num, BC_NUM_SIZE(nrdx)); 327350696a6eSStefan Eßer frac.len = nrdx; 327450696a6eSStefan Eßer BC_NUM_RDX_SET_NP(frac, nrdx); 3275252884aeSStefan Eßer frac.scale = n->scale; 3276252884aeSStefan Eßer 327750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(frac)); 327850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(vm.max2)); 327950696a6eSStefan Eßer 328044d4804dSStefan Eßer // Multiply the fraction and truncate so that it's an integer. The 328144d4804dSStefan Eßer // truncation is what clamps it, by the way. 328250696a6eSStefan Eßer bc_num_mul(&frac, &vm.max2, &temp, 0); 3283252884aeSStefan Eßer bc_num_truncate(&temp, temp.scale); 3284252884aeSStefan Eßer bc_num_copy(&frac, &temp); 3285252884aeSStefan Eßer 328644d4804dSStefan Eßer // Get the integer. 328750696a6eSStefan Eßer memcpy(intn.num, n->num + nrdx, BC_NUM_SIZE(bc_num_int(n))); 3288252884aeSStefan Eßer intn.len = bc_num_int(n); 3289252884aeSStefan Eßer 3290252884aeSStefan Eßer // This assert is here because it has to be true. It is also here to justify 329144d4804dSStefan Eßer // some optimizations. 3292252884aeSStefan Eßer assert(BC_NUM_NONZERO(&vm.max)); 3293252884aeSStefan Eßer 329444d4804dSStefan Eßer // If there *was* a fractional part... 3295252884aeSStefan Eßer if (BC_NUM_NONZERO(&frac)) { 3296252884aeSStefan Eßer 329744d4804dSStefan Eßer // This divmod splits frac into the two state parts. 3298252884aeSStefan Eßer bc_num_divmod(&frac, &vm.max, &temp, &temp2, 0); 3299252884aeSStefan Eßer 3300252884aeSStefan Eßer // frac is guaranteed to be smaller than vm.max * vm.max (pow). 3301252884aeSStefan Eßer // This means that when dividing frac by vm.max, as above, the 3302252884aeSStefan Eßer // quotient and remainder are both guaranteed to be less than vm.max, 3303252884aeSStefan Eßer // which means we can use bc_num_bigdig2() here and not worry about 3304252884aeSStefan Eßer // overflow. 330544d4804dSStefan Eßer state1 = (BcRand) bc_num_bigdig2(&temp2); 330644d4804dSStefan Eßer state2 = (BcRand) bc_num_bigdig2(&temp); 3307252884aeSStefan Eßer } 3308252884aeSStefan Eßer else state1 = state2 = 0; 3309252884aeSStefan Eßer 331044d4804dSStefan Eßer // If there *was* an integer part... 3311252884aeSStefan Eßer if (BC_NUM_NONZERO(&intn)) { 3312252884aeSStefan Eßer 331344d4804dSStefan Eßer // This divmod splits intn into the two inc parts. 3314252884aeSStefan Eßer bc_num_divmod(&intn, &vm.max, &temp, &temp2, 0); 3315252884aeSStefan Eßer 3316252884aeSStefan Eßer // Because temp2 is the mod of vm.max, from above, it is guaranteed 3317252884aeSStefan Eßer // to be small enough to use bc_num_bigdig2(). 331844d4804dSStefan Eßer inc1 = (BcRand) bc_num_bigdig2(&temp2); 3319252884aeSStefan Eßer 332044d4804dSStefan Eßer // Clamp the second inc part. 3321252884aeSStefan Eßer if (bc_num_cmp(&temp, &vm.max) >= 0) { 3322252884aeSStefan Eßer bc_num_copy(&temp2, &temp); 3323252884aeSStefan Eßer bc_num_mod(&temp2, &vm.max, &temp, 0); 3324252884aeSStefan Eßer } 3325252884aeSStefan Eßer 3326252884aeSStefan Eßer // The if statement above ensures that temp is less than vm.max, which 3327252884aeSStefan Eßer // means that we can use bc_num_bigdig2() here. 332844d4804dSStefan Eßer inc2 = (BcRand) bc_num_bigdig2(&temp); 3329252884aeSStefan Eßer } 3330252884aeSStefan Eßer else inc1 = inc2 = 0; 3331252884aeSStefan Eßer 3332252884aeSStefan Eßer bc_rand_seed(rng, state1, state2, inc1, inc2); 3333252884aeSStefan Eßer 3334252884aeSStefan Eßer err: 3335252884aeSStefan Eßer BC_SIG_MAYLOCK; 3336252884aeSStefan Eßer bc_num_free(&intn); 3337252884aeSStefan Eßer bc_num_free(&frac); 3338252884aeSStefan Eßer bc_num_free(&temp2); 3339252884aeSStefan Eßer bc_num_free(&temp); 3340252884aeSStefan Eßer BC_LONGJMP_CONT; 3341252884aeSStefan Eßer } 3342252884aeSStefan Eßer 3343252884aeSStefan Eßer void bc_num_createFromRNG(BcNum *restrict n, BcRNG *rng) { 3344252884aeSStefan Eßer 3345252884aeSStefan Eßer BcRand s1, s2, i1, i2; 334650696a6eSStefan Eßer BcNum conv, temp1, temp2, temp3; 3347252884aeSStefan Eßer BcDig temp1_num[BC_RAND_NUM_SIZE], temp2_num[BC_RAND_NUM_SIZE]; 3348252884aeSStefan Eßer BcDig conv_num[BC_NUM_BIGDIG_LOG10]; 3349252884aeSStefan Eßer 3350252884aeSStefan Eßer BC_SIG_LOCK; 3351252884aeSStefan Eßer 3352252884aeSStefan Eßer bc_num_init(&temp3, 2 * BC_RAND_NUM_SIZE); 3353252884aeSStefan Eßer 3354252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3355252884aeSStefan Eßer 3356252884aeSStefan Eßer BC_SIG_UNLOCK; 3357252884aeSStefan Eßer 3358252884aeSStefan Eßer bc_num_setup(&temp1, temp1_num, sizeof(temp1_num) / sizeof(BcDig)); 3359252884aeSStefan Eßer bc_num_setup(&temp2, temp2_num, sizeof(temp2_num) / sizeof(BcDig)); 3360252884aeSStefan Eßer bc_num_setup(&conv, conv_num, sizeof(conv_num) / sizeof(BcDig)); 3361252884aeSStefan Eßer 3362252884aeSStefan Eßer // This assert is here because it has to be true. It is also here to justify 336344d4804dSStefan Eßer // the assumption that vm.max is not zero. 3364252884aeSStefan Eßer assert(BC_NUM_NONZERO(&vm.max)); 3365252884aeSStefan Eßer 336644d4804dSStefan Eßer // Because this is true, we can just ignore math errors that would happen 336744d4804dSStefan Eßer // otherwise. 336850696a6eSStefan Eßer assert(BC_NUM_NONZERO(&vm.max2)); 3369252884aeSStefan Eßer 3370252884aeSStefan Eßer bc_rand_getRands(rng, &s1, &s2, &i1, &i2); 3371252884aeSStefan Eßer 337244d4804dSStefan Eßer // Put the second piece of state into a number. 3373252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) s2); 3374252884aeSStefan Eßer 337550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(conv)); 337650696a6eSStefan Eßer 337744d4804dSStefan Eßer // Multiply by max to make room for the first piece of state. 3378252884aeSStefan Eßer bc_num_mul(&conv, &vm.max, &temp1, 0); 3379252884aeSStefan Eßer 338044d4804dSStefan Eßer // Add in the first piece of state. 3381252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) s1); 3382252884aeSStefan Eßer bc_num_add(&conv, &temp1, &temp2, 0); 3383252884aeSStefan Eßer 338444d4804dSStefan Eßer // Divide to make it an entirely fractional part. 338550696a6eSStefan Eßer bc_num_div(&temp2, &vm.max2, &temp3, BC_RAND_STATE_BITS); 3386252884aeSStefan Eßer 338744d4804dSStefan Eßer // Now start on the increment parts. It's the same process without the 338844d4804dSStefan Eßer // divide, so put the second piece of increment into a number. 3389252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) i2); 3390252884aeSStefan Eßer 339150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(conv)); 339250696a6eSStefan Eßer 339344d4804dSStefan Eßer // Multiply by max to make room for the first piece of increment. 3394252884aeSStefan Eßer bc_num_mul(&conv, &vm.max, &temp1, 0); 3395252884aeSStefan Eßer 339644d4804dSStefan Eßer // Add in the first piece of increment. 3397252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) i1); 3398252884aeSStefan Eßer bc_num_add(&conv, &temp1, &temp2, 0); 3399252884aeSStefan Eßer 340044d4804dSStefan Eßer // Now add the two together. 3401252884aeSStefan Eßer bc_num_add(&temp2, &temp3, n, 0); 3402252884aeSStefan Eßer 340350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(n)); 340450696a6eSStefan Eßer 3405252884aeSStefan Eßer err: 3406252884aeSStefan Eßer BC_SIG_MAYLOCK; 3407252884aeSStefan Eßer bc_num_free(&temp3); 3408252884aeSStefan Eßer BC_LONGJMP_CONT; 3409252884aeSStefan Eßer } 3410252884aeSStefan Eßer 341144d4804dSStefan Eßer void bc_num_irand(BcNum *restrict a, BcNum *restrict b, BcRNG *restrict rng) { 341244d4804dSStefan Eßer 341344d4804dSStefan Eßer BcNum atemp; 341444d4804dSStefan Eßer size_t i, len; 3415252884aeSStefan Eßer 3416252884aeSStefan Eßer assert(a != b); 3417252884aeSStefan Eßer 341844d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(a))) bc_err(BC_ERR_MATH_NEGATIVE); 341944d4804dSStefan Eßer 342044d4804dSStefan Eßer // If either of these are true, then the numbers are integers. 3421252884aeSStefan Eßer if (BC_NUM_ZERO(a) || BC_NUM_ONE(a)) return; 3422252884aeSStefan Eßer 342344d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(a, &atemp))) bc_err(BC_ERR_MATH_NON_INTEGER); 3424252884aeSStefan Eßer 342544d4804dSStefan Eßer assert(atemp.len); 3426252884aeSStefan Eßer 342744d4804dSStefan Eßer len = atemp.len - 1; 3428252884aeSStefan Eßer 342944d4804dSStefan Eßer // Just generate a random number for each limb. 343044d4804dSStefan Eßer for (i = 0; i < len; ++i) 343144d4804dSStefan Eßer b->num[i] = (BcDig) bc_rand_bounded(rng, BC_BASE_POW); 3432252884aeSStefan Eßer 343344d4804dSStefan Eßer // Do the last digit explicitly because the bound must be right. But only 343444d4804dSStefan Eßer // do it if the limb does not equal 1. If it does, we have already hit the 343544d4804dSStefan Eßer // limit. 343644d4804dSStefan Eßer if (atemp.num[i] != 1) { 343744d4804dSStefan Eßer b->num[i] = (BcDig) bc_rand_bounded(rng, (BcRand) atemp.num[i]); 343844d4804dSStefan Eßer b->len = atemp.len; 3439252884aeSStefan Eßer } 344044d4804dSStefan Eßer // We want 1 less len in the case where we skip the last limb. 344144d4804dSStefan Eßer else b->len = len; 3442252884aeSStefan Eßer 3443252884aeSStefan Eßer bc_num_clean(b); 3444252884aeSStefan Eßer 344550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3446252884aeSStefan Eßer } 344744d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 3448252884aeSStefan Eßer 3449252884aeSStefan Eßer size_t bc_num_addReq(const BcNum *a, const BcNum *b, size_t scale) { 3450252884aeSStefan Eßer 3451252884aeSStefan Eßer size_t aint, bint, ardx, brdx; 3452252884aeSStefan Eßer 345344d4804dSStefan Eßer // Addition and subtraction require the max of the length of the two numbers 345444d4804dSStefan Eßer // plus 1. 345544d4804dSStefan Eßer 3456252884aeSStefan Eßer BC_UNUSED(scale); 3457252884aeSStefan Eßer 345850696a6eSStefan Eßer ardx = BC_NUM_RDX_VAL(a); 3459252884aeSStefan Eßer aint = bc_num_int(a); 3460252884aeSStefan Eßer assert(aint <= a->len && ardx <= a->len); 3461252884aeSStefan Eßer 346250696a6eSStefan Eßer brdx = BC_NUM_RDX_VAL(b); 3463252884aeSStefan Eßer bint = bc_num_int(b); 3464252884aeSStefan Eßer assert(bint <= b->len && brdx <= b->len); 3465252884aeSStefan Eßer 3466252884aeSStefan Eßer ardx = BC_MAX(ardx, brdx); 3467252884aeSStefan Eßer aint = BC_MAX(aint, bint); 3468252884aeSStefan Eßer 3469252884aeSStefan Eßer return bc_vm_growSize(bc_vm_growSize(ardx, aint), 1); 3470252884aeSStefan Eßer } 3471252884aeSStefan Eßer 3472252884aeSStefan Eßer size_t bc_num_mulReq(const BcNum *a, const BcNum *b, size_t scale) { 347344d4804dSStefan Eßer 3474252884aeSStefan Eßer size_t max, rdx; 347544d4804dSStefan Eßer 347644d4804dSStefan Eßer // Multiplication requires the sum of the lengths of the numbers. 347744d4804dSStefan Eßer 347850696a6eSStefan Eßer rdx = bc_vm_growSize(BC_NUM_RDX_VAL(a), BC_NUM_RDX_VAL(b)); 347944d4804dSStefan Eßer 3480252884aeSStefan Eßer max = BC_NUM_RDX(scale); 348144d4804dSStefan Eßer 3482252884aeSStefan Eßer max = bc_vm_growSize(BC_MAX(max, rdx), 1); 3483252884aeSStefan Eßer rdx = bc_vm_growSize(bc_vm_growSize(bc_num_int(a), bc_num_int(b)), max); 348444d4804dSStefan Eßer 3485252884aeSStefan Eßer return rdx; 3486252884aeSStefan Eßer } 3487252884aeSStefan Eßer 348850696a6eSStefan Eßer size_t bc_num_divReq(const BcNum *a, const BcNum *b, size_t scale) { 348944d4804dSStefan Eßer 349050696a6eSStefan Eßer size_t max, rdx; 349144d4804dSStefan Eßer 349244d4804dSStefan Eßer // Division requires the length of the dividend plus the scale. 349344d4804dSStefan Eßer 349450696a6eSStefan Eßer rdx = bc_vm_growSize(BC_NUM_RDX_VAL(a), BC_NUM_RDX_VAL(b)); 349544d4804dSStefan Eßer 349650696a6eSStefan Eßer max = BC_NUM_RDX(scale); 349744d4804dSStefan Eßer 349850696a6eSStefan Eßer max = bc_vm_growSize(BC_MAX(max, rdx), 1); 349950696a6eSStefan Eßer rdx = bc_vm_growSize(bc_num_int(a), max); 350044d4804dSStefan Eßer 350150696a6eSStefan Eßer return rdx; 350250696a6eSStefan Eßer } 350350696a6eSStefan Eßer 3504252884aeSStefan Eßer size_t bc_num_powReq(const BcNum *a, const BcNum *b, size_t scale) { 3505252884aeSStefan Eßer BC_UNUSED(scale); 3506252884aeSStefan Eßer return bc_vm_growSize(bc_vm_growSize(a->len, b->len), 1); 3507252884aeSStefan Eßer } 3508252884aeSStefan Eßer 3509252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 3510252884aeSStefan Eßer size_t bc_num_placesReq(const BcNum *a, const BcNum *b, size_t scale) { 3511252884aeSStefan Eßer BC_UNUSED(scale); 351250696a6eSStefan Eßer return a->len + b->len - BC_NUM_RDX_VAL(a) - BC_NUM_RDX_VAL(b); 3513252884aeSStefan Eßer } 3514252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 3515252884aeSStefan Eßer 3516252884aeSStefan Eßer void bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 351750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 351850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3519252884aeSStefan Eßer bc_num_binary(a, b, c, false, bc_num_as, bc_num_addReq(a, b, scale)); 3520252884aeSStefan Eßer } 3521252884aeSStefan Eßer 3522252884aeSStefan Eßer void bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 352350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 352450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3525252884aeSStefan Eßer bc_num_binary(a, b, c, true, bc_num_as, bc_num_addReq(a, b, scale)); 3526252884aeSStefan Eßer } 3527252884aeSStefan Eßer 3528252884aeSStefan Eßer void bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 352950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 353050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3531252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_m, bc_num_mulReq(a, b, scale)); 3532252884aeSStefan Eßer } 3533252884aeSStefan Eßer 3534252884aeSStefan Eßer void bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 353550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 353650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 353750696a6eSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_d, bc_num_divReq(a, b, scale)); 3538252884aeSStefan Eßer } 3539252884aeSStefan Eßer 3540252884aeSStefan Eßer void bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 354150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 354250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 354350696a6eSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_rem, bc_num_divReq(a, b, scale)); 3544252884aeSStefan Eßer } 3545252884aeSStefan Eßer 3546252884aeSStefan Eßer void bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 354750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 354850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3549252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_p, bc_num_powReq(a, b, scale)); 3550252884aeSStefan Eßer } 3551252884aeSStefan Eßer 3552252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 3553252884aeSStefan Eßer void bc_num_places(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 355450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 355550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3556252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_place, bc_num_placesReq(a, b, scale)); 3557252884aeSStefan Eßer } 3558252884aeSStefan Eßer 3559252884aeSStefan Eßer void bc_num_lshift(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 356050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 356150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3562252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_left, bc_num_placesReq(a, b, scale)); 3563252884aeSStefan Eßer } 3564252884aeSStefan Eßer 3565252884aeSStefan Eßer void bc_num_rshift(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 356650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 356750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3568252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_right, bc_num_placesReq(a, b, scale)); 3569252884aeSStefan Eßer } 3570252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 3571252884aeSStefan Eßer 3572252884aeSStefan Eßer void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) { 3573252884aeSStefan Eßer 3574252884aeSStefan Eßer BcNum num1, num2, half, f, fprime, *x0, *x1, *temp; 357510328f8bSStefan Eßer size_t pow, len, rdx, req, resscale; 3576252884aeSStefan Eßer BcDig half_digs[1]; 3577252884aeSStefan Eßer 3578252884aeSStefan Eßer assert(a != NULL && b != NULL && a != b); 3579252884aeSStefan Eßer 358044d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(a))) bc_err(BC_ERR_MATH_NEGATIVE); 3581252884aeSStefan Eßer 358244d4804dSStefan Eßer // We want to calculate to a's scale if it is bigger so that the result will 358344d4804dSStefan Eßer // truncate properly. 3584252884aeSStefan Eßer if (a->scale > scale) scale = a->scale; 3585252884aeSStefan Eßer 358644d4804dSStefan Eßer // Set parameters for the result. 3587252884aeSStefan Eßer len = bc_vm_growSize(bc_num_intDigits(a), 1); 3588252884aeSStefan Eßer rdx = BC_NUM_RDX(scale); 358944d4804dSStefan Eßer 359044d4804dSStefan Eßer // Square root needs half of the length of the parameter. 359150696a6eSStefan Eßer req = bc_vm_growSize(BC_MAX(rdx, BC_NUM_RDX_VAL(a)), len >> 1); 3592252884aeSStefan Eßer 3593252884aeSStefan Eßer BC_SIG_LOCK; 3594252884aeSStefan Eßer 359544d4804dSStefan Eßer // Unlike the binary operators, this function is the only single parameter 359644d4804dSStefan Eßer // function and is expected to initialize the result. This means that it 359744d4804dSStefan Eßer // expects that b is *NOT* preallocated. We allocate it here. 3598252884aeSStefan Eßer bc_num_init(b, bc_vm_growSize(req, 1)); 3599252884aeSStefan Eßer 3600252884aeSStefan Eßer BC_SIG_UNLOCK; 3601252884aeSStefan Eßer 360250696a6eSStefan Eßer assert(a != NULL && b != NULL && a != b); 360350696a6eSStefan Eßer assert(a->num != NULL && b->num != NULL); 360450696a6eSStefan Eßer 360544d4804dSStefan Eßer // Easy case. 3606252884aeSStefan Eßer if (BC_NUM_ZERO(a)) { 3607252884aeSStefan Eßer bc_num_setToZero(b, scale); 3608252884aeSStefan Eßer return; 3609252884aeSStefan Eßer } 361044d4804dSStefan Eßer 361144d4804dSStefan Eßer // Another easy case. 3612252884aeSStefan Eßer if (BC_NUM_ONE(a)) { 3613252884aeSStefan Eßer bc_num_one(b); 3614252884aeSStefan Eßer bc_num_extend(b, scale); 3615252884aeSStefan Eßer return; 3616252884aeSStefan Eßer } 3617252884aeSStefan Eßer 361844d4804dSStefan Eßer // Set the parameters again. 3619252884aeSStefan Eßer rdx = BC_NUM_RDX(scale); 362050696a6eSStefan Eßer rdx = BC_MAX(rdx, BC_NUM_RDX_VAL(a)); 3621252884aeSStefan Eßer len = bc_vm_growSize(a->len, rdx); 3622252884aeSStefan Eßer 3623252884aeSStefan Eßer BC_SIG_LOCK; 3624252884aeSStefan Eßer 3625252884aeSStefan Eßer bc_num_init(&num1, len); 3626252884aeSStefan Eßer bc_num_init(&num2, len); 3627252884aeSStefan Eßer bc_num_setup(&half, half_digs, sizeof(half_digs) / sizeof(BcDig)); 3628252884aeSStefan Eßer 362944d4804dSStefan Eßer // There is a division by two in the formula. We setup a number that's 1/2 363044d4804dSStefan Eßer // so that we can use multiplication instead of heavy division. 3631252884aeSStefan Eßer bc_num_one(&half); 3632252884aeSStefan Eßer half.num[0] = BC_BASE_POW / 2; 3633252884aeSStefan Eßer half.len = 1; 363450696a6eSStefan Eßer BC_NUM_RDX_SET_NP(half, 1); 3635252884aeSStefan Eßer half.scale = 1; 3636252884aeSStefan Eßer 3637252884aeSStefan Eßer bc_num_init(&f, len); 3638252884aeSStefan Eßer bc_num_init(&fprime, len); 3639252884aeSStefan Eßer 3640252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3641252884aeSStefan Eßer 3642252884aeSStefan Eßer BC_SIG_UNLOCK; 3643252884aeSStefan Eßer 364444d4804dSStefan Eßer // Pointers for easy switching. 3645252884aeSStefan Eßer x0 = &num1; 3646252884aeSStefan Eßer x1 = &num2; 3647252884aeSStefan Eßer 364844d4804dSStefan Eßer // Start with 1. 3649252884aeSStefan Eßer bc_num_one(x0); 365044d4804dSStefan Eßer 365144d4804dSStefan Eßer // The power of the operand is needed for the estimate. 3652252884aeSStefan Eßer pow = bc_num_intDigits(a); 3653252884aeSStefan Eßer 365444d4804dSStefan Eßer // The code in this if statement calculates the initial estimate. First, if 365544d4804dSStefan Eßer // a is less than 0, then 0 is a good estimate. Otherwise, we want something 365644d4804dSStefan Eßer // in the same ballpark. That ballpark is pow. 3657252884aeSStefan Eßer if (pow) { 3658252884aeSStefan Eßer 365944d4804dSStefan Eßer // An odd number is served by starting with 2^((pow-1)/2), and an even 366044d4804dSStefan Eßer // number is served by starting with 6^((pow-2)/2). Why? Because math. 3661252884aeSStefan Eßer if (pow & 1) x0->num[0] = 2; 3662252884aeSStefan Eßer else x0->num[0] = 6; 3663252884aeSStefan Eßer 3664252884aeSStefan Eßer pow -= 2 - (pow & 1); 3665252884aeSStefan Eßer bc_num_shiftLeft(x0, pow / 2); 3666252884aeSStefan Eßer } 3667252884aeSStefan Eßer 366850696a6eSStefan Eßer // I can set the rdx here directly because neg should be false. 366910328f8bSStefan Eßer x0->scale = x0->rdx = 0; 3670252884aeSStefan Eßer resscale = (scale + BC_BASE_DIGS) + 2; 3671252884aeSStefan Eßer 367244d4804dSStefan Eßer // This is the calculation loop. This compare goes to 0 eventually as the 367344d4804dSStefan Eßer // difference between the two numbers gets smaller than resscale. 3674252884aeSStefan Eßer while (bc_num_cmp(x1, x0)) { 3675252884aeSStefan Eßer 3676252884aeSStefan Eßer assert(BC_NUM_NONZERO(x0)); 3677252884aeSStefan Eßer 367844d4804dSStefan Eßer // This loop directly corresponds to the iteration in Newton's method. 367944d4804dSStefan Eßer // If you know the formula, this loop makes sense. Go study the formula. 368044d4804dSStefan Eßer 3681252884aeSStefan Eßer bc_num_div(a, x0, &f, resscale); 3682252884aeSStefan Eßer bc_num_add(x0, &f, &fprime, resscale); 368350696a6eSStefan Eßer 368450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(fprime)); 368550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(half)); 368650696a6eSStefan Eßer 3687252884aeSStefan Eßer bc_num_mul(&fprime, &half, x1, resscale); 3688252884aeSStefan Eßer 368944d4804dSStefan Eßer // Switch. 3690252884aeSStefan Eßer temp = x0; 3691252884aeSStefan Eßer x0 = x1; 3692252884aeSStefan Eßer x1 = temp; 3693252884aeSStefan Eßer } 3694252884aeSStefan Eßer 369544d4804dSStefan Eßer // Copy to the result and truncate. 3696252884aeSStefan Eßer bc_num_copy(b, x0); 3697252884aeSStefan Eßer if (b->scale > scale) bc_num_truncate(b, b->scale - scale); 3698252884aeSStefan Eßer 369950696a6eSStefan Eßer assert(!BC_NUM_NEG(b) || BC_NUM_NONZERO(b)); 370050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 370150696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(b) <= b->len || !b->len); 370250696a6eSStefan Eßer assert(!b->len || b->num[b->len - 1] || BC_NUM_RDX_VAL(b) == b->len); 3703252884aeSStefan Eßer 3704252884aeSStefan Eßer err: 3705252884aeSStefan Eßer BC_SIG_MAYLOCK; 3706252884aeSStefan Eßer bc_num_free(&fprime); 3707252884aeSStefan Eßer bc_num_free(&f); 3708252884aeSStefan Eßer bc_num_free(&num2); 3709252884aeSStefan Eßer bc_num_free(&num1); 3710252884aeSStefan Eßer BC_LONGJMP_CONT; 3711252884aeSStefan Eßer } 3712252884aeSStefan Eßer 3713252884aeSStefan Eßer void bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) { 3714252884aeSStefan Eßer 3715252884aeSStefan Eßer size_t ts, len; 371650696a6eSStefan Eßer BcNum *ptr_a, num2; 371750696a6eSStefan Eßer bool init = false; 3718252884aeSStefan Eßer 371944d4804dSStefan Eßer // The bulk of this function is just doing what bc_num_binary() does for the 372044d4804dSStefan Eßer // binary operators. However, it assumes that only c and a can be equal. 372144d4804dSStefan Eßer 372244d4804dSStefan Eßer // Set up the parameters. 3723252884aeSStefan Eßer ts = BC_MAX(scale + b->scale, a->scale); 3724252884aeSStefan Eßer len = bc_num_mulReq(a, b, ts); 3725252884aeSStefan Eßer 3726252884aeSStefan Eßer assert(a != NULL && b != NULL && c != NULL && d != NULL); 3727252884aeSStefan Eßer assert(c != d && a != d && b != d && b != c); 3728252884aeSStefan Eßer 372944d4804dSStefan Eßer // Initialize or expand as necessary. 3730252884aeSStefan Eßer if (c == a) { 3731252884aeSStefan Eßer 3732252884aeSStefan Eßer memcpy(&num2, c, sizeof(BcNum)); 3733252884aeSStefan Eßer ptr_a = &num2; 3734252884aeSStefan Eßer 3735252884aeSStefan Eßer BC_SIG_LOCK; 3736252884aeSStefan Eßer 3737252884aeSStefan Eßer bc_num_init(c, len); 3738252884aeSStefan Eßer 3739252884aeSStefan Eßer init = true; 3740252884aeSStefan Eßer 3741252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3742252884aeSStefan Eßer 3743252884aeSStefan Eßer BC_SIG_UNLOCK; 3744252884aeSStefan Eßer } 3745252884aeSStefan Eßer else { 3746252884aeSStefan Eßer ptr_a = a; 3747252884aeSStefan Eßer bc_num_expand(c, len); 3748252884aeSStefan Eßer } 3749252884aeSStefan Eßer 375044d4804dSStefan Eßer // Do the quick version if possible. 375150696a6eSStefan Eßer if (BC_NUM_NONZERO(a) && !BC_NUM_RDX_VAL(a) && 375250696a6eSStefan Eßer !BC_NUM_RDX_VAL(b) && b->len == 1 && !scale) 375350696a6eSStefan Eßer { 3754252884aeSStefan Eßer BcBigDig rem; 3755252884aeSStefan Eßer 3756252884aeSStefan Eßer bc_num_divArray(ptr_a, (BcBigDig) b->num[0], c, &rem); 3757252884aeSStefan Eßer 3758252884aeSStefan Eßer assert(rem < BC_BASE_POW); 3759252884aeSStefan Eßer 3760252884aeSStefan Eßer d->num[0] = (BcDig) rem; 3761252884aeSStefan Eßer d->len = (rem != 0); 3762252884aeSStefan Eßer } 376344d4804dSStefan Eßer // Do the slow method. 3764252884aeSStefan Eßer else bc_num_r(ptr_a, b, c, d, scale, ts); 3765252884aeSStefan Eßer 376650696a6eSStefan Eßer assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c)); 376750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(c)); 376850696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len); 376950696a6eSStefan Eßer assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len); 377050696a6eSStefan Eßer assert(!BC_NUM_NEG(d) || BC_NUM_NONZERO(d)); 377150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(d)); 377250696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(d) <= d->len || !d->len); 377350696a6eSStefan Eßer assert(!d->len || d->num[d->len - 1] || BC_NUM_RDX_VAL(d) == d->len); 3774252884aeSStefan Eßer 3775252884aeSStefan Eßer err: 377644d4804dSStefan Eßer // Only cleanup if we initialized. 3777252884aeSStefan Eßer if (init) { 3778252884aeSStefan Eßer BC_SIG_MAYLOCK; 3779252884aeSStefan Eßer bc_num_free(&num2); 3780252884aeSStefan Eßer BC_LONGJMP_CONT; 3781252884aeSStefan Eßer } 3782252884aeSStefan Eßer } 3783252884aeSStefan Eßer 3784252884aeSStefan Eßer void bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d) { 3785252884aeSStefan Eßer 378644d4804dSStefan Eßer BcNum base, exp, two, temp, atemp, btemp, ctemp; 3787252884aeSStefan Eßer BcDig two_digs[2]; 3788252884aeSStefan Eßer 3789252884aeSStefan Eßer assert(a != NULL && b != NULL && c != NULL && d != NULL); 3790252884aeSStefan Eßer assert(a != d && b != d && c != d); 3791252884aeSStefan Eßer 379244d4804dSStefan Eßer if (BC_ERR(BC_NUM_ZERO(c))) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); 3793252884aeSStefan Eßer 379444d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(b))) bc_err(BC_ERR_MATH_NEGATIVE); 379544d4804dSStefan Eßer 379644d4804dSStefan Eßer #ifndef NDEBUG 379744d4804dSStefan Eßer // This is entirely for quieting a useless scan-build error. 379844d4804dSStefan Eßer btemp.len = 0; 379944d4804dSStefan Eßer ctemp.len = 0; 380044d4804dSStefan Eßer #endif // NDEBUG 380144d4804dSStefan Eßer 380244d4804dSStefan Eßer // Eliminate fractional parts that are zero or error if they are not zero. 380344d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(a, &atemp) || bc_num_nonInt(b, &btemp) || 380444d4804dSStefan Eßer bc_num_nonInt(c, &ctemp))) 380544d4804dSStefan Eßer { 380644d4804dSStefan Eßer bc_err(BC_ERR_MATH_NON_INTEGER); 380744d4804dSStefan Eßer } 380844d4804dSStefan Eßer 380944d4804dSStefan Eßer bc_num_expand(d, ctemp.len); 3810252884aeSStefan Eßer 3811252884aeSStefan Eßer BC_SIG_LOCK; 3812252884aeSStefan Eßer 381344d4804dSStefan Eßer bc_num_init(&base, ctemp.len); 3814252884aeSStefan Eßer bc_num_setup(&two, two_digs, sizeof(two_digs) / sizeof(BcDig)); 381544d4804dSStefan Eßer bc_num_init(&temp, btemp.len + 1); 381644d4804dSStefan Eßer bc_num_createCopy(&exp, &btemp); 3817252884aeSStefan Eßer 3818252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3819252884aeSStefan Eßer 3820252884aeSStefan Eßer BC_SIG_UNLOCK; 3821252884aeSStefan Eßer 3822252884aeSStefan Eßer bc_num_one(&two); 3823252884aeSStefan Eßer two.num[0] = 2; 3824252884aeSStefan Eßer bc_num_one(d); 3825252884aeSStefan Eßer 3826252884aeSStefan Eßer // We already checked for 0. 382744d4804dSStefan Eßer bc_num_rem(&atemp, &ctemp, &base, 0); 3828252884aeSStefan Eßer 382944d4804dSStefan Eßer // If you know the algorithm I used, the memory-efficient method, then this 383044d4804dSStefan Eßer // loop should be self-explanatory because it is the calculation loop. 3831252884aeSStefan Eßer while (BC_NUM_NONZERO(&exp)) { 3832252884aeSStefan Eßer 3833252884aeSStefan Eßer // Num two cannot be 0, so no errors. 3834252884aeSStefan Eßer bc_num_divmod(&exp, &two, &exp, &temp, 0); 3835252884aeSStefan Eßer 383650696a6eSStefan Eßer if (BC_NUM_ONE(&temp) && !BC_NUM_NEG_NP(temp)) { 383750696a6eSStefan Eßer 383850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(d)); 383950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(base)); 3840252884aeSStefan Eßer 3841252884aeSStefan Eßer bc_num_mul(d, &base, &temp, 0); 3842252884aeSStefan Eßer 3843252884aeSStefan Eßer // We already checked for 0. 384444d4804dSStefan Eßer bc_num_rem(&temp, &ctemp, d, 0); 3845252884aeSStefan Eßer } 3846252884aeSStefan Eßer 384750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(base)); 384850696a6eSStefan Eßer 3849252884aeSStefan Eßer bc_num_mul(&base, &base, &temp, 0); 3850252884aeSStefan Eßer 3851252884aeSStefan Eßer // We already checked for 0. 385244d4804dSStefan Eßer bc_num_rem(&temp, &ctemp, &base, 0); 3853252884aeSStefan Eßer } 3854252884aeSStefan Eßer 3855252884aeSStefan Eßer err: 3856252884aeSStefan Eßer BC_SIG_MAYLOCK; 3857252884aeSStefan Eßer bc_num_free(&exp); 3858252884aeSStefan Eßer bc_num_free(&temp); 3859252884aeSStefan Eßer bc_num_free(&base); 3860252884aeSStefan Eßer BC_LONGJMP_CONT; 386150696a6eSStefan Eßer assert(!BC_NUM_NEG(d) || d->len); 386250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(d)); 386350696a6eSStefan Eßer assert(!d->len || d->num[d->len - 1] || BC_NUM_RDX_VAL(d) == d->len); 3864252884aeSStefan Eßer } 3865252884aeSStefan Eßer 3866252884aeSStefan Eßer #if BC_DEBUG_CODE 3867252884aeSStefan Eßer void bc_num_printDebug(const BcNum *n, const char *name, bool emptyline) { 38687e5c51e5SStefan Eßer bc_file_puts(&vm.fout, bc_flush_none, name); 38697e5c51e5SStefan Eßer bc_file_puts(&vm.fout, bc_flush_none, ": "); 387044d4804dSStefan Eßer bc_num_printDecimal(n, true); 38717e5c51e5SStefan Eßer bc_file_putchar(&vm.fout, bc_flush_err, '\n'); 38727e5c51e5SStefan Eßer if (emptyline) bc_file_putchar(&vm.fout, bc_flush_err, '\n'); 3873252884aeSStefan Eßer vm.nchars = 0; 3874252884aeSStefan Eßer } 3875252884aeSStefan Eßer 3876252884aeSStefan Eßer void bc_num_printDigs(const BcDig *n, size_t len, bool emptyline) { 3877252884aeSStefan Eßer 3878252884aeSStefan Eßer size_t i; 3879252884aeSStefan Eßer 3880252884aeSStefan Eßer for (i = len - 1; i < len; --i) 3881252884aeSStefan Eßer bc_file_printf(&vm.fout, " %lu", (unsigned long) n[i]); 3882252884aeSStefan Eßer 38837e5c51e5SStefan Eßer bc_file_putchar(&vm.fout, bc_flush_err, '\n'); 38847e5c51e5SStefan Eßer if (emptyline) bc_file_putchar(&vm.fout, bc_flush_err, '\n'); 3885252884aeSStefan Eßer vm.nchars = 0; 3886252884aeSStefan Eßer } 3887252884aeSStefan Eßer 3888252884aeSStefan Eßer void bc_num_printWithDigs(const BcNum *n, const char *name, bool emptyline) { 38897e5c51e5SStefan Eßer bc_file_puts(&vm.fout, bc_flush_none, name); 3890252884aeSStefan Eßer bc_file_printf(&vm.fout, " len: %zu, rdx: %zu, scale: %zu\n", 389150696a6eSStefan Eßer name, n->len, BC_NUM_RDX_VAL(n), n->scale); 3892252884aeSStefan Eßer bc_num_printDigs(n->num, n->len, emptyline); 3893252884aeSStefan Eßer } 3894252884aeSStefan Eßer 3895252884aeSStefan Eßer void bc_num_dump(const char *varname, const BcNum *n) { 3896252884aeSStefan Eßer 3897252884aeSStefan Eßer ulong i, scale = n->scale; 3898252884aeSStefan Eßer 3899252884aeSStefan Eßer bc_file_printf(&vm.ferr, "\n%s = %s", varname, 390050696a6eSStefan Eßer n->len ? (BC_NUM_NEG(n) ? "-" : "+") : "0 "); 3901252884aeSStefan Eßer 3902252884aeSStefan Eßer for (i = n->len - 1; i < n->len; --i) { 3903252884aeSStefan Eßer 39047e5c51e5SStefan Eßer if (i + 1 == BC_NUM_RDX_VAL(n)) 39057e5c51e5SStefan Eßer bc_file_puts(&vm.ferr, bc_flush_none, ". "); 3906252884aeSStefan Eßer 390750696a6eSStefan Eßer if (scale / BC_BASE_DIGS != BC_NUM_RDX_VAL(n) - i - 1) 3908252884aeSStefan Eßer bc_file_printf(&vm.ferr, "%lu ", (unsigned long) n->num[i]); 3909252884aeSStefan Eßer else { 3910252884aeSStefan Eßer 3911252884aeSStefan Eßer int mod = scale % BC_BASE_DIGS; 3912252884aeSStefan Eßer int d = BC_BASE_DIGS - mod; 3913252884aeSStefan Eßer BcDig div; 3914252884aeSStefan Eßer 3915252884aeSStefan Eßer if (mod != 0) { 3916252884aeSStefan Eßer div = n->num[i] / ((BcDig) bc_num_pow10[(ulong) d]); 3917252884aeSStefan Eßer bc_file_printf(&vm.ferr, "%lu", (unsigned long) div); 3918252884aeSStefan Eßer } 3919252884aeSStefan Eßer 3920252884aeSStefan Eßer div = n->num[i] % ((BcDig) bc_num_pow10[(ulong) d]); 3921252884aeSStefan Eßer bc_file_printf(&vm.ferr, " ' %lu ", (unsigned long) div); 3922252884aeSStefan Eßer } 3923252884aeSStefan Eßer } 3924252884aeSStefan Eßer 3925252884aeSStefan Eßer bc_file_printf(&vm.ferr, "(%zu | %zu.%zu / %zu) %lu\n", 392650696a6eSStefan Eßer n->scale, n->len, BC_NUM_RDX_VAL(n), n->cap, 3927252884aeSStefan Eßer (unsigned long) (void*) n->num); 39287e5c51e5SStefan Eßer 39297e5c51e5SStefan Eßer bc_file_flush(&vm.ferr, bc_flush_err); 3930252884aeSStefan Eßer } 3931252884aeSStefan Eßer #endif // BC_DEBUG_CODE 3932