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 48*44d4804dSStefan Eßer // Before you try to understand this code, see the development manual 49*44d4804dSStefan Eßer // (manuals/development.md#numbers). 50*44d4804dSStefan Eßer 51252884aeSStefan Eßer static void bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale); 52252884aeSStefan Eßer 53*44d4804dSStefan Eßer /** 54*44d4804dSStefan Eßer * Multiply two numbers and throw a math error if they overflow. 55*44d4804dSStefan Eßer * @param a The first operand. 56*44d4804dSStefan Eßer * @param b The second operand. 57*44d4804dSStefan Eßer * @return The product of the two operands. 58*44d4804dSStefan Eßer */ 59*44d4804dSStefan Eßer static inline size_t bc_num_mulOverflow(size_t a, size_t b) { 60*44d4804dSStefan Eßer size_t res = a * b; 61*44d4804dSStefan Eßer if (BC_ERR(BC_VM_MUL_OVERFLOW(a, b, res))) bc_err(BC_ERR_MATH_OVERFLOW); 62*44d4804dSStefan Eßer return res; 63*44d4804dSStefan Eßer } 64*44d4804dSStefan Eßer 65*44d4804dSStefan Eßer /** 66*44d4804dSStefan Eßer * Conditionally negate @a n based on @a neg. Algorithm taken from 67*44d4804dSStefan Eßer * https://graphics.stanford.edu/~seander/bithacks.html#ConditionalNegate . 68*44d4804dSStefan Eßer * @param n The value to turn into a signed value and negate. 69*44d4804dSStefan Eßer * @param neg The condition to negate or not. 70*44d4804dSStefan 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 75*44d4804dSStefan Eßer /** 76*44d4804dSStefan Eßer * Compare a BcNum against zero. 77*44d4804dSStefan Eßer * @param n The number to compare. 78*44d4804dSStefan Eßer * @return -1 if the number is less than 0, 1 if greater, and 0 if equal. 79*44d4804dSStefan 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 84*44d4804dSStefan Eßer /** 85*44d4804dSStefan Eßer * Return the number of integer limbs in a BcNum. This is the opposite of rdx. 86*44d4804dSStefan Eßer * @param n The number to return the amount of integer limbs for. 87*44d4804dSStefan Eßer * @return The amount of integer limbs in @a n. 88*44d4804dSStefan 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 93*44d4804dSStefan Eßer /** 94*44d4804dSStefan Eßer * Expand a number's allocation capacity to at least req limbs. 95*44d4804dSStefan Eßer * @param n The number to expand. 96*44d4804dSStefan Eßer * @param req The number limbs to expand the allocation capacity to. 97*44d4804dSStefan 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 115*44d4804dSStefan Eßer /** 116*44d4804dSStefan Eßer * Set a number to 0 with the specified scale. 117*44d4804dSStefan Eßer * @param n The number to set to zero. 118*44d4804dSStefan Eßer * @param scale The scale to set the number to. 119*44d4804dSStefan 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 136*44d4804dSStefan Eßer /** 137*44d4804dSStefan Eßer * "Cleans" a number, which means reducing the length if the most significant 138*44d4804dSStefan Eßer * limbs are zero. 139*44d4804dSStefan Eßer * @param n The number to clean. 140*44d4804dSStefan Eßer */ 141252884aeSStefan Eßer static void bc_num_clean(BcNum *restrict n) { 142252884aeSStefan Eßer 143*44d4804dSStefan Eßer // Reduce the length. 144252884aeSStefan Eßer while (BC_NUM_NONZERO(n) && !n->num[n->len - 1]) n->len -= 1; 145252884aeSStefan Eßer 146*44d4804dSStefan Eßer // Special cases. 14750696a6eSStefan Eßer if (BC_NUM_ZERO(n)) n->rdx = 0; 14850696a6eSStefan Eßer else { 149*44d4804dSStefan Eßer 150*44d4804dSStefan 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 156*44d4804dSStefan Eßer /** 157*44d4804dSStefan Eßer * Returns the log base 10 of @a i. I could have done this with floating-point 158*44d4804dSStefan Eßer * math, and in fact, I originally did. However, that was the only 159*44d4804dSStefan Eßer * floating-point code in the entire codebase, and I decided I didn't want any. 160*44d4804dSStefan Eßer * This is fast enough. Also, it might handle larger numbers better. 161*44d4804dSStefan Eßer * @param i The number to return the log base 10 of. 162*44d4804dSStefan Eßer * @return The log base 10 of @a i. 163*44d4804dSStefan 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 171*44d4804dSStefan Eßer /** 172*44d4804dSStefan Eßer * Returns the number of decimal digits in a limb that are zero starting at the 173*44d4804dSStefan Eßer * most significant digits. This basically returns how much of the limb is used. 174*44d4804dSStefan Eßer * @param n The number. 175*44d4804dSStefan Eßer * @return The number of decimal digits that are 0 starting at the most 176*44d4804dSStefan Eßer * significant digits. 177*44d4804dSStefan 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 184*44d4804dSStefan Eßer /** 185*44d4804dSStefan Eßer * Return the total number of integer digits in a number. This is the opposite 186*44d4804dSStefan Eßer * of scale, like bc_num_int() is the opposite of rdx. 187*44d4804dSStefan Eßer * @param n The number. 188*44d4804dSStefan Eßer * @return The number of integer digits in @a n. 189*44d4804dSStefan 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 196*44d4804dSStefan Eßer /** 197*44d4804dSStefan Eßer * Returns the number of limbs of a number that are non-zero starting at the 198*44d4804dSStefan Eßer * most significant limbs. This expects that there are *no* integer limbs in the 199*44d4804dSStefan Eßer * number because it is specifically to figure out how many zero limbs after the 200*44d4804dSStefan Eßer * decimal place to ignore. If there are zero limbs after non-zero limbs, they 201*44d4804dSStefan Eßer * are counted as non-zero limbs. 202*44d4804dSStefan Eßer * @param n The number. 203*44d4804dSStefan Eßer * @return The number of non-zero limbs after the decimal point. 204*44d4804dSStefan Eßer */ 205*44d4804dSStefan 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 213*44d4804dSStefan Eßer /** 214*44d4804dSStefan Eßer * Performs a one-limb add with a carry. 215*44d4804dSStefan Eßer * @param a The first limb. 216*44d4804dSStefan Eßer * @param b The second limb. 217*44d4804dSStefan Eßer * @param carry An in/out parameter; the carry in from the previous add and the 218*44d4804dSStefan Eßer * carry out from this add. 219*44d4804dSStefan Eßer * @return The resulting limb sum. 220*44d4804dSStefan 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 237*44d4804dSStefan Eßer /** 238*44d4804dSStefan Eßer * Performs a one-limb subtract with a carry. 239*44d4804dSStefan Eßer * @param a The first limb. 240*44d4804dSStefan Eßer * @param b The second limb. 241*44d4804dSStefan Eßer * @param carry An in/out parameter; the carry in from the previous subtract 242*44d4804dSStefan Eßer * and the carry out from this subtract. 243*44d4804dSStefan Eßer * @return The resulting limb difference. 244*44d4804dSStefan 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 260*44d4804dSStefan Eßer /** 261*44d4804dSStefan Eßer * Add two BcDig arrays and store the result in the first array. 262*44d4804dSStefan Eßer * @param a The first operand and out array. 263*44d4804dSStefan Eßer * @param b The second operand. 264*44d4804dSStefan Eßer * @param len The length of @a b. 265*44d4804dSStefan 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 274*44d4804dSStefan 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 278*44d4804dSStefan Eßer /** 279*44d4804dSStefan Eßer * Subtract two BcDig arrays and store the result in the first array. 280*44d4804dSStefan Eßer * @param a The first operand and out array. 281*44d4804dSStefan Eßer * @param b The second operand. 282*44d4804dSStefan Eßer * @param len The length of @a b. 283*44d4804dSStefan 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 292*44d4804dSStefan 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 296*44d4804dSStefan Eßer /** 297*44d4804dSStefan Eßer * Multiply a BcNum array by a one-limb number. This is a faster version of 298*44d4804dSStefan Eßer * multiplication for when we can use it. 299*44d4804dSStefan Eßer * @param a The BcNum to multiply by the one-limb number. 300*44d4804dSStefan Eßer * @param b The one limb of the one-limb number. 301*44d4804dSStefan Eßer * @param c The return parameter. 302*44d4804dSStefan 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 311*44d4804dSStefan 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 314*44d4804dSStefan 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 317*44d4804dSStefan 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); 325*44d4804dSStefan Eßer 326*44d4804dSStefan 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 333*44d4804dSStefan 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 339*44d4804dSStefan Eßer /** 340*44d4804dSStefan Eßer * Divide a BcNum array by a one-limb number. This is a faster version of divide 341*44d4804dSStefan Eßer * for when we can use it. 342*44d4804dSStefan Eßer * @param a The BcNum to multiply by the one-limb number. 343*44d4804dSStefan Eßer * @param b The one limb of the one-limb number. 344*44d4804dSStefan Eßer * @param c The return parameter for the quotient. 345*44d4804dSStefan Eßer * @param rem The return parameter for the remainder. 346*44d4804dSStefan 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 355*44d4804dSStefan 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 363*44d4804dSStefan 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 368*44d4804dSStefan 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 374*44d4804dSStefan Eßer /** 375*44d4804dSStefan Eßer * Compare two BcDig arrays and return >0 if @a b is greater, <0 if @a b is 376*44d4804dSStefan Eßer * less, and 0 if equal. Both @a a and @a b must have the same length. 377*44d4804dSStefan Eßer * @param a The first array. 378*44d4804dSStefan Eßer * @param b The second array. 379*44d4804dSStefan Eßer * @param len The minimum length of the arrays. 380*44d4804dSStefan 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 399*44d4804dSStefan Eßer // Same num? Equal. 400252884aeSStefan Eßer if (a == b) return 0; 401*44d4804dSStefan Eßer 402*44d4804dSStefan 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 411*44d4804dSStefan 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 416*44d4804dSStefan 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 419*44d4804dSStefan 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 424*44d4804dSStefan 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 438*44d4804dSStefan 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 441*44d4804dSStefan 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 444*44d4804dSStefan Eßer // If there was no difference, then the final step is to check which number 445*44d4804dSStefan 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 459*44d4804dSStefan Eßer // Grab these needed values; places_rdx is the rdx equivalent to places like 460*44d4804dSStefan 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; 463*44d4804dSStefan Eßer 464*44d4804dSStefan 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 470*44d4804dSStefan 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 475*44d4804dSStefan Eßer // This calculates how many decimal digits are in the least significant 476*44d4804dSStefan 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; 482*44d4804dSStefan Eßer 483*44d4804dSStefan Eßer // We have to move limbs to maintain invariants. The limbs must begin at 484*44d4804dSStefan 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; 499*44d4804dSStefan Eßer 500*44d4804dSStefan 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 506*44d4804dSStefan Eßer // Grab these needed values; places_rdx is the rdx equivalent to places like 507*44d4804dSStefan 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 511*44d4804dSStefan Eßer // This is the hard case. We need to expand the number, move the limbs, and 512*44d4804dSStefan 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 519*44d4804dSStefan 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 527*44d4804dSStefan Eßer /** 528*44d4804dSStefan Eßer * Retires (finishes) a multiplication or division operation. 529*44d4804dSStefan 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 { 533*44d4804dSStefan 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); 538*44d4804dSStefan Eßer 539*44d4804dSStefan 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 543*44d4804dSStefan Eßer /** 544*44d4804dSStefan Eßer * Splits a number into two BcNum's. This is used in Karatsuba. 545*44d4804dSStefan Eßer * @param n The number to split. 546*44d4804dSStefan Eßer * @param idx The index to split at. 547*44d4804dSStefan Eßer * @param a An out parameter; the low part of @a n. 548*44d4804dSStefan Eßer * @param b An out parameter; the high part of @a n. 549*44d4804dSStefan 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 { 553*44d4804dSStefan 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 557*44d4804dSStefan Eßer // The usual case. 558252884aeSStefan Eßer if (idx < n->len) { 559252884aeSStefan Eßer 560*44d4804dSStefan 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 570*44d4804dSStefan Eßer // Copy the arrays. This is not necessary for safety, but it is faster, 571*44d4804dSStefan 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 } 577*44d4804dSStefan 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 583*44d4804dSStefan Eßer /** 584*44d4804dSStefan Eßer * Copies a number into another, but shifts the rdx so that the result number 585*44d4804dSStefan Eßer * only sees the integer part of the source number. 586*44d4804dSStefan Eßer * @param n The number to copy. 587*44d4804dSStefan Eßer * @param r The result number with a shifted rdx, len, and num. 588*44d4804dSStefan Eßer */ 589*44d4804dSStefan Eßer static void bc_num_shiftRdx(const BcNum *restrict n, BcNum *restrict r) { 590*44d4804dSStefan Eßer 591*44d4804dSStefan Eßer size_t rdx = BC_NUM_RDX_VAL(n); 592*44d4804dSStefan Eßer 593*44d4804dSStefan Eßer r->len = n->len - rdx; 594*44d4804dSStefan Eßer r->cap = n->cap - rdx; 595*44d4804dSStefan Eßer r->num = n->num + rdx; 596*44d4804dSStefan Eßer 597*44d4804dSStefan Eßer BC_NUM_RDX_SET_NEG(r, 0, BC_NUM_NEG(n)); 598*44d4804dSStefan Eßer r->scale = 0; 599*44d4804dSStefan Eßer } 600*44d4804dSStefan Eßer 601*44d4804dSStefan Eßer /** 602*44d4804dSStefan Eßer * Shifts a number so that all of the least significant limbs of the number are 603*44d4804dSStefan Eßer * skipped. This must be undone by bc_num_unshiftZero(). 604*44d4804dSStefan Eßer * @param n The number to shift. 605*44d4804dSStefan 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 610*44d4804dSStefan Eßer // If we don't have an integer, that is a problem, but it's also a bug 611*44d4804dSStefan 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 622*44d4804dSStefan Eßer /** 623*44d4804dSStefan Eßer * Undo the damage done by bc_num_unshiftZero(). This must be called like all 624*44d4804dSStefan Eßer * cleanup functions: after a label used by setjmp() and longjmp(). 625*44d4804dSStefan Eßer * @param n The number to unshift. 626*44d4804dSStefan Eßer * @param places_rdx The amount the number was originally shift. 627*44d4804dSStefan 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 633*44d4804dSStefan Eßer /** 634*44d4804dSStefan Eßer * Shifts the digits right within a number by no more than BC_BASE_DIGS - 1. 635*44d4804dSStefan Eßer * This is the final step on shifting numbers with the shift operators. It 636*44d4804dSStefan Eßer * depends on the caller to shift the limbs properly because all it does is 637*44d4804dSStefan Eßer * ensure that the rdx point is realigned to be between limbs. 638*44d4804dSStefan Eßer * @param n The number to shift digits in. 639*44d4804dSStefan Eßer * @param dig The number of places to shift right. 640*44d4804dSStefan 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 649*44d4804dSStefan 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 653*44d4804dSStefan Eßer // Run a series of divisions and mods with carries across the entire number 654*44d4804dSStefan 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 666*44d4804dSStefan Eßer /** 667*44d4804dSStefan Eßer * Shift a number left by a certain number of places. This is the workhorse of 668*44d4804dSStefan Eßer * the left shift operator. 669*44d4804dSStefan Eßer * @param n The number to shift left. 670*44d4804dSStefan Eßer * @param places The amount of places to shift @a n left by. 671*44d4804dSStefan 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; 679*44d4804dSStefan Eßer 680*44d4804dSStefan 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); 683*44d4804dSStefan Eßer if (size > SIZE_MAX - 1) bc_err(BC_ERR_MATH_OVERFLOW); 684252884aeSStefan Eßer } 685*44d4804dSStefan Eßer 686*44d4804dSStefan 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 693*44d4804dSStefan Eßer // When I changed bc to have multiple digits per limb, this was the hardest 694*44d4804dSStefan Eßer // code to change. This and shift right. Make sure you understand this 695*44d4804dSStefan Eßer // before attempting anything. 696*44d4804dSStefan Eßer 697*44d4804dSStefan 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); 700*44d4804dSStefan Eßer 701*44d4804dSStefan Eßer // Convert places to a rdx value. 702252884aeSStefan Eßer places_rdx = BC_NUM_RDX(places); 703252884aeSStefan Eßer 704*44d4804dSStefan Eßer // If the number is not an integer, we need special care. The reason an 705*44d4804dSStefan Eßer // integer doesn't is because left shift would only extend the integer, 706*44d4804dSStefan Eßer // whereas a non-integer might have its fractional part eliminated or only 707*44d4804dSStefan 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 712*44d4804dSStefan 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 717*44d4804dSStefan Eßer // We want mod to be in the range [1, BC_BASE_DIGS], not 718*44d4804dSStefan Eßer // [0, BC_BASE_DIGS). 719252884aeSStefan Eßer mod = mod ? mod : BC_BASE_DIGS; 720*44d4804dSStefan Eßer 721*44d4804dSStefan 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 724*44d4804dSStefan 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 731*44d4804dSStefan 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 739*44d4804dSStefan 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 749*44d4804dSStefan 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; 762*44d4804dSStefan Eßer 763*44d4804dSStefan 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 770*44d4804dSStefan 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); 773*44d4804dSStefan Eßer 774252884aeSStefan Eßer scale = n->scale; 775*44d4804dSStefan Eßer 776*44d4804dSStefan 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; 779*44d4804dSStefan Eßer 780*44d4804dSStefan 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 784*44d4804dSStefan 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 794*44d4804dSStefan Eßer // Clamp expanding. 795252884aeSStefan Eßer if (expand > int_len) expand -= int_len; 796252884aeSStefan Eßer else expand = 0; 797252884aeSStefan Eßer 798*44d4804dSStefan 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)); 802*44d4804dSStefan Eßer 803*44d4804dSStefan 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 808*44d4804dSStefan 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 820*44d4804dSStefan Eßer /** 821*44d4804dSStefan Eßer * Invert @a into @a b at the current scale. 822*44d4804dSStefan Eßer * @param a The number to invert. 823*44d4804dSStefan Eßer * @param b The return parameter. This must be preallocated. 824*44d4804dSStefan Eßer * @param scale The current scale. 825*44d4804dSStefan Eßer */ 826*44d4804dSStefan Eßer static inline void bc_num_inv(BcNum *a, BcNum *b, size_t scale) { 827252884aeSStefan Eßer assert(BC_NUM_NONZERO(a)); 828*44d4804dSStefan Eßer bc_num_div(&vm.one, a, b, scale); 829*44d4804dSStefan Eßer } 830252884aeSStefan Eßer 831*44d4804dSStefan Eßer /** 832*44d4804dSStefan Eßer * Tests if a number is a integer with scale or not. Returns true if the number 833*44d4804dSStefan Eßer * is not an integer. If it is, its integer shifted form is copied into the 834*44d4804dSStefan Eßer * result parameter for use where only integers are allowed. 835*44d4804dSStefan Eßer * @param n The integer to test and shift. 836*44d4804dSStefan Eßer * @param r The number to store the shifted result into. This number should 837*44d4804dSStefan Eßer * *not* be allocated. 838*44d4804dSStefan Eßer * @return True if the number is a non-integer, false otherwise. 839*44d4804dSStefan Eßer */ 840*44d4804dSStefan Eßer static bool bc_num_nonInt(const BcNum *restrict n, BcNum *restrict r) { 841252884aeSStefan Eßer 842*44d4804dSStefan Eßer bool zero; 843*44d4804dSStefan Eßer size_t i, rdx = BC_NUM_RDX_VAL(n); 844*44d4804dSStefan Eßer 845*44d4804dSStefan Eßer if (!rdx) { 846*44d4804dSStefan Eßer memcpy(r, n, sizeof(BcNum)); 847*44d4804dSStefan Eßer return false; 848*44d4804dSStefan Eßer } 849*44d4804dSStefan Eßer 850*44d4804dSStefan Eßer zero = true; 851*44d4804dSStefan Eßer 852*44d4804dSStefan Eßer for (i = 0; zero && i < rdx; ++i) zero = (n->num[i] == 0); 853*44d4804dSStefan Eßer 854*44d4804dSStefan Eßer if (BC_ERR(!zero)) return true; 855*44d4804dSStefan Eßer 856*44d4804dSStefan Eßer bc_num_shiftRdx(n, r); 857*44d4804dSStefan Eßer 858*44d4804dSStefan Eßer return false; 859252884aeSStefan Eßer } 860252884aeSStefan Eßer 861252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 862*44d4804dSStefan Eßer 863*44d4804dSStefan Eßer /** 864*44d4804dSStefan Eßer * Execute common code for an operater that needs an integer for the second 865*44d4804dSStefan Eßer * operand and return the integer operand as a BcBigDig. 866*44d4804dSStefan Eßer * @param a The first operand. 867*44d4804dSStefan Eßer * @param b The second operand. 868*44d4804dSStefan Eßer * @param c The result operand. 869*44d4804dSStefan Eßer * @return The second operand as a hardware integer. 870*44d4804dSStefan Eßer */ 871*44d4804dSStefan Eßer static BcBigDig bc_num_intop(const BcNum *a, const BcNum *b, BcNum *restrict c) 872252884aeSStefan Eßer { 873*44d4804dSStefan Eßer BcNum temp; 874*44d4804dSStefan Eßer 875*44d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(b, &temp))) bc_err(BC_ERR_MATH_NON_INTEGER); 876*44d4804dSStefan Eßer 877252884aeSStefan Eßer bc_num_copy(c, a); 878*44d4804dSStefan Eßer 879*44d4804dSStefan Eßer return bc_num_bigdig(&temp); 880252884aeSStefan Eßer } 881252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 882252884aeSStefan Eßer 883*44d4804dSStefan Eßer /** 884*44d4804dSStefan Eßer * This is the actual implementation of add *and* subtract. Since this function 885*44d4804dSStefan Eßer * doesn't need to use scale (per the bc spec), I am hijacking it to say whether 886*44d4804dSStefan Eßer * it's doing an add or a subtract. And then I convert substraction to addition 887*44d4804dSStefan Eßer * of negative second operand. This is a BcNumBinOp function. 888*44d4804dSStefan Eßer * @param a The first operand. 889*44d4804dSStefan Eßer * @param b The second operand. 890*44d4804dSStefan Eßer * @param c The return parameter. 891*44d4804dSStefan Eßer * @param sub Non-zero for a subtract, zero for an add. 892*44d4804dSStefan 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 } 904*44d4804dSStefan 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 912*44d4804dSStefan 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 915*44d4804dSStefan Eßer // Figure out if we will actually add the numbers if their signs are equal 916*44d4804dSStefan 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 923*44d4804dSStefan Eßer // Figure out which number will have its last limbs copied (for addition) or 924*44d4804dSStefan 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 952*44d4804dSStefan 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 969*44d4804dSStefan Eßer // This is true if the numbers have a different number of limbs after the 970*44d4804dSStefan 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 1002*44d4804dSStefan 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 1007*44d4804dSStefan 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 1011*44d4804dSStefan 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 1015*44d4804dSStefan Eßer // operand above, the actual add or subtract can be performed as if the rdx 1016*44d4804dSStefan Eßer // of both operands was the same. 1017*44d4804dSStefan 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) { 1022*44d4804dSStefan Eßer 1023*44d4804dSStefan 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); 1026*44d4804dSStefan Eßer 1027*44d4804dSStefan 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 { 1031*44d4804dSStefan Eßer 1032*44d4804dSStefan 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); 1035*44d4804dSStefan Eßer 1036*44d4804dSStefan 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); 1038*44d4804dSStefan Eßer 1039*44d4804dSStefan 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 1055*44d4804dSStefan Eßer /** 1056*44d4804dSStefan Eßer * The simple multiplication that karatsuba dishes out to when the length of the 1057*44d4804dSStefan Eßer * numbers gets low enough. This doesn't use scale because it treats the 1058*44d4804dSStefan Eßer * operands as though they are integers. 1059*44d4804dSStefan Eßer * @param a The first operand. 1060*44d4804dSStefan Eßer * @param b The second operand. 1061*44d4804dSStefan Eßer * @param c The return parameter. 1062*44d4804dSStefan Eßer */ 1063*44d4804dSStefan Eßer static void bc_num_m_simp(const BcNum *a, const BcNum *b, BcNum *restrict c) { 1064*44d4804dSStefan 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 1072*44d4804dSStefan 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 1076*44d4804dSStefan 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 1080*44d4804dSStefan Eßer // This is the actual multiplication loop. It uses the lattice form of long 1081*44d4804dSStefan Eßer // multiplication (see the explanation on the web page at 1082*44d4804dSStefan Eßer // https://knilt.arcc.albany.edu/What_is_Lattice_Multiplication or the 1083*44d4804dSStefan 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); 1087*44d4804dSStefan Eßer size_t j, k; 1088252884aeSStefan Eßer 1089*44d4804dSStefan Eßer // These are the start indices. 1090*44d4804dSStefan Eßer j = (size_t) BC_MAX(0, sidx); 1091*44d4804dSStefan Eßer k = BC_MIN(i, blen - 1); 1092*44d4804dSStefan Eßer 1093*44d4804dSStefan Eßer // On every iteration of this loop, a multiplication happens, then the 1094*44d4804dSStefan 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 1105*44d4804dSStefan 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 1111*44d4804dSStefan 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 1125*44d4804dSStefan Eßer /** 1126*44d4804dSStefan Eßer * Does a shifted add or subtract for Karatsuba below. This calls either 1127*44d4804dSStefan Eßer * bc_num_addArrays() or bc_num_subArrays(). 1128*44d4804dSStefan Eßer * @param n An in/out parameter; the first operand and return parameter. 1129*44d4804dSStefan Eßer * @param a The second operand. 1130*44d4804dSStefan Eßer * @param shift The amount to shift @a n by when adding/subtracting. 1131*44d4804dSStefan Eßer * @param op The function to call, either bc_num_addArrays() or 1132*44d4804dSStefan Eßer * bc_num_subArrays(). 1133*44d4804dSStefan 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 1142*44d4804dSStefan Eßer /** 1143*44d4804dSStefan Eßer * Implements the Karatsuba algorithm. 1144*44d4804dSStefan Eßer */ 1145*44d4804dSStefan 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; 1156*44d4804dSStefan 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 } 1162*44d4804dSStefan Eßer 1163*44d4804dSStefan 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 1169*44d4804dSStefan Eßer // We need to calculate the max size of the numbers that can result from the 1170*44d4804dSStefan 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 1175*44d4804dSStefan Eßer // Calculate the space needed for all of the temporary allocations. We do 1176*44d4804dSStefan 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 1181*44d4804dSStefan 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 1184*44d4804dSStefan 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); 1196*44d4804dSStefan Eßer 1197*44d4804dSStefan Eßer // Some temporaries need the ability to grow, so we allocate them 1198*44d4804dSStefan 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 1210*44d4804dSStefan 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 1215*44d4804dSStefan Eßer // Split the parameters. 1216*44d4804dSStefan Eßer bc_num_split(a, max2, &l1, &h1); 1217*44d4804dSStefan Eßer bc_num_split(b, max2, &l2, &h2); 1218*44d4804dSStefan Eßer 1219*44d4804dSStefan 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 1223*44d4804dSStefan Eßer // The if statements below are there for efficiency reasons. The best way to 1224*44d4804dSStefan Eßer // understand them is to understand the Karatsuba algorithm because now that 1225*44d4804dSStefan Eßer // the ollocations and splits are done, the algorithm is pretty 1226*44d4804dSStefan Eßer // straightforward. 1227*44d4804dSStefan 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 1275*44d4804dSStefan Eßer /** 1276*44d4804dSStefan Eßer * Does checks for Karatsuba. It also changes things to ensure that the 1277*44d4804dSStefan Eßer * Karatsuba and simple multiplication can treat the numbers as integers. This 1278*44d4804dSStefan Eßer * is a BcNumBinOp function. 1279*44d4804dSStefan Eßer * @param a The first operand. 1280*44d4804dSStefan Eßer * @param b The second operand. 1281*44d4804dSStefan Eßer * @param c The return parameter. 1282*44d4804dSStefan Eßer * @param scale The current scale. 1283*44d4804dSStefan 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); 1293*44d4804dSStefan Eßer 1294252884aeSStefan Eßer ascale = a->scale; 1295252884aeSStefan Eßer bscale = b->scale; 1296*44d4804dSStefan Eßer 1297*44d4804dSStefan 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 1303*44d4804dSStefan Eßer // If this condition is true, we can use bc_num_mulArray(), which would be 1304*44d4804dSStefan 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 1310*44d4804dSStefan 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 1322*44d4804dSStefan 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 1334*44d4804dSStefan Eßer // We need copies because of all of the mutation needed to make Karatsuba 1335*44d4804dSStefan 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 1355*44d4804dSStefan 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 1369*44d4804dSStefan 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 1382*44d4804dSStefan Eßer // The return parameter needs to have its scale set. This is the start. It 1383*44d4804dSStefan Eßer // also needs to be shifted by the same amount as a and b have limbs after 1384*44d4804dSStefan 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); 1389*44d4804dSStefan Eßer 1390*44d4804dSStefan 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 1405*44d4804dSStefan Eßer /** 1406*44d4804dSStefan Eßer * Returns true if the BcDig array has non-zero limbs, false otherwise. 1407*44d4804dSStefan Eßer * @param a The array to test. 1408*44d4804dSStefan Eßer * @param len The length of the array. 1409*44d4804dSStefan Eßer * @return True if @a has any non-zero limbs, false otherwise. 1410*44d4804dSStefan 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 1418*44d4804dSStefan Eßer /** 1419*44d4804dSStefan Eßer * Compares a BcDig array against a BcNum. This is especially suited for 1420*44d4804dSStefan Eßer * division. Returns >0 if @a a is greater than @a b, <0 if it is less, and =0 1421*44d4804dSStefan Eßer * if they are equal. 1422*44d4804dSStefan Eßer * @param a The array. 1423*44d4804dSStefan Eßer * @param b The number. 1424*44d4804dSStefan Eßer * @param len The length to assume the arrays are. This is always less than the 1425*44d4804dSStefan Eßer * actual length because of how this is implemented. 1426*44d4804dSStefan 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 1441*44d4804dSStefan Eßer /** 1442*44d4804dSStefan Eßer * Extends the two operands of a division by BC_BASE_DIGS minus the number of 1443*44d4804dSStefan Eßer * digits in the divisor estimate. In other words, it is shifting the numbers in 1444*44d4804dSStefan Eßer * order to force the divisor estimate to fill the limb. 1445*44d4804dSStefan Eßer * @param a The first operand. 1446*44d4804dSStefan Eßer * @param b The second operand. 1447*44d4804dSStefan Eßer * @param divisor The divisor estimate. 1448*44d4804dSStefan 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 1462*44d4804dSStefan Eßer /** 1463*44d4804dSStefan Eßer * Actually does division. This is a rewrite of my original code by Stefan Esser 1464*44d4804dSStefan Eßer * from FreeBSD. 1465*44d4804dSStefan Eßer * @param a The first operand. 1466*44d4804dSStefan Eßer * @param b The second operand. 1467*44d4804dSStefan Eßer * @param c The return parameter. 1468*44d4804dSStefan Eßer * @param scale The current scale. 1469*44d4804dSStefan 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); 1479*44d4804dSStefan Eßer 1480252884aeSStefan Eßer len = b->len; 1481252884aeSStefan Eßer end = a->len - len; 1482*44d4804dSStefan Eßer 1483252884aeSStefan Eßer assert(len >= 1); 1484252884aeSStefan Eßer 1485*44d4804dSStefan Eßer // This is a final time to make sure c is big enough and that its array is 1486*44d4804dSStefan 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 1490*44d4804dSStefan 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 1495*44d4804dSStefan Eßer // This is pulling the most significant limb of b in order to establish a 1496*44d4804dSStefan Eßer // good "estimate" for the actual divisor. 1497252884aeSStefan Eßer divisor = (BcBigDig) b->num[len - 1]; 1498252884aeSStefan Eßer 1499*44d4804dSStefan Eßer // The entire bit of code in this if statement is to tighten the estimate of 1500*44d4804dSStefan 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 1503*44d4804dSStefan Eßer // This takes a little bit of understanding. The "10*BC_BASE_DIGS/6+1" 1504*44d4804dSStefan Eßer // results in either 16 for 64-bit 9-digit limbs or 7 for 32-bit 4-digit 1505*44d4804dSStefan Eßer // limbs. Then it shifts a 1 by that many, which in both cases, puts the 1506*44d4804dSStefan Eßer // result above *half* of the max value a limb can store. Basically, 1507*44d4804dSStefan Eßer // this quickly calculates if the divisor is greater than half the max 1508*44d4804dSStefan Eßer // of a limb. 1509252884aeSStefan Eßer nonzero = (divisor > 1 << ((10 * BC_BASE_DIGS) / 6 + 1)); 1510252884aeSStefan Eßer 1511*44d4804dSStefan Eßer // If the divisor is *not* greater than half the limb... 1512252884aeSStefan Eßer if (!nonzero) { 1513252884aeSStefan Eßer 1514*44d4804dSStefan Eßer // Extend the parameters by the number of missing digits in the 1515*44d4804dSStefan Eßer // divisor. 1516252884aeSStefan Eßer bc_num_divExtend(a, b, divisor); 1517252884aeSStefan Eßer 1518*44d4804dSStefan Eßer // Check bc_num_d(). In there, we grow a again and again. We do it 1519*44d4804dSStefan 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 1523*44d4804dSStefan 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 1526*44d4804dSStefan Eßer // Grab the new divisor estimate, new because the shift has made it 1527*44d4804dSStefan 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 1536*44d4804dSStefan Eßer // If b has other nonzero limbs, we want the divisor to be one higher, so 1537*44d4804dSStefan Eßer // that it is an upper bound. 1538252884aeSStefan Eßer divisor += nonzero; 1539252884aeSStefan Eßer 1540*44d4804dSStefan 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 1555*44d4804dSStefan Eßer // This is the actual division loop. 1556*44d4804dSStefan 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 1568*44d4804dSStefan Eßer // This is true if n is greater than b, which means that division can 1569*44d4804dSStefan Eßer // proceed, so this inner loop is the part that implements one instance 1570*44d4804dSStefan Eßer // of the division. 1571252884aeSStefan Eßer while (cmp >= 0) { 1572252884aeSStefan Eßer 1573*44d4804dSStefan Eßer BcBigDig n1, dividend, quotient; 1574252884aeSStefan Eßer 1575*44d4804dSStefan Eßer // These should be named obviously enough. Just imagine that it's a 1576*44d4804dSStefan 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]; 1579*44d4804dSStefan Eßer quotient = (dividend / divisor); 1580252884aeSStefan Eßer 1581*44d4804dSStefan Eßer // If this is true, then we can just subtract. Remember: setting 1582*44d4804dSStefan Eßer // quotient to 1 is not bad because we already know that n is 1583*44d4804dSStefan Eßer // greater than b. 1584*44d4804dSStefan Eßer if (quotient <= 1) { 1585*44d4804dSStefan Eßer quotient = 1; 1586252884aeSStefan Eßer bc_num_subArrays(n, b->num, len); 1587252884aeSStefan Eßer } 1588252884aeSStefan Eßer else { 1589252884aeSStefan Eßer 1590*44d4804dSStefan Eßer assert(quotient <= BC_BASE_POW); 1591252884aeSStefan Eßer 1592*44d4804dSStefan Eßer // We need to multiply and subtract for a quotient above 1. 1593*44d4804dSStefan 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 1597*44d4804dSStefan Eßer // The result is the *real* quotient, by the way, but it might take 1598*44d4804dSStefan Eßer // multiple trips around this loop to get it. 1599*44d4804dSStefan Eßer result += quotient; 1600252884aeSStefan Eßer assert(result <= BC_BASE_POW); 1601252884aeSStefan Eßer 1602*44d4804dSStefan Eßer // And here's why it might take multiple trips: n might *still* be 1603*44d4804dSStefan Eßer // greater than b. So we have to loop again. That's what this is 1604*44d4804dSStefan 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 1611*44d4804dSStefan 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 1621*44d4804dSStefan Eßer /** 1622*44d4804dSStefan Eßer * Implements division. This is a BcNumBinOp function. 1623*44d4804dSStefan Eßer * @param a The first operand. 1624*44d4804dSStefan Eßer * @param b The second operand. 1625*44d4804dSStefan Eßer * @param c The return parameter. 1626*44d4804dSStefan Eßer * @param scale The current scale. 1627*44d4804dSStefan 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 1633*44d4804dSStefan Eßer if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); 1634*44d4804dSStefan 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 } 1639*44d4804dSStefan 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 } 1645*44d4804dSStefan Eßer 1646*44d4804dSStefan 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 1658*44d4804dSStefan Eßer // Initialize copies of the parameters. We want the length of the first 1659*44d4804dSStefan Eßer // operand copy to be as big as the result because of the way the division 1660*44d4804dSStefan 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 1671*44d4804dSStefan Eßer // Like the above comment, we want the copy of the first parameter to be 1672*44d4804dSStefan 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 1681*44d4804dSStefan 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 1687*44d4804dSStefan 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 1694*44d4804dSStefan 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 1700*44d4804dSStefan Eßer // Still setting things up. Why all of these things are needed is not 1701*44d4804dSStefan Eßer // something that can be easily explained, but it has to do with making the 1702*44d4804dSStefan Eßer // actual algorithm easier to understand because it can assume a lot of 1703*44d4804dSStefan Eßer // things. Thus, you should view all of this setup code as establishing 1704*44d4804dSStefan Eßer // assumptions for bc_num_d_long(), where the actual division happens. 1705*44d4804dSStefan Eßer if (cpardx == cpa.len) cpa.len = bc_num_nonZeroLen(&cpa); 1706*44d4804dSStefan 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 1721*44d4804dSStefan Eßer /** 1722*44d4804dSStefan Eßer * Implements divmod. This is the actual modulus function; since modulus 1723*44d4804dSStefan Eßer * requires a division anyway, this returns the quotient and modulus. Either can 1724*44d4804dSStefan Eßer * be thrown out as desired. 1725*44d4804dSStefan Eßer * @param a The first operand. 1726*44d4804dSStefan Eßer * @param b The second operand. 1727*44d4804dSStefan Eßer * @param c The return parameter for the quotient. 1728*44d4804dSStefan Eßer * @param d The return parameter for the modulus. 1729*44d4804dSStefan Eßer * @param scale The current scale. 1730*44d4804dSStefan Eßer * @param ts The scale that the operation should be done to. Yes, it's not 1731*44d4804dSStefan Eßer * necessarily the same as scale, per the bc spec. 1732*44d4804dSStefan 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 1739*44d4804dSStefan Eßer if (BC_NUM_ZERO(b)) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); 1740*44d4804dSStefan 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 1755*44d4804dSStefan Eßer // Division. 1756252884aeSStefan Eßer bc_num_d(a, b, c, scale); 1757252884aeSStefan Eßer 1758*44d4804dSStefan 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 1764*44d4804dSStefan 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 1768*44d4804dSStefan 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 1781*44d4804dSStefan Eßer /** 1782*44d4804dSStefan Eßer * Implements modulus/remainder. (Yes, I know they are different, but not in the 1783*44d4804dSStefan Eßer * context of bc.) This is a BcNumBinOp function. 1784*44d4804dSStefan Eßer * @param a The first operand. 1785*44d4804dSStefan Eßer * @param b The second operand. 1786*44d4804dSStefan Eßer * @param c The return parameter. 1787*44d4804dSStefan Eßer * @param scale The current scale. 1788*44d4804dSStefan 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 1799*44d4804dSStefan 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 1814*44d4804dSStefan Eßer /** 1815*44d4804dSStefan Eßer * Implements power (exponentiation). This is a BcNumBinOp function. 1816*44d4804dSStefan Eßer * @param a The first operand. 1817*44d4804dSStefan Eßer * @param b The second operand. 1818*44d4804dSStefan Eßer * @param c The return parameter. 1819*44d4804dSStefan Eßer * @param scale The current scale. 1820*44d4804dSStefan Eßer */ 1821252884aeSStefan Eßer static void bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1822252884aeSStefan Eßer 1823*44d4804dSStefan Eßer BcNum copy, btemp; 1824*44d4804dSStefan Eßer BcBigDig exp; 1825*44d4804dSStefan Eßer size_t powrdx, resrdx; 1826*44d4804dSStefan Eßer bool neg; 1827252884aeSStefan Eßer 1828*44d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(b, &btemp))) bc_err(BC_ERR_MATH_NON_INTEGER); 1829252884aeSStefan Eßer 1830*44d4804dSStefan Eßer if (BC_NUM_ZERO(&btemp)) { 1831252884aeSStefan Eßer bc_num_one(c); 1832252884aeSStefan Eßer return; 1833252884aeSStefan Eßer } 1834*44d4804dSStefan Eßer 1835252884aeSStefan Eßer if (BC_NUM_ZERO(a)) { 1836*44d4804dSStefan 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 } 1840*44d4804dSStefan Eßer 1841*44d4804dSStefan Eßer if (BC_NUM_ONE(&btemp)) { 1842*44d4804dSStefan 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 1847*44d4804dSStefan Eßer neg = BC_NUM_NEG_NP(btemp); 1848*44d4804dSStefan Eßer BC_NUM_NEG_CLR_NP(btemp); 1849252884aeSStefan Eßer 1850*44d4804dSStefan Eßer exp = bc_num_bigdig(&btemp); 1851*44d4804dSStefan Eßer 1852*44d4804dSStefan 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 1860*44d4804dSStefan Eßer // If this is true, then we do not have to do a division, and we need to 1861*44d4804dSStefan Eßer // set scale accordingly. 1862252884aeSStefan Eßer if (!neg) { 1863*44d4804dSStefan Eßer size_t max = BC_MAX(scale, a->scale), scalepow; 1864*44d4804dSStefan Eßer scalepow = bc_num_mulOverflow(a->scale, exp); 1865252884aeSStefan Eßer scale = BC_MIN(scalepow, max); 1866252884aeSStefan Eßer } 1867252884aeSStefan Eßer 1868*44d4804dSStefan Eßer // This is only implementing the first exponentiation by squaring, until it 1869*44d4804dSStefan Eßer // reaches the first time where the square is actually used. 1870*44d4804dSStefan 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 1876*44d4804dSStefan Eßer // Make c a copy of copy for the purpose of saving the squares that should 1877*44d4804dSStefan Eßer // be saved. 1878252884aeSStefan Eßer bc_num_copy(c, ©); 1879252884aeSStefan Eßer resrdx = powrdx; 1880252884aeSStefan Eßer 1881*44d4804dSStefan Eßer // Now finish the exponentiation by squaring, this time saving the squares 1882*44d4804dSStefan Eßer // as necessary. 1883*44d4804dSStefan 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 1889*44d4804dSStefan Eßer // If this is true, we want to save that particular square. This does 1890*44d4804dSStefan Eßer // that by multiplying c with copy. 1891*44d4804dSStefan 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 1899*44d4804dSStefan Eßer // Invert if necessary. 1900252884aeSStefan Eßer if (neg) bc_num_inv(c, c, scale); 1901252884aeSStefan Eßer 1902*44d4804dSStefan Eßer // Truncate if necessary. 1903252884aeSStefan Eßer if (c->scale > scale) bc_num_truncate(c, c->scale - scale); 1904252884aeSStefan Eßer 1905*44d4804dSStefan 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 1914*44d4804dSStefan Eßer /** 1915*44d4804dSStefan Eßer * Implements the places operator. This is a BcNumBinOp function. 1916*44d4804dSStefan Eßer * @param a The first operand. 1917*44d4804dSStefan Eßer * @param b The second operand. 1918*44d4804dSStefan Eßer * @param c The return parameter. 1919*44d4804dSStefan Eßer * @param scale The current scale. 1920*44d4804dSStefan Eßer */ 1921252884aeSStefan Eßer static void bc_num_place(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1922252884aeSStefan Eßer 1923*44d4804dSStefan Eßer BcBigDig val; 1924252884aeSStefan Eßer 1925252884aeSStefan Eßer BC_UNUSED(scale); 1926252884aeSStefan Eßer 1927*44d4804dSStefan Eßer val = bc_num_intop(a, b, c); 1928252884aeSStefan Eßer 1929*44d4804dSStefan 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 1934*44d4804dSStefan Eßer /** 1935*44d4804dSStefan Eßer * Implements the left shift operator. This is a BcNumBinOp function. 1936*44d4804dSStefan Eßer */ 1937252884aeSStefan Eßer static void bc_num_left(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1938252884aeSStefan Eßer 1939*44d4804dSStefan Eßer BcBigDig val; 1940252884aeSStefan Eßer 1941252884aeSStefan Eßer BC_UNUSED(scale); 1942252884aeSStefan Eßer 1943*44d4804dSStefan 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 1948*44d4804dSStefan Eßer /** 1949*44d4804dSStefan Eßer * Implements the right shift operator. This is a BcNumBinOp function. 1950*44d4804dSStefan Eßer */ 1951252884aeSStefan Eßer static void bc_num_right(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { 1952252884aeSStefan Eßer 1953*44d4804dSStefan Eßer BcBigDig val; 1954252884aeSStefan Eßer 1955252884aeSStefan Eßer BC_UNUSED(scale); 1956252884aeSStefan Eßer 1957*44d4804dSStefan 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 1965*44d4804dSStefan Eßer /** 1966*44d4804dSStefan Eßer * Prepares for, and calls, a binary operator function. This is probably the 1967*44d4804dSStefan Eßer * most important function in the entire file because it establishes assumptions 1968*44d4804dSStefan Eßer * that make the rest of the code so easy. Those assumptions include: 1969*44d4804dSStefan Eßer * 1970*44d4804dSStefan Eßer * - a is not the same pointer as c. 1971*44d4804dSStefan Eßer * - b is not the same pointer as c. 1972*44d4804dSStefan Eßer * - there is enough room in c for the result. 1973*44d4804dSStefan Eßer * 1974*44d4804dSStefan Eßer * Without these, this whole function would basically have to be duplicated for 1975*44d4804dSStefan Eßer * *all* binary operators. 1976*44d4804dSStefan Eßer * 1977*44d4804dSStefan Eßer * @param a The first operand. 1978*44d4804dSStefan Eßer * @param b The second operand. 1979*44d4804dSStefan Eßer * @param c The return parameter. 1980*44d4804dSStefan Eßer * @param scale The current scale. 1981*44d4804dSStefan Eßer * @param req The number of limbs needed to fit the result. 1982*44d4804dSStefan 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 1996*44d4804dSStefan 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 2008*44d4804dSStefan 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 2022*44d4804dSStefan Eßer // Actually reallocate. If we don't reallocate, we want to expand at the 2023*44d4804dSStefan Eßer // very least. 2024252884aeSStefan Eßer if (init) { 2025252884aeSStefan Eßer 2026252884aeSStefan Eßer bc_num_init(c, req); 2027252884aeSStefan Eßer 2028*44d4804dSStefan Eßer // Must prepare for cleanup. We want this here so that locals that got 2029*44d4804dSStefan 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 2038*44d4804dSStefan Eßer // It is okay for a and b to be the same. If a binary operator function does 2039*44d4804dSStefan Eßer // need them to be different, the binary operator function is responsible 2040*44d4804dSStefan Eßer // for that. 2041*44d4804dSStefan Eßer 2042*44d4804dSStefan 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: 2051*44d4804dSStefan 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 2060*44d4804dSStefan Eßer 2061*44d4804dSStefan Eßer /** 2062*44d4804dSStefan Eßer * Tests a number string for validity. This function has a history; I originally 2063*44d4804dSStefan Eßer * wrote it because I did not trust my parser. Over time, however, I came to 2064*44d4804dSStefan Eßer * trust it, so I was able to relegate this function to debug builds only, and I 2065*44d4804dSStefan Eßer * used it in assert()'s. But then I created the library, and well, I can't 2066*44d4804dSStefan Eßer * trust users, so I reused this for yelling at users. 2067*44d4804dSStefan Eßer * @param val The string to check to see if it's a valid number string. 2068*44d4804dSStefan Eßer * @return True if the string is a valid number string, false otherwise. 2069*44d4804dSStefan 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 2075*44d4804dSStefan Eßer // Notice that I don't check if there is a negative sign. That is not part 2076*44d4804dSStefan Eßer // of a valid number, except in the library. The library-specific code takes 2077*44d4804dSStefan Eßer // care of that part. 2078*44d4804dSStefan Eßer 2079*44d4804dSStefan Eßer // Nothing in the string is okay. 2080252884aeSStefan Eßer if (!len) return true; 2081252884aeSStefan Eßer 2082*44d4804dSStefan 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 2087*44d4804dSStefan Eßer // If we have found a radix point... 2088252884aeSStefan Eßer if (c == '.') { 2089252884aeSStefan Eßer 2090*44d4804dSStefan 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 2097*44d4804dSStefan 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 2105*44d4804dSStefan Eßer /** 2106*44d4804dSStefan Eßer * Parses one character and returns the digit that corresponds to that 2107*44d4804dSStefan Eßer * character according to the base. 2108*44d4804dSStefan Eßer * @param c The character to parse. 2109*44d4804dSStefan Eßer * @param base The base. 2110*44d4804dSStefan Eßer * @return The character as a digit. 2111*44d4804dSStefan Eßer */ 2112*44d4804dSStefan Eßer static BcBigDig bc_num_parseChar(char c, size_t base) { 2113252884aeSStefan Eßer 2114*44d4804dSStefan Eßer assert(isupper(c) || isdigit(c)); 2115*44d4804dSStefan Eßer 2116*44d4804dSStefan Eßer // If a letter... 2117252884aeSStefan Eßer if (isupper(c)) { 2118*44d4804dSStefan Eßer 2119*44d4804dSStefan Eßer // This returns the digit that directly corresponds with the letter. 2120252884aeSStefan Eßer c = BC_NUM_NUM_LETTER(c); 2121*44d4804dSStefan Eßer 2122*44d4804dSStefan Eßer // If the digit is greater than the base, we clamp. 2123*44d4804dSStefan Eßer c = ((size_t) c) >= base ? (char) base - 1 : c; 2124252884aeSStefan Eßer } 2125*44d4804dSStefan 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 2131*44d4804dSStefan Eßer /** 2132*44d4804dSStefan Eßer * Parses a string as a decimal number. This is separate because it's going to 2133*44d4804dSStefan Eßer * be the most used, and it can be heavily optimized for decimal only. 2134*44d4804dSStefan Eßer * @param n The number to parse into and return. Must be preallocated. 2135*44d4804dSStefan Eßer * @param val The string to parse. 2136*44d4804dSStefan 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 2143*44d4804dSStefan 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 2149*44d4804dSStefan Eßer // All 0's. We can just return, since this procedure expects a virgin 2150*44d4804dSStefan Eßer // (already 0) BcNum. 2151252884aeSStefan Eßer if (!val[0]) return; 2152252884aeSStefan Eßer 2153*44d4804dSStefan Eßer // The length of the string is the length of the number, except it might be 2154*44d4804dSStefan Eßer // one bigger because of a decimal point. 2155252884aeSStefan Eßer len = strlen(val); 2156252884aeSStefan Eßer 2157*44d4804dSStefan Eßer // Find the location of the decimal point. 2158252884aeSStefan Eßer ptr = strchr(val, '.'); 2159252884aeSStefan Eßer rdx = (ptr != NULL); 2160252884aeSStefan Eßer 2161*44d4804dSStefan Eßer // We eat leading zeroes again. These leading zeroes are different because 2162*44d4804dSStefan Eßer // they will come after the decimal point if they exist, and since that's 2163*44d4804dSStefan 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 2166*44d4804dSStefan Eßer // Set the scale of the number based on the location of the decimal point. 2167*44d4804dSStefan Eßer // The casts to uintptr_t is to ensure that bc does not hit undefined 2168*44d4804dSStefan 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 2172*44d4804dSStefan Eßer // Set rdx. 217350696a6eSStefan Eßer BC_NUM_RDX_SET(n, BC_NUM_RDX(n->scale)); 2174*44d4804dSStefan Eßer 2175*44d4804dSStefan Eßer // Calculate length. First, the length of the integer, then the number of 2176*44d4804dSStefan 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 2183*44d4804dSStefan 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 2194*44d4804dSStefan 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 2199*44d4804dSStefan Eßer // The exponent and power. 2200252884aeSStefan Eßer exp = (BcBigDig) i; 2201252884aeSStefan Eßer pow = bc_num_pow10[exp]; 2202252884aeSStefan Eßer 2203*44d4804dSStefan Eßer // Parse loop. We parse backwards because numbers are stored little 2204*44d4804dSStefan 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 2209*44d4804dSStefan Eßer // Skip the decimal point. 2210252884aeSStefan Eßer if (c == '.') exp -= 1; 2211252884aeSStefan Eßer else { 2212252884aeSStefan Eßer 2213*44d4804dSStefan Eßer // The index of the limb. 2214252884aeSStefan Eßer size_t idx = exp / BC_BASE_DIGS; 2215252884aeSStefan Eßer 2216*44d4804dSStefan Eßer // Clamp for the base. 2217252884aeSStefan Eßer if (isupper(c)) c = '9'; 2218*44d4804dSStefan Eßer 2219*44d4804dSStefan Eßer // Add the digit to the limb. 2220252884aeSStefan Eßer n->num[idx] += (((BcBigDig) c) - '0') * pow; 2221252884aeSStefan Eßer 2222*44d4804dSStefan 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 2230*44d4804dSStefan Eßer /** 2231*44d4804dSStefan Eßer * Parse a number in any base (besides decimal). 2232*44d4804dSStefan Eßer * @param n The number to parse into and return. Must be preallocated. 2233*44d4804dSStefan Eßer * @param val The string to parse. 2234*44d4804dSStefan Eßer * @param base The base to parse as. 2235*44d4804dSStefan 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 2245*44d4804dSStefan 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 2258*44d4804dSStefan Eßer // We split parsing into parsing the integer and parsing the fractional 2259*44d4804dSStefan Eßer // part. 2260*44d4804dSStefan Eßer 2261*44d4804dSStefan Eßer // Parse the integer part. This is the easy part because we just multiply 2262*44d4804dSStefan 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 2265*44d4804dSStefan Eßer // Convert the character to a digit. 2266252884aeSStefan Eßer v = bc_num_parseChar(c, base); 2267252884aeSStefan Eßer 2268*44d4804dSStefan Eßer // Multiply the number. 2269252884aeSStefan Eßer bc_num_mulArray(n, base, &mult1); 2270*44d4804dSStefan Eßer 2271*44d4804dSStefan 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 2276*44d4804dSStefan Eßer // If this condition is true, then we are done. We still need to do cleanup 2277*44d4804dSStefan Eßer // though. 227810328f8bSStefan Eßer if (i == len && !val[i]) goto int_err; 2279252884aeSStefan Eßer 2280*44d4804dSStefan 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 2285*44d4804dSStefan 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 2297*44d4804dSStefan Eßer // Pointers for easy switching. 2298252884aeSStefan Eßer m1 = &mult1; 2299252884aeSStefan Eßer m2 = &mult2; 2300252884aeSStefan Eßer 2301*44d4804dSStefan 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 2306*44d4804dSStefan Eßer // Convert the character to a digit. 2307252884aeSStefan Eßer v = bc_num_parseChar(c, base); 2308252884aeSStefan Eßer 2309*44d4804dSStefan Eßer // We keep growing result2 according to the base because the more digits 2310*44d4804dSStefan Eßer // after the radix, the more significant the digits close to the radix 2311*44d4804dSStefan Eßer // should be. 2312252884aeSStefan Eßer bc_num_mulArray(&result1, base, &result2); 2313252884aeSStefan Eßer 2314*44d4804dSStefan Eßer // Convert the digit to a number. 2315252884aeSStefan Eßer bc_num_bigdig2num(&temp, v); 2316*44d4804dSStefan Eßer 2317*44d4804dSStefan Eßer // Add the digit into the fraction part. 2318252884aeSStefan Eßer bc_num_add(&result2, &temp, &result1, 0); 2319*44d4804dSStefan Eßer 2320*44d4804dSStefan 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 2327*44d4804dSStefan 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 2334*44d4804dSStefan Eßer // multiplied by base, and base cannot be 0, so mult cannot be 0. And this 2335*44d4804dSStefan Eßer // is the reason we keep growing m1 and m2; this division is what converts 2336*44d4804dSStefan Eßer // the parsed fractional part from an integer to a fractional part. 2337252884aeSStefan Eßer bc_num_div(&result1, m1, &result2, digs * 2); 2338*44d4804dSStefan Eßer 2339*44d4804dSStefan Eßer // Pretruncate. 2340252884aeSStefan Eßer bc_num_truncate(&result2, digs); 2341*44d4804dSStefan Eßer 2342*44d4804dSStefan 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 2345*44d4804dSStefan 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 2363*44d4804dSStefan Eßer /** 2364*44d4804dSStefan Eßer * Prints a backslash+newline combo if the number of characters needs it. This 2365*44d4804dSStefan Eßer * is really a convenience function. 2366*44d4804dSStefan Eßer */ 236750696a6eSStefan Eßer static inline void bc_num_printNewline(void) { 236850696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY 2369252884aeSStefan Eßer if (vm.nchars >= vm.line_len - 1) { 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 2376*44d4804dSStefan Eßer /** 2377*44d4804dSStefan Eßer * Prints a character after a backslash+newline, if needed. 2378*44d4804dSStefan Eßer * @param c The character to print. 2379*44d4804dSStefan Eßer * @param bslash Whether to print a backslash+newline. 2380*44d4804dSStefan Eßer */ 2381*44d4804dSStefan Eßer static void bc_num_putchar(int c, bool bslash) { 2382*44d4804dSStefan 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 2386*44d4804dSStefan Eßer #if !BC_ENABLE_LIBRARY 2387*44d4804dSStefan Eßer 2388*44d4804dSStefan Eßer /** 2389*44d4804dSStefan Eßer * Prints a character for a number's digit. This is for printing for dc's P 2390*44d4804dSStefan Eßer * command. This function does not need to worry about radix points. This is a 2391*44d4804dSStefan Eßer * BcNumDigitOp. 2392*44d4804dSStefan Eßer * @param n The "digit" to print. 2393*44d4804dSStefan Eßer * @param len The "length" of the digit, or number of characters that will 2394*44d4804dSStefan Eßer * need to be printed for the digit. 2395*44d4804dSStefan Eßer * @param rdx True if a decimal (radix) point should be printed. 2396*44d4804dSStefan Eßer * @param bslash True if a backslash+newline should be printed if the character 2397*44d4804dSStefan Eßer * limit for the line is reached, false otherwise. 2398*44d4804dSStefan Eßer */ 2399*44d4804dSStefan 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); 2402*44d4804dSStefan 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 2407*44d4804dSStefan Eßer #endif // !BC_ENABLE_LIBRARY 2408*44d4804dSStefan Eßer 2409*44d4804dSStefan Eßer /** 2410*44d4804dSStefan Eßer * Prints a series of characters for large bases. This is for printing in bases 2411*44d4804dSStefan Eßer * above hexadecimal. This is a BcNumDigitOp. 2412*44d4804dSStefan Eßer * @param n The "digit" to print. 2413*44d4804dSStefan Eßer * @param len The "length" of the digit, or number of characters that will 2414*44d4804dSStefan Eßer * need to be printed for the digit. 2415*44d4804dSStefan Eßer * @param rdx True if a decimal (radix) point should be printed. 2416*44d4804dSStefan Eßer * @param bslash True if a backslash+newline should be printed if the character 2417*44d4804dSStefan Eßer * limit for the line is reached, false otherwise. 2418*44d4804dSStefan Eßer */ 2419*44d4804dSStefan 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 2423*44d4804dSStefan Eßer // If needed, print the radix; otherwise, print a space to separate digits. 2424*44d4804dSStefan Eßer bc_num_putchar(rdx ? '.' : ' ', true); 2425252884aeSStefan Eßer 2426*44d4804dSStefan 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 2429*44d4804dSStefan Eßer // Print each character individually. 2430252884aeSStefan Eßer for (exp = 0; exp < len; pow /= BC_BASE, ++exp) { 2431*44d4804dSStefan Eßer 2432*44d4804dSStefan Eßer // The individual subdigit. 2433252884aeSStefan Eßer size_t dig = n / pow; 2434*44d4804dSStefan Eßer 2435*44d4804dSStefan Eßer // Take the subdigit away. 2436252884aeSStefan Eßer n -= dig * pow; 2437*44d4804dSStefan Eßer 2438*44d4804dSStefan Eßer // Print the subdigit. 2439*44d4804dSStefan Eßer bc_num_putchar(((uchar) dig) + '0', bslash || exp != len - 1); 2440252884aeSStefan Eßer } 2441252884aeSStefan Eßer } 2442252884aeSStefan Eßer 2443*44d4804dSStefan Eßer /** 2444*44d4804dSStefan Eßer * Prints a character for a number's digit. This is for printing in bases for 2445*44d4804dSStefan Eßer * hexadecimal and below because they always print only one character at a time. 2446*44d4804dSStefan Eßer * This is a BcNumDigitOp. 2447*44d4804dSStefan Eßer * @param n The "digit" to print. 2448*44d4804dSStefan Eßer * @param len The "length" of the digit, or number of characters that will 2449*44d4804dSStefan Eßer * need to be printed for the digit. 2450*44d4804dSStefan Eßer * @param rdx True if a decimal (radix) point should be printed. 2451*44d4804dSStefan Eßer * @param bslash True if a backslash+newline should be printed if the character 2452*44d4804dSStefan Eßer * limit for the line is reached, false otherwise. 2453*44d4804dSStefan Eßer */ 2454*44d4804dSStefan 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); 2457*44d4804dSStefan Eßer BC_UNUSED(bslash); 2458252884aeSStefan Eßer 2459252884aeSStefan Eßer assert(len == 1); 2460252884aeSStefan Eßer 2461*44d4804dSStefan Eßer if (rdx) bc_num_putchar('.', true); 2462252884aeSStefan Eßer 2463*44d4804dSStefan Eßer bc_num_putchar(bc_num_hex_digits[n], bslash); 2464252884aeSStefan Eßer } 2465252884aeSStefan Eßer 2466*44d4804dSStefan Eßer /** 2467*44d4804dSStefan Eßer * Prints a decimal number. This is specially written for optimization since 2468*44d4804dSStefan Eßer * this will be used the most and because bc's numbers are already in decimal. 2469*44d4804dSStefan Eßer * @param n The number to print. 2470*44d4804dSStefan Eßer * @param newline Whether to print backslash+newlines on long enough lines. 2471*44d4804dSStefan Eßer */ 2472*44d4804dSStefan 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 2478*44d4804dSStefan Eßer // Print the sign. 2479*44d4804dSStefan Eßer if (BC_NUM_NEG(n)) bc_num_putchar('-', true); 2480252884aeSStefan Eßer 2481*44d4804dSStefan Eßer // Print loop. 2482252884aeSStefan Eßer for (i = n->len - 1; i < n->len; --i) { 2483252884aeSStefan Eßer 2484252884aeSStefan Eßer BcDig n9 = n->num[i]; 2485252884aeSStefan Eßer size_t temp; 2486252884aeSStefan Eßer bool irdx = (i == rdx - 1); 2487252884aeSStefan Eßer 2488*44d4804dSStefan Eßer // Calculate the number of digits in the limb. 2489252884aeSStefan Eßer zero = (zero & !irdx); 2490252884aeSStefan Eßer temp = n->scale % BC_BASE_DIGS; 2491252884aeSStefan Eßer temp = i || !temp ? 0 : BC_BASE_DIGS - temp; 2492252884aeSStefan Eßer 2493252884aeSStefan Eßer memset(buffer, 0, BC_BASE_DIGS * sizeof(size_t)); 2494252884aeSStefan Eßer 2495*44d4804dSStefan Eßer // Fill the buffer with individual digits. 2496252884aeSStefan Eßer for (j = 0; n9 && j < BC_BASE_DIGS; ++j) { 2497d213476dSStefan Eßer buffer[j] = ((size_t) n9) % BC_BASE; 2498252884aeSStefan Eßer n9 /= BC_BASE; 2499252884aeSStefan Eßer } 2500252884aeSStefan Eßer 2501*44d4804dSStefan Eßer // Print the digits in the buffer. 2502252884aeSStefan Eßer for (j = BC_BASE_DIGS - 1; j < BC_BASE_DIGS && j >= temp; --j) { 2503*44d4804dSStefan Eßer 2504*44d4804dSStefan Eßer // Figure out whether to print the decimal point. 2505252884aeSStefan Eßer bool print_rdx = (irdx & (j == BC_BASE_DIGS - 1)); 2506*44d4804dSStefan Eßer 2507*44d4804dSStefan Eßer // The zero variable helps us skip leading zero digits in the limb. 2508252884aeSStefan Eßer zero = (zero && buffer[j] == 0); 2509*44d4804dSStefan Eßer 2510*44d4804dSStefan Eßer if (!zero) { 2511*44d4804dSStefan Eßer 2512*44d4804dSStefan Eßer // While the first three arguments should be self-explanatory, 2513*44d4804dSStefan Eßer // the last needs explaining. I don't want to print a newline 2514*44d4804dSStefan Eßer // when the last digit to be printed could take the place of the 2515*44d4804dSStefan Eßer // backslash rather than being pushed, as a single character, to 2516*44d4804dSStefan Eßer // the next line. That's what that last argument does for bc. 2517*44d4804dSStefan Eßer bc_num_printHex(buffer[j], 1, print_rdx, 2518*44d4804dSStefan Eßer !newline || (j > temp || i != 0)); 2519*44d4804dSStefan Eßer } 2520252884aeSStefan Eßer } 2521252884aeSStefan Eßer } 2522252884aeSStefan Eßer } 2523252884aeSStefan Eßer 2524252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 2525252884aeSStefan Eßer 2526*44d4804dSStefan Eßer /** 2527*44d4804dSStefan Eßer * Prints a number in scientific or engineering format. When doing this, we are 2528*44d4804dSStefan Eßer * always printing in decimal. 2529*44d4804dSStefan Eßer * @param n The number to print. 2530*44d4804dSStefan Eßer * @param eng True if we are in engineering mode. 2531*44d4804dSStefan Eßer * @param newline Whether to print backslash+newlines on long enough lines. 2532*44d4804dSStefan Eßer */ 2533*44d4804dSStefan Eßer static void bc_num_printExponent(const BcNum *restrict n, 2534*44d4804dSStefan Eßer bool eng, bool newline) 2535*44d4804dSStefan Eßer { 253650696a6eSStefan Eßer size_t places, mod, nrdx = BC_NUM_RDX_VAL(n); 253750696a6eSStefan Eßer bool neg = (n->len <= nrdx); 2538252884aeSStefan Eßer BcNum temp, exp; 2539252884aeSStefan Eßer BcDig digs[BC_NUM_BIGDIG_LOG10]; 2540252884aeSStefan Eßer 2541252884aeSStefan Eßer BC_SIG_LOCK; 2542252884aeSStefan Eßer 2543252884aeSStefan Eßer bc_num_createCopy(&temp, n); 2544252884aeSStefan Eßer 2545252884aeSStefan Eßer BC_SETJMP_LOCKED(exit); 2546252884aeSStefan Eßer 2547252884aeSStefan Eßer BC_SIG_UNLOCK; 2548252884aeSStefan Eßer 2549*44d4804dSStefan Eßer // We need to calculate the exponents, and they change based on whether the 2550*44d4804dSStefan Eßer // number is all fractional or not, obviously. 2551252884aeSStefan Eßer if (neg) { 2552252884aeSStefan Eßer 2553*44d4804dSStefan Eßer // Figure out how many limbs after the decimal point is zero. 2554*44d4804dSStefan Eßer size_t i, idx = bc_num_nonZeroLen(n) - 1; 2555252884aeSStefan Eßer 2556252884aeSStefan Eßer places = 1; 2557252884aeSStefan Eßer 2558*44d4804dSStefan Eßer // Figure out how much in the last limb is zero. 2559252884aeSStefan Eßer for (i = BC_BASE_DIGS - 1; i < BC_BASE_DIGS; --i) { 2560252884aeSStefan Eßer if (bc_num_pow10[i] > (BcBigDig) n->num[idx]) places += 1; 2561252884aeSStefan Eßer else break; 2562252884aeSStefan Eßer } 2563252884aeSStefan Eßer 2564*44d4804dSStefan Eßer // Calculate the combination of zero limbs and zero digits in the last 2565*44d4804dSStefan Eßer // limb. 256650696a6eSStefan Eßer places += (nrdx - (idx + 1)) * BC_BASE_DIGS; 2567252884aeSStefan Eßer mod = places % 3; 2568252884aeSStefan Eßer 2569*44d4804dSStefan Eßer // Calculate places if we are in engineering mode. 2570252884aeSStefan Eßer if (eng && mod != 0) places += 3 - mod; 2571*44d4804dSStefan Eßer 2572*44d4804dSStefan Eßer // Shift the temp to the right place. 2573252884aeSStefan Eßer bc_num_shiftLeft(&temp, places); 2574252884aeSStefan Eßer } 2575252884aeSStefan Eßer else { 2576*44d4804dSStefan Eßer 2577*44d4804dSStefan Eßer // This is the number of digits that we are supposed to put behind the 2578*44d4804dSStefan Eßer // decimal point. 2579252884aeSStefan Eßer places = bc_num_intDigits(n) - 1; 2580*44d4804dSStefan Eßer 2581*44d4804dSStefan Eßer // Calculate the true number based on whether engineering mode is 2582*44d4804dSStefan Eßer // activated. 2583252884aeSStefan Eßer mod = places % 3; 2584252884aeSStefan Eßer if (eng && mod != 0) places -= 3 - (3 - mod); 2585*44d4804dSStefan Eßer 2586*44d4804dSStefan Eßer // Shift the temp to the right place. 2587252884aeSStefan Eßer bc_num_shiftRight(&temp, places); 2588252884aeSStefan Eßer } 2589252884aeSStefan Eßer 2590*44d4804dSStefan Eßer // Print the shifted number. 2591*44d4804dSStefan Eßer bc_num_printDecimal(&temp, newline); 2592252884aeSStefan Eßer 2593*44d4804dSStefan Eßer // Print the e. 2594*44d4804dSStefan Eßer bc_num_putchar('e', !newline); 2595*44d4804dSStefan Eßer 2596*44d4804dSStefan Eßer // Need to explicitly print a zero exponent. 2597252884aeSStefan Eßer if (!places) { 2598*44d4804dSStefan Eßer bc_num_printHex(0, 1, false, !newline); 2599252884aeSStefan Eßer goto exit; 2600252884aeSStefan Eßer } 2601252884aeSStefan Eßer 2602*44d4804dSStefan Eßer // Need to print sign for the exponent. 2603*44d4804dSStefan Eßer if (neg) bc_num_putchar('-', true); 2604252884aeSStefan Eßer 2605*44d4804dSStefan Eßer // Create a temporary for the exponent... 2606252884aeSStefan Eßer bc_num_setup(&exp, digs, BC_NUM_BIGDIG_LOG10); 2607252884aeSStefan Eßer bc_num_bigdig2num(&exp, (BcBigDig) places); 2608252884aeSStefan Eßer 2609*44d4804dSStefan Eßer /// ..and print it. 2610*44d4804dSStefan Eßer bc_num_printDecimal(&exp, newline); 2611252884aeSStefan Eßer 2612252884aeSStefan Eßer exit: 2613252884aeSStefan Eßer BC_SIG_MAYLOCK; 2614252884aeSStefan Eßer bc_num_free(&temp); 2615252884aeSStefan Eßer BC_LONGJMP_CONT; 2616252884aeSStefan Eßer } 2617252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 2618252884aeSStefan Eßer 2619*44d4804dSStefan Eßer /** 2620*44d4804dSStefan Eßer * Converts a number from limbs with base BC_BASE_POW to base @a pow, where 2621*44d4804dSStefan Eßer * @a pow is obase^N. 2622*44d4804dSStefan Eßer * @param n The number to convert. 2623*44d4804dSStefan Eßer * @param rem BC_BASE_POW - @a pow. 2624*44d4804dSStefan Eßer * @param pow The power of obase we will convert the number to. 2625*44d4804dSStefan Eßer * @param idx The index of the number to start converting at. Doing the 2626*44d4804dSStefan Eßer * conversion is O(n^2); we have to sweep through starting at the 2627*44d4804dSStefan Eßer * least significant limb 2628*44d4804dSStefan Eßer */ 2629252884aeSStefan Eßer static void bc_num_printFixup(BcNum *restrict n, BcBigDig rem, 2630252884aeSStefan Eßer BcBigDig pow, size_t idx) 2631252884aeSStefan Eßer { 2632252884aeSStefan Eßer size_t i, len = n->len - idx; 2633252884aeSStefan Eßer BcBigDig acc; 2634252884aeSStefan Eßer BcDig *a = n->num + idx; 2635252884aeSStefan Eßer 2636*44d4804dSStefan Eßer // Ignore if there's just one limb left. This is the part that requires the 2637*44d4804dSStefan Eßer // extra loop after the one calling this function in bc_num_printPrepare(). 2638252884aeSStefan Eßer if (len < 2) return; 2639252884aeSStefan Eßer 2640*44d4804dSStefan Eßer // Loop through the remaining limbs and convert. We start at the second limb 2641*44d4804dSStefan Eßer // because we pull the value from the previous one as well. 2642252884aeSStefan Eßer for (i = len - 1; i > 0; --i) { 2643252884aeSStefan Eßer 2644*44d4804dSStefan Eßer // Get the limb and add it to the previous, along with multiplying by 2645*44d4804dSStefan Eßer // the remainder because that's the proper overflow. "acc" means 2646*44d4804dSStefan Eßer // "accumulator," by the way. 2647252884aeSStefan Eßer acc = ((BcBigDig) a[i]) * rem + ((BcBigDig) a[i - 1]); 2648*44d4804dSStefan Eßer 2649*44d4804dSStefan Eßer // Store a value in base pow in the previous limb. 2650252884aeSStefan Eßer a[i - 1] = (BcDig) (acc % pow); 2651*44d4804dSStefan Eßer 2652*44d4804dSStefan Eßer // Divide by the base and accumulate the remaining value in the limb. 2653252884aeSStefan Eßer acc /= pow; 2654252884aeSStefan Eßer acc += (BcBigDig) a[i]; 2655252884aeSStefan Eßer 2656*44d4804dSStefan Eßer // If the accumulator is greater than the base... 2657252884aeSStefan Eßer if (acc >= BC_BASE_POW) { 2658252884aeSStefan Eßer 2659*44d4804dSStefan Eßer // Do we need to grow? 2660252884aeSStefan Eßer if (i == len - 1) { 2661*44d4804dSStefan Eßer 2662*44d4804dSStefan Eßer // Grow. 2663252884aeSStefan Eßer len = bc_vm_growSize(len, 1); 2664252884aeSStefan Eßer bc_num_expand(n, bc_vm_growSize(len, idx)); 2665*44d4804dSStefan Eßer 2666*44d4804dSStefan Eßer // Update the pointer because it may have moved. 2667252884aeSStefan Eßer a = n->num + idx; 2668*44d4804dSStefan Eßer 2669*44d4804dSStefan Eßer // Zero out the last limb. 2670252884aeSStefan Eßer a[len - 1] = 0; 2671252884aeSStefan Eßer } 2672252884aeSStefan Eßer 2673*44d4804dSStefan Eßer // Overflow into the next limb since we are over the base. 2674252884aeSStefan Eßer a[i + 1] += acc / BC_BASE_POW; 2675252884aeSStefan Eßer acc %= BC_BASE_POW; 2676252884aeSStefan Eßer } 2677252884aeSStefan Eßer 2678252884aeSStefan Eßer assert(acc < BC_BASE_POW); 2679*44d4804dSStefan Eßer 2680*44d4804dSStefan Eßer // Set the limb. 2681252884aeSStefan Eßer a[i] = (BcDig) acc; 2682252884aeSStefan Eßer } 2683252884aeSStefan Eßer 2684*44d4804dSStefan Eßer // We may have grown the number, so adjust the length. 2685252884aeSStefan Eßer n->len = len + idx; 2686252884aeSStefan Eßer } 2687252884aeSStefan Eßer 2688*44d4804dSStefan Eßer /** 2689*44d4804dSStefan Eßer * Prepares a number for printing in a base that is not a divisor of 2690*44d4804dSStefan Eßer * BC_BASE_POW. This basically converts the number from having limbs of base 2691*44d4804dSStefan Eßer * BC_BASE_POW to limbs of pow, where pow is obase^N. 2692*44d4804dSStefan Eßer * @param n The number to prepare for printing. 2693*44d4804dSStefan Eßer * @param rem The remainder of BC_BASE_POW when divided by a power of the base. 2694*44d4804dSStefan Eßer * @param pow The power of the base. 2695*44d4804dSStefan Eßer */ 2696*44d4804dSStefan Eßer static void bc_num_printPrepare(BcNum *restrict n, BcBigDig rem, BcBigDig pow) { 2697*44d4804dSStefan Eßer 2698252884aeSStefan Eßer size_t i; 2699252884aeSStefan Eßer 2700*44d4804dSStefan Eßer // Loop from the least significant limb to the most significant limb and 2701*44d4804dSStefan Eßer // convert limbs in each pass. 2702252884aeSStefan Eßer for (i = 0; i < n->len; ++i) bc_num_printFixup(n, rem, pow, i); 2703252884aeSStefan Eßer 2704*44d4804dSStefan Eßer // bc_num_printFixup() does not do everything it is supposed to, so we do 2705*44d4804dSStefan Eßer // the last bit of cleanup here. That cleanup is to ensure that each limb 2706*44d4804dSStefan Eßer // is less than pow and to expand the number to fit new limbs as necessary. 2707252884aeSStefan Eßer for (i = 0; i < n->len; ++i) { 2708252884aeSStefan Eßer 2709252884aeSStefan Eßer assert(pow == ((BcBigDig) ((BcDig) pow))); 2710252884aeSStefan Eßer 2711*44d4804dSStefan Eßer // If the limb needs fixing... 2712252884aeSStefan Eßer if (n->num[i] >= (BcDig) pow) { 2713252884aeSStefan Eßer 2714*44d4804dSStefan Eßer // Do we need to grow? 2715252884aeSStefan Eßer if (i + 1 == n->len) { 2716*44d4804dSStefan Eßer 2717*44d4804dSStefan Eßer // Grow the number. 2718252884aeSStefan Eßer n->len = bc_vm_growSize(n->len, 1); 2719252884aeSStefan Eßer bc_num_expand(n, n->len); 2720*44d4804dSStefan Eßer 2721*44d4804dSStefan Eßer // Without this, we might use uninitialized data. 2722252884aeSStefan Eßer n->num[i + 1] = 0; 2723252884aeSStefan Eßer } 2724252884aeSStefan Eßer 2725252884aeSStefan Eßer assert(pow < BC_BASE_POW); 2726*44d4804dSStefan Eßer 2727*44d4804dSStefan Eßer // Overflow into the next limb. 2728252884aeSStefan Eßer n->num[i + 1] += n->num[i] / ((BcDig) pow); 2729252884aeSStefan Eßer n->num[i] %= (BcDig) pow; 2730252884aeSStefan Eßer } 2731252884aeSStefan Eßer } 2732252884aeSStefan Eßer } 2733252884aeSStefan Eßer 2734*44d4804dSStefan Eßer static void bc_num_printNum(BcNum *restrict n, BcBigDig base, size_t len, 2735*44d4804dSStefan Eßer BcNumDigitOp print, bool newline) 2736252884aeSStefan Eßer { 2737252884aeSStefan Eßer BcVec stack; 2738252884aeSStefan Eßer BcNum intp, fracp1, fracp2, digit, flen1, flen2, *n1, *n2, *temp; 2739252884aeSStefan Eßer BcBigDig dig = 0, *ptr, acc, exp; 2740*44d4804dSStefan Eßer size_t i, j, nrdx, idigits; 2741252884aeSStefan Eßer bool radix; 2742252884aeSStefan Eßer BcDig digit_digs[BC_NUM_BIGDIG_LOG10 + 1]; 2743252884aeSStefan Eßer 2744252884aeSStefan Eßer assert(base > 1); 2745252884aeSStefan Eßer 2746*44d4804dSStefan Eßer // Easy case. Even with scale, we just print this. 2747252884aeSStefan Eßer if (BC_NUM_ZERO(n)) { 2748*44d4804dSStefan Eßer print(0, len, false, !newline); 2749252884aeSStefan Eßer return; 2750252884aeSStefan Eßer } 2751252884aeSStefan Eßer 2752252884aeSStefan Eßer // This function uses an algorithm that Stefan Esser <se@freebsd.org> came 2753252884aeSStefan Eßer // up with to print the integer part of a number. What it does is convert 2754252884aeSStefan Eßer // intp into a number of the specified base, but it does it directly, 2755252884aeSStefan Eßer // instead of just doing a series of divisions and printing the remainders 2756252884aeSStefan Eßer // in reverse order. 2757252884aeSStefan Eßer // 2758252884aeSStefan Eßer // Let me explain in a bit more detail: 2759252884aeSStefan Eßer // 2760*44d4804dSStefan Eßer // The algorithm takes the current least significant limb (after intp has 2761*44d4804dSStefan Eßer // been converted to an integer) and the next to least significant limb, and 2762*44d4804dSStefan Eßer // it converts the least significant limb into one of the specified base, 2763*44d4804dSStefan Eßer // putting any overflow into the next to least significant limb. It iterates 2764*44d4804dSStefan Eßer // through the whole number, from least significant to most significant, 2765*44d4804dSStefan Eßer // doing this conversion. At the end of that iteration, the least 2766*44d4804dSStefan Eßer // significant limb is converted, but the others are not, so it iterates 2767*44d4804dSStefan Eßer // again, starting at the next to least significant limb. It keeps doing 2768*44d4804dSStefan Eßer // that conversion, skipping one more limb than the last time, until all 2769*44d4804dSStefan Eßer // limbs have been converted. Then it prints them in reverse order. 2770252884aeSStefan Eßer // 2771252884aeSStefan Eßer // That is the gist of the algorithm. It leaves out several things, such as 2772*44d4804dSStefan Eßer // the fact that limbs are not always converted into the specified base, but 2773*44d4804dSStefan Eßer // into something close, basically a power of the specified base. In 2774252884aeSStefan Eßer // Stefan's words, "You could consider BcDigs to be of base 10^BC_BASE_DIGS 2775252884aeSStefan Eßer // in the normal case and obase^N for the largest value of N that satisfies 2776252884aeSStefan Eßer // obase^N <= 10^BC_BASE_DIGS. [This means that] the result is not in base 2777252884aeSStefan Eßer // "obase", but in base "obase^N", which happens to be printable as a number 2778252884aeSStefan Eßer // of base "obase" without consideration for neighbouring BcDigs." This fact 2779252884aeSStefan Eßer // is what necessitates the existence of the loop later in this function. 2780252884aeSStefan Eßer // 2781252884aeSStefan Eßer // The conversion happens in bc_num_printPrepare() where the outer loop 2782252884aeSStefan Eßer // happens and bc_num_printFixup() where the inner loop, or actual 2783*44d4804dSStefan Eßer // conversion, happens. In other words, bc_num_printPrepare() is where the 2784*44d4804dSStefan Eßer // loop that starts at the least significant limb and goes to the most 2785*44d4804dSStefan Eßer // significant limb. Then, on every iteration of its loop, it calls 2786*44d4804dSStefan Eßer // bc_num_printFixup(), which has the inner loop of actually converting 2787*44d4804dSStefan Eßer // the limbs it passes into limbs of base obase^N rather than base 2788*44d4804dSStefan Eßer // BC_BASE_POW. 2789252884aeSStefan Eßer 279050696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL(n); 279150696a6eSStefan Eßer 2792252884aeSStefan Eßer BC_SIG_LOCK; 2793252884aeSStefan Eßer 2794*44d4804dSStefan Eßer // The stack is what allows us to reverse the digits for printing. 2795*44d4804dSStefan Eßer bc_vec_init(&stack, sizeof(BcBigDig), BC_DTOR_NONE); 279650696a6eSStefan Eßer bc_num_init(&fracp1, nrdx); 2797252884aeSStefan Eßer 2798*44d4804dSStefan Eßer // intp will be the "integer part" of the number, so copy it. 2799252884aeSStefan Eßer bc_num_createCopy(&intp, n); 2800252884aeSStefan Eßer 2801252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 2802252884aeSStefan Eßer 2803252884aeSStefan Eßer BC_SIG_UNLOCK; 2804252884aeSStefan Eßer 2805*44d4804dSStefan Eßer // Make intp an integer. 2806252884aeSStefan Eßer bc_num_truncate(&intp, intp.scale); 2807252884aeSStefan Eßer 2808*44d4804dSStefan Eßer // Get the fractional part out. 2809252884aeSStefan Eßer bc_num_sub(n, &intp, &fracp1, 0); 2810252884aeSStefan Eßer 2811*44d4804dSStefan Eßer // If the base is not the same as the last base used for printing, we need 2812*44d4804dSStefan Eßer // to update the cached exponent and power. Yes, we cache the values of the 2813*44d4804dSStefan Eßer // exponent and power. That is to prevent us from calculating them every 2814*44d4804dSStefan Eßer // time because printing will probably happen multiple times on the same 2815*44d4804dSStefan Eßer // base. 2816252884aeSStefan Eßer if (base != vm.last_base) { 2817252884aeSStefan Eßer 2818252884aeSStefan Eßer vm.last_pow = 1; 2819252884aeSStefan Eßer vm.last_exp = 0; 2820252884aeSStefan Eßer 2821*44d4804dSStefan Eßer // Calculate the exponent and power. 2822252884aeSStefan Eßer while (vm.last_pow * base <= BC_BASE_POW) { 2823252884aeSStefan Eßer vm.last_pow *= base; 2824252884aeSStefan Eßer vm.last_exp += 1; 2825252884aeSStefan Eßer } 2826252884aeSStefan Eßer 2827*44d4804dSStefan Eßer // Also, the remainder and base itself. 2828252884aeSStefan Eßer vm.last_rem = BC_BASE_POW - vm.last_pow; 2829252884aeSStefan Eßer vm.last_base = base; 2830252884aeSStefan Eßer } 2831252884aeSStefan Eßer 2832252884aeSStefan Eßer exp = vm.last_exp; 2833252884aeSStefan Eßer 2834*44d4804dSStefan Eßer // If vm.last_rem is 0, then the base we are printing in is a divisor of 2835*44d4804dSStefan Eßer // BC_BASE_POW, which is the easy case because it means that BC_BASE_POW is 2836*44d4804dSStefan Eßer // a power of obase, and no conversion is needed. If it *is* 0, then we have 2837*44d4804dSStefan Eßer // the hard case, and we have to prepare the number for the base. 2838252884aeSStefan Eßer if (vm.last_rem != 0) bc_num_printPrepare(&intp, vm.last_rem, vm.last_pow); 2839252884aeSStefan Eßer 2840*44d4804dSStefan Eßer // After the conversion comes the surprisingly easy part. From here on out, 2841*44d4804dSStefan Eßer // this is basically naive code that I wrote, adjusted for the larger bases. 2842*44d4804dSStefan Eßer 2843*44d4804dSStefan Eßer // Fill the stack of digits for the integer part. 2844252884aeSStefan Eßer for (i = 0; i < intp.len; ++i) { 2845252884aeSStefan Eßer 2846*44d4804dSStefan Eßer // Get the limb. 2847252884aeSStefan Eßer acc = (BcBigDig) intp.num[i]; 2848252884aeSStefan Eßer 2849*44d4804dSStefan Eßer // Turn the limb into digits of base obase. 2850252884aeSStefan Eßer for (j = 0; j < exp && (i < intp.len - 1 || acc != 0); ++j) 2851252884aeSStefan Eßer { 2852*44d4804dSStefan Eßer // This condition is true if we are not at the last digit. 2853252884aeSStefan Eßer if (j != exp - 1) { 2854252884aeSStefan Eßer dig = acc % base; 2855252884aeSStefan Eßer acc /= base; 2856252884aeSStefan Eßer } 2857252884aeSStefan Eßer else { 2858252884aeSStefan Eßer dig = acc; 2859252884aeSStefan Eßer acc = 0; 2860252884aeSStefan Eßer } 2861252884aeSStefan Eßer 2862252884aeSStefan Eßer assert(dig < base); 2863252884aeSStefan Eßer 2864*44d4804dSStefan Eßer // Push the digit onto the stack. 2865252884aeSStefan Eßer bc_vec_push(&stack, &dig); 2866252884aeSStefan Eßer } 2867252884aeSStefan Eßer 2868252884aeSStefan Eßer assert(acc == 0); 2869252884aeSStefan Eßer } 2870252884aeSStefan Eßer 2871*44d4804dSStefan Eßer // Go through the stack backwards and print each digit. 2872252884aeSStefan Eßer for (i = 0; i < stack.len; ++i) { 2873*44d4804dSStefan Eßer 2874252884aeSStefan Eßer ptr = bc_vec_item_rev(&stack, i); 2875*44d4804dSStefan Eßer 2876252884aeSStefan Eßer assert(ptr != NULL); 2877*44d4804dSStefan Eßer 2878*44d4804dSStefan Eßer // While the first three arguments should be self-explanatory, the last 2879*44d4804dSStefan Eßer // needs explaining. I don't want to print a newline when the last digit 2880*44d4804dSStefan Eßer // to be printed could take the place of the backslash rather than being 2881*44d4804dSStefan Eßer // pushed, as a single character, to the next line. That's what that 2882*44d4804dSStefan Eßer // last argument does for bc. 2883*44d4804dSStefan Eßer print(*ptr, len, false, !newline || 2884*44d4804dSStefan Eßer (n->scale != 0 || i == stack.len - 1)); 2885252884aeSStefan Eßer } 2886252884aeSStefan Eßer 2887*44d4804dSStefan Eßer // We are done if there is no fractional part. 2888252884aeSStefan Eßer if (!n->scale) goto err; 2889252884aeSStefan Eßer 2890252884aeSStefan Eßer BC_SIG_LOCK; 2891252884aeSStefan Eßer 2892*44d4804dSStefan Eßer // Reset the jump because some locals are changing. 2893252884aeSStefan Eßer BC_UNSETJMP; 2894252884aeSStefan Eßer 289550696a6eSStefan Eßer bc_num_init(&fracp2, nrdx); 2896252884aeSStefan Eßer bc_num_setup(&digit, digit_digs, sizeof(digit_digs) / sizeof(BcDig)); 2897252884aeSStefan Eßer bc_num_init(&flen1, BC_NUM_BIGDIG_LOG10); 2898252884aeSStefan Eßer bc_num_init(&flen2, BC_NUM_BIGDIG_LOG10); 2899252884aeSStefan Eßer 2900252884aeSStefan Eßer BC_SETJMP_LOCKED(frac_err); 2901252884aeSStefan Eßer 2902252884aeSStefan Eßer BC_SIG_UNLOCK; 2903252884aeSStefan Eßer 2904252884aeSStefan Eßer bc_num_one(&flen1); 2905252884aeSStefan Eßer 2906252884aeSStefan Eßer radix = true; 2907*44d4804dSStefan Eßer 2908*44d4804dSStefan Eßer // Pointers for easy switching. 2909252884aeSStefan Eßer n1 = &flen1; 2910252884aeSStefan Eßer n2 = &flen2; 2911252884aeSStefan Eßer 2912252884aeSStefan Eßer fracp2.scale = n->scale; 291350696a6eSStefan Eßer BC_NUM_RDX_SET_NP(fracp2, BC_NUM_RDX(fracp2.scale)); 2914252884aeSStefan Eßer 2915*44d4804dSStefan Eßer // As long as we have not reached the scale of the number, keep printing. 2916*44d4804dSStefan Eßer while ((idigits = bc_num_intDigits(n1)) <= n->scale) { 2917252884aeSStefan Eßer 2918*44d4804dSStefan Eßer // These numbers will keep growing. 2919252884aeSStefan Eßer bc_num_expand(&fracp2, fracp1.len + 1); 2920252884aeSStefan Eßer bc_num_mulArray(&fracp1, base, &fracp2); 292150696a6eSStefan Eßer 292250696a6eSStefan Eßer nrdx = BC_NUM_RDX_VAL_NP(fracp2); 292350696a6eSStefan Eßer 2924*44d4804dSStefan Eßer // Ensure an invariant. 292550696a6eSStefan Eßer if (fracp2.len < nrdx) fracp2.len = nrdx; 2926252884aeSStefan Eßer 2927252884aeSStefan Eßer // fracp is guaranteed to be non-negative and small enough. 2928*44d4804dSStefan Eßer dig = bc_num_bigdig2(&fracp2); 2929252884aeSStefan Eßer 2930*44d4804dSStefan Eßer // Convert the digit to a number and subtract it from the number. 2931252884aeSStefan Eßer bc_num_bigdig2num(&digit, dig); 2932252884aeSStefan Eßer bc_num_sub(&fracp2, &digit, &fracp1, 0); 2933252884aeSStefan Eßer 2934*44d4804dSStefan Eßer // While the first three arguments should be self-explanatory, the last 2935*44d4804dSStefan Eßer // needs explaining. I don't want to print a newline when the last digit 2936*44d4804dSStefan Eßer // to be printed could take the place of the backslash rather than being 2937*44d4804dSStefan Eßer // pushed, as a single character, to the next line. That's what that 2938*44d4804dSStefan Eßer // last argument does for bc. 2939*44d4804dSStefan Eßer print(dig, len, radix, !newline || idigits != n->scale); 2940*44d4804dSStefan Eßer 2941*44d4804dSStefan Eßer // Update the multipliers. 2942252884aeSStefan Eßer bc_num_mulArray(n1, base, n2); 2943252884aeSStefan Eßer 2944252884aeSStefan Eßer radix = false; 2945*44d4804dSStefan Eßer 2946*44d4804dSStefan Eßer // Switch. 2947252884aeSStefan Eßer temp = n1; 2948252884aeSStefan Eßer n1 = n2; 2949252884aeSStefan Eßer n2 = temp; 2950252884aeSStefan Eßer } 2951252884aeSStefan Eßer 2952252884aeSStefan Eßer frac_err: 2953252884aeSStefan Eßer BC_SIG_MAYLOCK; 2954252884aeSStefan Eßer bc_num_free(&flen2); 2955252884aeSStefan Eßer bc_num_free(&flen1); 2956252884aeSStefan Eßer bc_num_free(&fracp2); 2957252884aeSStefan Eßer err: 2958252884aeSStefan Eßer BC_SIG_MAYLOCK; 2959252884aeSStefan Eßer bc_num_free(&fracp1); 2960252884aeSStefan Eßer bc_num_free(&intp); 2961252884aeSStefan Eßer bc_vec_free(&stack); 2962252884aeSStefan Eßer BC_LONGJMP_CONT; 2963252884aeSStefan Eßer } 2964252884aeSStefan Eßer 2965*44d4804dSStefan Eßer /** 2966*44d4804dSStefan Eßer * Prints a number in the specified base, or rather, figures out which function 2967*44d4804dSStefan Eßer * to call to print the number in the specified base and calls it. 2968*44d4804dSStefan Eßer * @param n The number to print. 2969*44d4804dSStefan Eßer * @param base The base to print in. 2970*44d4804dSStefan Eßer * @param newline Whether to print backslash+newlines on long enough lines. 2971*44d4804dSStefan Eßer */ 2972*44d4804dSStefan Eßer static void bc_num_printBase(BcNum *restrict n, BcBigDig base, bool newline) { 2973252884aeSStefan Eßer 2974252884aeSStefan Eßer size_t width; 2975252884aeSStefan Eßer BcNumDigitOp print; 297650696a6eSStefan Eßer bool neg = BC_NUM_NEG(n); 2977252884aeSStefan Eßer 2978*44d4804dSStefan Eßer // Just take care of the sign right here. 2979*44d4804dSStefan Eßer if (neg) bc_num_putchar('-', true); 2980252884aeSStefan Eßer 2981*44d4804dSStefan Eßer // Clear the sign because it makes the actual printing easier when we have 2982*44d4804dSStefan Eßer // to do math. 298350696a6eSStefan Eßer BC_NUM_NEG_CLR(n); 2984252884aeSStefan Eßer 2985*44d4804dSStefan Eßer // Bases at hexadecimal and below are printed as one character, larger bases 2986*44d4804dSStefan Eßer // are printed as a series of digits separated by spaces. 2987252884aeSStefan Eßer if (base <= BC_NUM_MAX_POSIX_IBASE) { 2988252884aeSStefan Eßer width = 1; 2989252884aeSStefan Eßer print = bc_num_printHex; 2990252884aeSStefan Eßer } 2991252884aeSStefan Eßer else { 2992252884aeSStefan Eßer assert(base <= BC_BASE_POW); 2993252884aeSStefan Eßer width = bc_num_log10(base - 1); 2994252884aeSStefan Eßer print = bc_num_printDigits; 2995252884aeSStefan Eßer } 2996252884aeSStefan Eßer 2997*44d4804dSStefan Eßer // Print. 2998*44d4804dSStefan Eßer bc_num_printNum(n, base, width, print, newline); 2999*44d4804dSStefan Eßer 3000*44d4804dSStefan Eßer // Reset the sign. 300150696a6eSStefan Eßer n->rdx = BC_NUM_NEG_VAL(n, neg); 3002252884aeSStefan Eßer } 3003252884aeSStefan Eßer 3004*44d4804dSStefan Eßer #if !BC_ENABLE_LIBRARY 3005*44d4804dSStefan Eßer 3006*44d4804dSStefan Eßer void bc_num_stream(BcNum *restrict n) { 3007*44d4804dSStefan Eßer bc_num_printNum(n, BC_NUM_STREAM_BASE, 1, bc_num_printChar, false); 3008252884aeSStefan Eßer } 3009*44d4804dSStefan Eßer 3010*44d4804dSStefan Eßer #endif // !BC_ENABLE_LIBRARY 3011252884aeSStefan Eßer 3012252884aeSStefan Eßer void bc_num_setup(BcNum *restrict n, BcDig *restrict num, size_t cap) { 3013252884aeSStefan Eßer assert(n != NULL); 3014252884aeSStefan Eßer n->num = num; 3015252884aeSStefan Eßer n->cap = cap; 3016252884aeSStefan Eßer bc_num_zero(n); 3017252884aeSStefan Eßer } 3018252884aeSStefan Eßer 3019252884aeSStefan Eßer void bc_num_init(BcNum *restrict n, size_t req) { 3020252884aeSStefan Eßer 3021252884aeSStefan Eßer BcDig *num; 3022252884aeSStefan Eßer 3023252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 3024252884aeSStefan Eßer 3025252884aeSStefan Eßer assert(n != NULL); 3026252884aeSStefan Eßer 3027*44d4804dSStefan Eßer // BC_NUM_DEF_SIZE is set to be about the smallest allocation size that 3028*44d4804dSStefan Eßer // malloc() returns in practice, so just use it. 3029252884aeSStefan Eßer req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; 3030252884aeSStefan Eßer 3031*44d4804dSStefan Eßer // If we can't use a temp, allocate. 3032*44d4804dSStefan Eßer if (req != BC_NUM_DEF_SIZE || (num = bc_vm_takeTemp()) == NULL) 3033*44d4804dSStefan Eßer num = bc_vm_malloc(BC_NUM_SIZE(req)); 3034252884aeSStefan Eßer 3035252884aeSStefan Eßer bc_num_setup(n, num, req); 3036252884aeSStefan Eßer } 3037252884aeSStefan Eßer 3038252884aeSStefan Eßer void bc_num_clear(BcNum *restrict n) { 3039252884aeSStefan Eßer n->num = NULL; 3040252884aeSStefan Eßer n->cap = 0; 3041252884aeSStefan Eßer } 3042252884aeSStefan Eßer 3043252884aeSStefan Eßer void bc_num_free(void *num) { 3044252884aeSStefan Eßer 3045252884aeSStefan Eßer BcNum *n = (BcNum*) num; 3046252884aeSStefan Eßer 3047252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 3048252884aeSStefan Eßer 3049252884aeSStefan Eßer assert(n != NULL); 3050252884aeSStefan Eßer 3051*44d4804dSStefan Eßer if (n->cap == BC_NUM_DEF_SIZE) bc_vm_addTemp(n->num); 3052252884aeSStefan Eßer else free(n->num); 3053252884aeSStefan Eßer } 3054252884aeSStefan Eßer 3055252884aeSStefan Eßer void bc_num_copy(BcNum *d, const BcNum *s) { 3056*44d4804dSStefan Eßer 3057252884aeSStefan Eßer assert(d != NULL && s != NULL); 3058*44d4804dSStefan Eßer 3059252884aeSStefan Eßer if (d == s) return; 3060*44d4804dSStefan Eßer 3061252884aeSStefan Eßer bc_num_expand(d, s->len); 3062252884aeSStefan Eßer d->len = s->len; 3063*44d4804dSStefan Eßer 3064*44d4804dSStefan Eßer // I can just copy directly here because the sign *and* rdx will be 3065*44d4804dSStefan Eßer // properly preserved. 3066252884aeSStefan Eßer d->rdx = s->rdx; 3067252884aeSStefan Eßer d->scale = s->scale; 3068252884aeSStefan Eßer memcpy(d->num, s->num, BC_NUM_SIZE(d->len)); 3069252884aeSStefan Eßer } 3070252884aeSStefan Eßer 3071252884aeSStefan Eßer void bc_num_createCopy(BcNum *d, const BcNum *s) { 3072252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 3073252884aeSStefan Eßer bc_num_init(d, s->len); 3074252884aeSStefan Eßer bc_num_copy(d, s); 3075252884aeSStefan Eßer } 3076252884aeSStefan Eßer 3077*44d4804dSStefan Eßer void bc_num_createFromBigdig(BcNum *restrict n, BcBigDig val) { 3078252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 307950696a6eSStefan Eßer bc_num_init(n, BC_NUM_BIGDIG_LOG10); 3080252884aeSStefan Eßer bc_num_bigdig2num(n, val); 3081252884aeSStefan Eßer } 3082252884aeSStefan Eßer 3083252884aeSStefan Eßer size_t bc_num_scale(const BcNum *restrict n) { 3084252884aeSStefan Eßer return n->scale; 3085252884aeSStefan Eßer } 3086252884aeSStefan Eßer 3087252884aeSStefan Eßer size_t bc_num_len(const BcNum *restrict n) { 3088252884aeSStefan Eßer 3089252884aeSStefan Eßer size_t len = n->len; 3090252884aeSStefan Eßer 3091*44d4804dSStefan Eßer // Always return at least 1. 3092028616d0SStefan Eßer if (BC_NUM_ZERO(n)) return n->scale ? n->scale : 1; 3093252884aeSStefan Eßer 3094*44d4804dSStefan Eßer // If this is true, there is no integer portion of the number. 309550696a6eSStefan Eßer if (BC_NUM_RDX_VAL(n) == len) { 3096252884aeSStefan Eßer 3097*44d4804dSStefan Eßer // We have to take into account the fact that some of the digits right 3098*44d4804dSStefan Eßer // after the decimal could be zero. If that is the case, we need to 3099*44d4804dSStefan Eßer // ignore them until we hit the first non-zero digit. 3100*44d4804dSStefan Eßer 3101252884aeSStefan Eßer size_t zero, scale; 3102252884aeSStefan Eßer 3103*44d4804dSStefan Eßer // The number of limbs with non-zero digits. 3104*44d4804dSStefan Eßer len = bc_num_nonZeroLen(n); 3105252884aeSStefan Eßer 3106*44d4804dSStefan Eßer // Get the number of digits in the last limb. 3107252884aeSStefan Eßer scale = n->scale % BC_BASE_DIGS; 3108252884aeSStefan Eßer scale = scale ? scale : BC_BASE_DIGS; 3109252884aeSStefan Eßer 3110*44d4804dSStefan Eßer // Get the number of zero digits. 3111252884aeSStefan Eßer zero = bc_num_zeroDigits(n->num + len - 1); 3112252884aeSStefan Eßer 3113*44d4804dSStefan Eßer // Calculate the true length. 3114252884aeSStefan Eßer len = len * BC_BASE_DIGS - zero - (BC_BASE_DIGS - scale); 3115252884aeSStefan Eßer } 3116*44d4804dSStefan Eßer // Otherwise, count the number of int digits and return that plus the scale. 3117252884aeSStefan Eßer else len = bc_num_intDigits(n) + n->scale; 3118252884aeSStefan Eßer 3119252884aeSStefan Eßer return len; 3120252884aeSStefan Eßer } 3121252884aeSStefan Eßer 312250696a6eSStefan Eßer void bc_num_parse(BcNum *restrict n, const char *restrict val, BcBigDig base) { 312350696a6eSStefan Eßer 3124252884aeSStefan Eßer assert(n != NULL && val != NULL && base); 3125252884aeSStefan Eßer assert(base >= BC_NUM_MIN_BASE && base <= vm.maxes[BC_PROG_GLOBALS_IBASE]); 3126252884aeSStefan Eßer assert(bc_num_strValid(val)); 3127252884aeSStefan Eßer 3128*44d4804dSStefan Eßer // A one character number is *always* parsed as though the base was the 3129*44d4804dSStefan Eßer // maximum allowed ibase, per the bc spec. 313050696a6eSStefan Eßer if (!val[1]) { 3131252884aeSStefan Eßer BcBigDig dig = bc_num_parseChar(val[0], BC_NUM_MAX_LBASE); 3132252884aeSStefan Eßer bc_num_bigdig2num(n, dig); 3133252884aeSStefan Eßer } 3134252884aeSStefan Eßer else if (base == BC_BASE) bc_num_parseDecimal(n, val); 3135252884aeSStefan Eßer else bc_num_parseBase(n, val, base); 313650696a6eSStefan Eßer 313750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(n)); 3138252884aeSStefan Eßer } 3139252884aeSStefan Eßer 3140252884aeSStefan Eßer void bc_num_print(BcNum *restrict n, BcBigDig base, bool newline) { 3141252884aeSStefan Eßer 3142252884aeSStefan Eßer assert(n != NULL); 3143252884aeSStefan Eßer assert(BC_ENABLE_EXTRA_MATH || base >= BC_NUM_MIN_BASE); 3144252884aeSStefan Eßer 3145*44d4804dSStefan Eßer // We may need a newline, just to start. 3146252884aeSStefan Eßer bc_num_printNewline(); 3147252884aeSStefan Eßer 3148*44d4804dSStefan Eßer // Short-circuit 0. 3149*44d4804dSStefan Eßer if (BC_NUM_ZERO(n)) bc_num_printHex(0, 1, false, !newline); 3150*44d4804dSStefan Eßer else if (base == BC_BASE) bc_num_printDecimal(n, newline); 3151252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 3152*44d4804dSStefan Eßer else if (base == 0 || base == 1) 3153*44d4804dSStefan Eßer bc_num_printExponent(n, base != 0, newline); 3154252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 3155*44d4804dSStefan Eßer else bc_num_printBase(n, base, newline); 3156252884aeSStefan Eßer 3157*44d4804dSStefan Eßer if (newline) bc_num_putchar('\n', false); 3158252884aeSStefan Eßer } 3159252884aeSStefan Eßer 3160*44d4804dSStefan Eßer BcBigDig bc_num_bigdig2(const BcNum *restrict n) { 3161252884aeSStefan Eßer 3162252884aeSStefan Eßer // This function returns no errors because it's guaranteed to succeed if 3163*44d4804dSStefan Eßer // its preconditions are met. Those preconditions include both n needs to 3164*44d4804dSStefan Eßer // be non-NULL, n being non-negative, and n being less than vm.max. If all 3165*44d4804dSStefan Eßer // of that is true, then we can just convert without worrying about negative 3166*44d4804dSStefan Eßer // errors or overflow. 3167252884aeSStefan Eßer 3168252884aeSStefan Eßer BcBigDig r = 0; 316950696a6eSStefan Eßer size_t nrdx = BC_NUM_RDX_VAL(n); 3170252884aeSStefan Eßer 3171*44d4804dSStefan Eßer assert(n != NULL); 317250696a6eSStefan Eßer assert(!BC_NUM_NEG(n)); 3173252884aeSStefan Eßer assert(bc_num_cmp(n, &vm.max) < 0); 317450696a6eSStefan Eßer assert(n->len - nrdx <= 3); 3175252884aeSStefan Eßer 3176252884aeSStefan Eßer // There is a small speed win from unrolling the loop here, and since it 3177252884aeSStefan Eßer // only adds 53 bytes, I decided that it was worth it. 317850696a6eSStefan Eßer switch (n->len - nrdx) { 317950696a6eSStefan Eßer 3180252884aeSStefan Eßer case 3: 318150696a6eSStefan Eßer { 318250696a6eSStefan Eßer r = (BcBigDig) n->num[nrdx + 2]; 318350696a6eSStefan Eßer } 3184252884aeSStefan Eßer // Fallthrough. 318550696a6eSStefan Eßer BC_FALLTHROUGH 318650696a6eSStefan Eßer 3187252884aeSStefan Eßer case 2: 318850696a6eSStefan Eßer { 318950696a6eSStefan Eßer r = r * BC_BASE_POW + (BcBigDig) n->num[nrdx + 1]; 319050696a6eSStefan Eßer } 3191252884aeSStefan Eßer // Fallthrough. 319250696a6eSStefan Eßer BC_FALLTHROUGH 319350696a6eSStefan Eßer 3194252884aeSStefan Eßer case 1: 319550696a6eSStefan Eßer { 319650696a6eSStefan Eßer r = r * BC_BASE_POW + (BcBigDig) n->num[nrdx]; 319750696a6eSStefan Eßer } 3198252884aeSStefan Eßer } 3199252884aeSStefan Eßer 3200*44d4804dSStefan Eßer return r; 3201252884aeSStefan Eßer } 3202252884aeSStefan Eßer 3203*44d4804dSStefan Eßer BcBigDig bc_num_bigdig(const BcNum *restrict n) { 3204252884aeSStefan Eßer 3205*44d4804dSStefan Eßer assert(n != NULL); 3206252884aeSStefan Eßer 3207*44d4804dSStefan Eßer // This error checking is extremely important, and if you do not have a 3208*44d4804dSStefan Eßer // guarantee that converting a number will always succeed in a particular 3209*44d4804dSStefan Eßer // case, you *must* call this function to get these error checks. This 3210*44d4804dSStefan Eßer // includes all instances of numbers inputted by the user or calculated by 3211*44d4804dSStefan Eßer // the user. Otherwise, you can call the faster bc_num_bigdig2(). 3212*44d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(n))) bc_err(BC_ERR_MATH_NEGATIVE); 3213*44d4804dSStefan Eßer if (BC_ERR(bc_num_cmp(n, &vm.max) >= 0)) bc_err(BC_ERR_MATH_OVERFLOW); 3214252884aeSStefan Eßer 3215*44d4804dSStefan Eßer return bc_num_bigdig2(n); 3216252884aeSStefan Eßer } 3217252884aeSStefan Eßer 3218252884aeSStefan Eßer void bc_num_bigdig2num(BcNum *restrict n, BcBigDig val) { 3219252884aeSStefan Eßer 3220252884aeSStefan Eßer BcDig *ptr; 3221252884aeSStefan Eßer size_t i; 3222252884aeSStefan Eßer 3223252884aeSStefan Eßer assert(n != NULL); 3224252884aeSStefan Eßer 3225252884aeSStefan Eßer bc_num_zero(n); 3226252884aeSStefan Eßer 3227*44d4804dSStefan Eßer // Already 0. 3228252884aeSStefan Eßer if (!val) return; 3229252884aeSStefan Eßer 3230*44d4804dSStefan Eßer // Expand first. This is the only way this function can fail, and it's a 3231*44d4804dSStefan Eßer // fatal error. 3232252884aeSStefan Eßer bc_num_expand(n, BC_NUM_BIGDIG_LOG10); 3233252884aeSStefan Eßer 3234*44d4804dSStefan Eßer // The conversion is easy because numbers are laid out in little-endian 3235*44d4804dSStefan Eßer // order. 3236252884aeSStefan Eßer for (ptr = n->num, i = 0; val; ++i, val /= BC_BASE_POW) 3237252884aeSStefan Eßer ptr[i] = val % BC_BASE_POW; 3238252884aeSStefan Eßer 3239252884aeSStefan Eßer n->len = i; 3240252884aeSStefan Eßer } 3241252884aeSStefan Eßer 3242*44d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 3243*44d4804dSStefan Eßer 3244252884aeSStefan Eßer void bc_num_rng(const BcNum *restrict n, BcRNG *rng) { 3245252884aeSStefan Eßer 324650696a6eSStefan Eßer BcNum temp, temp2, intn, frac; 3247252884aeSStefan Eßer BcRand state1, state2, inc1, inc2; 324850696a6eSStefan Eßer size_t nrdx = BC_NUM_RDX_VAL(n); 3249252884aeSStefan Eßer 3250*44d4804dSStefan Eßer // This function holds the secret of how I interpret a seed number for the 3251*44d4804dSStefan Eßer // PRNG. Well, it's actually in the development manual 3252*44d4804dSStefan Eßer // (manuals/development.md#pseudo-random-number-generator), so look there 3253*44d4804dSStefan Eßer // before you try to understand this. 3254*44d4804dSStefan Eßer 3255252884aeSStefan Eßer BC_SIG_LOCK; 3256252884aeSStefan Eßer 3257252884aeSStefan Eßer bc_num_init(&temp, n->len); 3258252884aeSStefan Eßer bc_num_init(&temp2, n->len); 325950696a6eSStefan Eßer bc_num_init(&frac, nrdx); 3260252884aeSStefan Eßer bc_num_init(&intn, bc_num_int(n)); 3261252884aeSStefan Eßer 3262252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3263252884aeSStefan Eßer 3264252884aeSStefan Eßer BC_SIG_UNLOCK; 3265252884aeSStefan Eßer 326650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(vm.max)); 3267252884aeSStefan Eßer 326850696a6eSStefan Eßer memcpy(frac.num, n->num, BC_NUM_SIZE(nrdx)); 326950696a6eSStefan Eßer frac.len = nrdx; 327050696a6eSStefan Eßer BC_NUM_RDX_SET_NP(frac, nrdx); 3271252884aeSStefan Eßer frac.scale = n->scale; 3272252884aeSStefan Eßer 327350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(frac)); 327450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(vm.max2)); 327550696a6eSStefan Eßer 3276*44d4804dSStefan Eßer // Multiply the fraction and truncate so that it's an integer. The 3277*44d4804dSStefan Eßer // truncation is what clamps it, by the way. 327850696a6eSStefan Eßer bc_num_mul(&frac, &vm.max2, &temp, 0); 3279252884aeSStefan Eßer bc_num_truncate(&temp, temp.scale); 3280252884aeSStefan Eßer bc_num_copy(&frac, &temp); 3281252884aeSStefan Eßer 3282*44d4804dSStefan Eßer // Get the integer. 328350696a6eSStefan Eßer memcpy(intn.num, n->num + nrdx, BC_NUM_SIZE(bc_num_int(n))); 3284252884aeSStefan Eßer intn.len = bc_num_int(n); 3285252884aeSStefan Eßer 3286252884aeSStefan Eßer // This assert is here because it has to be true. It is also here to justify 3287*44d4804dSStefan Eßer // some optimizations. 3288252884aeSStefan Eßer assert(BC_NUM_NONZERO(&vm.max)); 3289252884aeSStefan Eßer 3290*44d4804dSStefan Eßer // If there *was* a fractional part... 3291252884aeSStefan Eßer if (BC_NUM_NONZERO(&frac)) { 3292252884aeSStefan Eßer 3293*44d4804dSStefan Eßer // This divmod splits frac into the two state parts. 3294252884aeSStefan Eßer bc_num_divmod(&frac, &vm.max, &temp, &temp2, 0); 3295252884aeSStefan Eßer 3296252884aeSStefan Eßer // frac is guaranteed to be smaller than vm.max * vm.max (pow). 3297252884aeSStefan Eßer // This means that when dividing frac by vm.max, as above, the 3298252884aeSStefan Eßer // quotient and remainder are both guaranteed to be less than vm.max, 3299252884aeSStefan Eßer // which means we can use bc_num_bigdig2() here and not worry about 3300252884aeSStefan Eßer // overflow. 3301*44d4804dSStefan Eßer state1 = (BcRand) bc_num_bigdig2(&temp2); 3302*44d4804dSStefan Eßer state2 = (BcRand) bc_num_bigdig2(&temp); 3303252884aeSStefan Eßer } 3304252884aeSStefan Eßer else state1 = state2 = 0; 3305252884aeSStefan Eßer 3306*44d4804dSStefan Eßer // If there *was* an integer part... 3307252884aeSStefan Eßer if (BC_NUM_NONZERO(&intn)) { 3308252884aeSStefan Eßer 3309*44d4804dSStefan Eßer // This divmod splits intn into the two inc parts. 3310252884aeSStefan Eßer bc_num_divmod(&intn, &vm.max, &temp, &temp2, 0); 3311252884aeSStefan Eßer 3312252884aeSStefan Eßer // Because temp2 is the mod of vm.max, from above, it is guaranteed 3313252884aeSStefan Eßer // to be small enough to use bc_num_bigdig2(). 3314*44d4804dSStefan Eßer inc1 = (BcRand) bc_num_bigdig2(&temp2); 3315252884aeSStefan Eßer 3316*44d4804dSStefan Eßer // Clamp the second inc part. 3317252884aeSStefan Eßer if (bc_num_cmp(&temp, &vm.max) >= 0) { 3318252884aeSStefan Eßer bc_num_copy(&temp2, &temp); 3319252884aeSStefan Eßer bc_num_mod(&temp2, &vm.max, &temp, 0); 3320252884aeSStefan Eßer } 3321252884aeSStefan Eßer 3322252884aeSStefan Eßer // The if statement above ensures that temp is less than vm.max, which 3323252884aeSStefan Eßer // means that we can use bc_num_bigdig2() here. 3324*44d4804dSStefan Eßer inc2 = (BcRand) bc_num_bigdig2(&temp); 3325252884aeSStefan Eßer } 3326252884aeSStefan Eßer else inc1 = inc2 = 0; 3327252884aeSStefan Eßer 3328252884aeSStefan Eßer bc_rand_seed(rng, state1, state2, inc1, inc2); 3329252884aeSStefan Eßer 3330252884aeSStefan Eßer err: 3331252884aeSStefan Eßer BC_SIG_MAYLOCK; 3332252884aeSStefan Eßer bc_num_free(&intn); 3333252884aeSStefan Eßer bc_num_free(&frac); 3334252884aeSStefan Eßer bc_num_free(&temp2); 3335252884aeSStefan Eßer bc_num_free(&temp); 3336252884aeSStefan Eßer BC_LONGJMP_CONT; 3337252884aeSStefan Eßer } 3338252884aeSStefan Eßer 3339252884aeSStefan Eßer void bc_num_createFromRNG(BcNum *restrict n, BcRNG *rng) { 3340252884aeSStefan Eßer 3341252884aeSStefan Eßer BcRand s1, s2, i1, i2; 334250696a6eSStefan Eßer BcNum conv, temp1, temp2, temp3; 3343252884aeSStefan Eßer BcDig temp1_num[BC_RAND_NUM_SIZE], temp2_num[BC_RAND_NUM_SIZE]; 3344252884aeSStefan Eßer BcDig conv_num[BC_NUM_BIGDIG_LOG10]; 3345252884aeSStefan Eßer 3346252884aeSStefan Eßer BC_SIG_LOCK; 3347252884aeSStefan Eßer 3348252884aeSStefan Eßer bc_num_init(&temp3, 2 * BC_RAND_NUM_SIZE); 3349252884aeSStefan Eßer 3350252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3351252884aeSStefan Eßer 3352252884aeSStefan Eßer BC_SIG_UNLOCK; 3353252884aeSStefan Eßer 3354252884aeSStefan Eßer bc_num_setup(&temp1, temp1_num, sizeof(temp1_num) / sizeof(BcDig)); 3355252884aeSStefan Eßer bc_num_setup(&temp2, temp2_num, sizeof(temp2_num) / sizeof(BcDig)); 3356252884aeSStefan Eßer bc_num_setup(&conv, conv_num, sizeof(conv_num) / sizeof(BcDig)); 3357252884aeSStefan Eßer 3358252884aeSStefan Eßer // This assert is here because it has to be true. It is also here to justify 3359*44d4804dSStefan Eßer // the assumption that vm.max is not zero. 3360252884aeSStefan Eßer assert(BC_NUM_NONZERO(&vm.max)); 3361252884aeSStefan Eßer 3362*44d4804dSStefan Eßer // Because this is true, we can just ignore math errors that would happen 3363*44d4804dSStefan Eßer // otherwise. 336450696a6eSStefan Eßer assert(BC_NUM_NONZERO(&vm.max2)); 3365252884aeSStefan Eßer 3366252884aeSStefan Eßer bc_rand_getRands(rng, &s1, &s2, &i1, &i2); 3367252884aeSStefan Eßer 3368*44d4804dSStefan Eßer // Put the second piece of state into a number. 3369252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) s2); 3370252884aeSStefan Eßer 337150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(conv)); 337250696a6eSStefan Eßer 3373*44d4804dSStefan Eßer // Multiply by max to make room for the first piece of state. 3374252884aeSStefan Eßer bc_num_mul(&conv, &vm.max, &temp1, 0); 3375252884aeSStefan Eßer 3376*44d4804dSStefan Eßer // Add in the first piece of state. 3377252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) s1); 3378252884aeSStefan Eßer bc_num_add(&conv, &temp1, &temp2, 0); 3379252884aeSStefan Eßer 3380*44d4804dSStefan Eßer // Divide to make it an entirely fractional part. 338150696a6eSStefan Eßer bc_num_div(&temp2, &vm.max2, &temp3, BC_RAND_STATE_BITS); 3382252884aeSStefan Eßer 3383*44d4804dSStefan Eßer // Now start on the increment parts. It's the same process without the 3384*44d4804dSStefan Eßer // divide, so put the second piece of increment into a number. 3385252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) i2); 3386252884aeSStefan Eßer 338750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(conv)); 338850696a6eSStefan Eßer 3389*44d4804dSStefan Eßer // Multiply by max to make room for the first piece of increment. 3390252884aeSStefan Eßer bc_num_mul(&conv, &vm.max, &temp1, 0); 3391252884aeSStefan Eßer 3392*44d4804dSStefan Eßer // Add in the first piece of increment. 3393252884aeSStefan Eßer bc_num_bigdig2num(&conv, (BcBigDig) i1); 3394252884aeSStefan Eßer bc_num_add(&conv, &temp1, &temp2, 0); 3395252884aeSStefan Eßer 3396*44d4804dSStefan Eßer // Now add the two together. 3397252884aeSStefan Eßer bc_num_add(&temp2, &temp3, n, 0); 3398252884aeSStefan Eßer 339950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(n)); 340050696a6eSStefan Eßer 3401252884aeSStefan Eßer err: 3402252884aeSStefan Eßer BC_SIG_MAYLOCK; 3403252884aeSStefan Eßer bc_num_free(&temp3); 3404252884aeSStefan Eßer BC_LONGJMP_CONT; 3405252884aeSStefan Eßer } 3406252884aeSStefan Eßer 3407*44d4804dSStefan Eßer void bc_num_irand(BcNum *restrict a, BcNum *restrict b, BcRNG *restrict rng) { 3408*44d4804dSStefan Eßer 3409*44d4804dSStefan Eßer BcNum atemp; 3410*44d4804dSStefan Eßer size_t i, len; 3411252884aeSStefan Eßer 3412252884aeSStefan Eßer assert(a != b); 3413252884aeSStefan Eßer 3414*44d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(a))) bc_err(BC_ERR_MATH_NEGATIVE); 3415*44d4804dSStefan Eßer 3416*44d4804dSStefan Eßer // If either of these are true, then the numbers are integers. 3417252884aeSStefan Eßer if (BC_NUM_ZERO(a) || BC_NUM_ONE(a)) return; 3418252884aeSStefan Eßer 3419*44d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(a, &atemp))) bc_err(BC_ERR_MATH_NON_INTEGER); 3420252884aeSStefan Eßer 3421*44d4804dSStefan Eßer assert(atemp.len); 3422252884aeSStefan Eßer 3423*44d4804dSStefan Eßer len = atemp.len - 1; 3424252884aeSStefan Eßer 3425*44d4804dSStefan Eßer // Just generate a random number for each limb. 3426*44d4804dSStefan Eßer for (i = 0; i < len; ++i) 3427*44d4804dSStefan Eßer b->num[i] = (BcDig) bc_rand_bounded(rng, BC_BASE_POW); 3428252884aeSStefan Eßer 3429*44d4804dSStefan Eßer // Do the last digit explicitly because the bound must be right. But only 3430*44d4804dSStefan Eßer // do it if the limb does not equal 1. If it does, we have already hit the 3431*44d4804dSStefan Eßer // limit. 3432*44d4804dSStefan Eßer if (atemp.num[i] != 1) { 3433*44d4804dSStefan Eßer b->num[i] = (BcDig) bc_rand_bounded(rng, (BcRand) atemp.num[i]); 3434*44d4804dSStefan Eßer b->len = atemp.len; 3435252884aeSStefan Eßer } 3436*44d4804dSStefan Eßer // We want 1 less len in the case where we skip the last limb. 3437*44d4804dSStefan Eßer else b->len = len; 3438252884aeSStefan Eßer 3439252884aeSStefan Eßer bc_num_clean(b); 3440252884aeSStefan Eßer 344150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3442252884aeSStefan Eßer } 3443*44d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 3444252884aeSStefan Eßer 3445252884aeSStefan Eßer size_t bc_num_addReq(const BcNum *a, const BcNum *b, size_t scale) { 3446252884aeSStefan Eßer 3447252884aeSStefan Eßer size_t aint, bint, ardx, brdx; 3448252884aeSStefan Eßer 3449*44d4804dSStefan Eßer // Addition and subtraction require the max of the length of the two numbers 3450*44d4804dSStefan Eßer // plus 1. 3451*44d4804dSStefan Eßer 3452252884aeSStefan Eßer BC_UNUSED(scale); 3453252884aeSStefan Eßer 345450696a6eSStefan Eßer ardx = BC_NUM_RDX_VAL(a); 3455252884aeSStefan Eßer aint = bc_num_int(a); 3456252884aeSStefan Eßer assert(aint <= a->len && ardx <= a->len); 3457252884aeSStefan Eßer 345850696a6eSStefan Eßer brdx = BC_NUM_RDX_VAL(b); 3459252884aeSStefan Eßer bint = bc_num_int(b); 3460252884aeSStefan Eßer assert(bint <= b->len && brdx <= b->len); 3461252884aeSStefan Eßer 3462252884aeSStefan Eßer ardx = BC_MAX(ardx, brdx); 3463252884aeSStefan Eßer aint = BC_MAX(aint, bint); 3464252884aeSStefan Eßer 3465252884aeSStefan Eßer return bc_vm_growSize(bc_vm_growSize(ardx, aint), 1); 3466252884aeSStefan Eßer } 3467252884aeSStefan Eßer 3468252884aeSStefan Eßer size_t bc_num_mulReq(const BcNum *a, const BcNum *b, size_t scale) { 3469*44d4804dSStefan Eßer 3470252884aeSStefan Eßer size_t max, rdx; 3471*44d4804dSStefan Eßer 3472*44d4804dSStefan Eßer // Multiplication requires the sum of the lengths of the numbers. 3473*44d4804dSStefan Eßer 347450696a6eSStefan Eßer rdx = bc_vm_growSize(BC_NUM_RDX_VAL(a), BC_NUM_RDX_VAL(b)); 3475*44d4804dSStefan Eßer 3476252884aeSStefan Eßer max = BC_NUM_RDX(scale); 3477*44d4804dSStefan Eßer 3478252884aeSStefan Eßer max = bc_vm_growSize(BC_MAX(max, rdx), 1); 3479252884aeSStefan Eßer rdx = bc_vm_growSize(bc_vm_growSize(bc_num_int(a), bc_num_int(b)), max); 3480*44d4804dSStefan Eßer 3481252884aeSStefan Eßer return rdx; 3482252884aeSStefan Eßer } 3483252884aeSStefan Eßer 348450696a6eSStefan Eßer size_t bc_num_divReq(const BcNum *a, const BcNum *b, size_t scale) { 3485*44d4804dSStefan Eßer 348650696a6eSStefan Eßer size_t max, rdx; 3487*44d4804dSStefan Eßer 3488*44d4804dSStefan Eßer // Division requires the length of the dividend plus the scale. 3489*44d4804dSStefan Eßer 349050696a6eSStefan Eßer rdx = bc_vm_growSize(BC_NUM_RDX_VAL(a), BC_NUM_RDX_VAL(b)); 3491*44d4804dSStefan Eßer 349250696a6eSStefan Eßer max = BC_NUM_RDX(scale); 3493*44d4804dSStefan Eßer 349450696a6eSStefan Eßer max = bc_vm_growSize(BC_MAX(max, rdx), 1); 349550696a6eSStefan Eßer rdx = bc_vm_growSize(bc_num_int(a), max); 3496*44d4804dSStefan Eßer 349750696a6eSStefan Eßer return rdx; 349850696a6eSStefan Eßer } 349950696a6eSStefan Eßer 3500252884aeSStefan Eßer size_t bc_num_powReq(const BcNum *a, const BcNum *b, size_t scale) { 3501252884aeSStefan Eßer BC_UNUSED(scale); 3502252884aeSStefan Eßer return bc_vm_growSize(bc_vm_growSize(a->len, b->len), 1); 3503252884aeSStefan Eßer } 3504252884aeSStefan Eßer 3505252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 3506252884aeSStefan Eßer size_t bc_num_placesReq(const BcNum *a, const BcNum *b, size_t scale) { 3507252884aeSStefan Eßer BC_UNUSED(scale); 350850696a6eSStefan Eßer return a->len + b->len - BC_NUM_RDX_VAL(a) - BC_NUM_RDX_VAL(b); 3509252884aeSStefan Eßer } 3510252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 3511252884aeSStefan Eßer 3512252884aeSStefan Eßer void bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 351350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 351450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3515252884aeSStefan Eßer bc_num_binary(a, b, c, false, bc_num_as, bc_num_addReq(a, b, scale)); 3516252884aeSStefan Eßer } 3517252884aeSStefan Eßer 3518252884aeSStefan Eßer void bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 351950696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 352050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3521252884aeSStefan Eßer bc_num_binary(a, b, c, true, bc_num_as, bc_num_addReq(a, b, scale)); 3522252884aeSStefan Eßer } 3523252884aeSStefan Eßer 3524252884aeSStefan Eßer void bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 352550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 352650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3527252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_m, bc_num_mulReq(a, b, scale)); 3528252884aeSStefan Eßer } 3529252884aeSStefan Eßer 3530252884aeSStefan Eßer void bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 353150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 353250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 353350696a6eSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_d, bc_num_divReq(a, b, scale)); 3534252884aeSStefan Eßer } 3535252884aeSStefan Eßer 3536252884aeSStefan Eßer void bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 353750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 353850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 353950696a6eSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_rem, bc_num_divReq(a, b, scale)); 3540252884aeSStefan Eßer } 3541252884aeSStefan Eßer 3542252884aeSStefan Eßer void bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 354350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 354450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3545252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_p, bc_num_powReq(a, b, scale)); 3546252884aeSStefan Eßer } 3547252884aeSStefan Eßer 3548252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 3549252884aeSStefan Eßer void bc_num_places(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 355050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 355150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3552252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_place, bc_num_placesReq(a, b, scale)); 3553252884aeSStefan Eßer } 3554252884aeSStefan Eßer 3555252884aeSStefan Eßer void bc_num_lshift(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 355650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 355750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3558252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_left, bc_num_placesReq(a, b, scale)); 3559252884aeSStefan Eßer } 3560252884aeSStefan Eßer 3561252884aeSStefan Eßer void bc_num_rshift(BcNum *a, BcNum *b, BcNum *c, size_t scale) { 356250696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(a)); 356350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 3564252884aeSStefan Eßer bc_num_binary(a, b, c, scale, bc_num_right, bc_num_placesReq(a, b, scale)); 3565252884aeSStefan Eßer } 3566252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 3567252884aeSStefan Eßer 3568252884aeSStefan Eßer void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale) { 3569252884aeSStefan Eßer 3570252884aeSStefan Eßer BcNum num1, num2, half, f, fprime, *x0, *x1, *temp; 357110328f8bSStefan Eßer size_t pow, len, rdx, req, resscale; 3572252884aeSStefan Eßer BcDig half_digs[1]; 3573252884aeSStefan Eßer 3574252884aeSStefan Eßer assert(a != NULL && b != NULL && a != b); 3575252884aeSStefan Eßer 3576*44d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(a))) bc_err(BC_ERR_MATH_NEGATIVE); 3577252884aeSStefan Eßer 3578*44d4804dSStefan Eßer // We want to calculate to a's scale if it is bigger so that the result will 3579*44d4804dSStefan Eßer // truncate properly. 3580252884aeSStefan Eßer if (a->scale > scale) scale = a->scale; 3581252884aeSStefan Eßer 3582*44d4804dSStefan Eßer // Set parameters for the result. 3583252884aeSStefan Eßer len = bc_vm_growSize(bc_num_intDigits(a), 1); 3584252884aeSStefan Eßer rdx = BC_NUM_RDX(scale); 3585*44d4804dSStefan Eßer 3586*44d4804dSStefan Eßer // Square root needs half of the length of the parameter. 358750696a6eSStefan Eßer req = bc_vm_growSize(BC_MAX(rdx, BC_NUM_RDX_VAL(a)), len >> 1); 3588252884aeSStefan Eßer 3589252884aeSStefan Eßer BC_SIG_LOCK; 3590252884aeSStefan Eßer 3591*44d4804dSStefan Eßer // Unlike the binary operators, this function is the only single parameter 3592*44d4804dSStefan Eßer // function and is expected to initialize the result. This means that it 3593*44d4804dSStefan Eßer // expects that b is *NOT* preallocated. We allocate it here. 3594252884aeSStefan Eßer bc_num_init(b, bc_vm_growSize(req, 1)); 3595252884aeSStefan Eßer 3596252884aeSStefan Eßer BC_SIG_UNLOCK; 3597252884aeSStefan Eßer 359850696a6eSStefan Eßer assert(a != NULL && b != NULL && a != b); 359950696a6eSStefan Eßer assert(a->num != NULL && b->num != NULL); 360050696a6eSStefan Eßer 3601*44d4804dSStefan Eßer // Easy case. 3602252884aeSStefan Eßer if (BC_NUM_ZERO(a)) { 3603252884aeSStefan Eßer bc_num_setToZero(b, scale); 3604252884aeSStefan Eßer return; 3605252884aeSStefan Eßer } 3606*44d4804dSStefan Eßer 3607*44d4804dSStefan Eßer // Another easy case. 3608252884aeSStefan Eßer if (BC_NUM_ONE(a)) { 3609252884aeSStefan Eßer bc_num_one(b); 3610252884aeSStefan Eßer bc_num_extend(b, scale); 3611252884aeSStefan Eßer return; 3612252884aeSStefan Eßer } 3613252884aeSStefan Eßer 3614*44d4804dSStefan Eßer // Set the parameters again. 3615252884aeSStefan Eßer rdx = BC_NUM_RDX(scale); 361650696a6eSStefan Eßer rdx = BC_MAX(rdx, BC_NUM_RDX_VAL(a)); 3617252884aeSStefan Eßer len = bc_vm_growSize(a->len, rdx); 3618252884aeSStefan Eßer 3619252884aeSStefan Eßer BC_SIG_LOCK; 3620252884aeSStefan Eßer 3621252884aeSStefan Eßer bc_num_init(&num1, len); 3622252884aeSStefan Eßer bc_num_init(&num2, len); 3623252884aeSStefan Eßer bc_num_setup(&half, half_digs, sizeof(half_digs) / sizeof(BcDig)); 3624252884aeSStefan Eßer 3625*44d4804dSStefan Eßer // There is a division by two in the formula. We setup a number that's 1/2 3626*44d4804dSStefan Eßer // so that we can use multiplication instead of heavy division. 3627252884aeSStefan Eßer bc_num_one(&half); 3628252884aeSStefan Eßer half.num[0] = BC_BASE_POW / 2; 3629252884aeSStefan Eßer half.len = 1; 363050696a6eSStefan Eßer BC_NUM_RDX_SET_NP(half, 1); 3631252884aeSStefan Eßer half.scale = 1; 3632252884aeSStefan Eßer 3633252884aeSStefan Eßer bc_num_init(&f, len); 3634252884aeSStefan Eßer bc_num_init(&fprime, len); 3635252884aeSStefan Eßer 3636252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3637252884aeSStefan Eßer 3638252884aeSStefan Eßer BC_SIG_UNLOCK; 3639252884aeSStefan Eßer 3640*44d4804dSStefan Eßer // Pointers for easy switching. 3641252884aeSStefan Eßer x0 = &num1; 3642252884aeSStefan Eßer x1 = &num2; 3643252884aeSStefan Eßer 3644*44d4804dSStefan Eßer // Start with 1. 3645252884aeSStefan Eßer bc_num_one(x0); 3646*44d4804dSStefan Eßer 3647*44d4804dSStefan Eßer // The power of the operand is needed for the estimate. 3648252884aeSStefan Eßer pow = bc_num_intDigits(a); 3649252884aeSStefan Eßer 3650*44d4804dSStefan Eßer // The code in this if statement calculates the initial estimate. First, if 3651*44d4804dSStefan Eßer // a is less than 0, then 0 is a good estimate. Otherwise, we want something 3652*44d4804dSStefan Eßer // in the same ballpark. That ballpark is pow. 3653252884aeSStefan Eßer if (pow) { 3654252884aeSStefan Eßer 3655*44d4804dSStefan Eßer // An odd number is served by starting with 2^((pow-1)/2), and an even 3656*44d4804dSStefan Eßer // number is served by starting with 6^((pow-2)/2). Why? Because math. 3657252884aeSStefan Eßer if (pow & 1) x0->num[0] = 2; 3658252884aeSStefan Eßer else x0->num[0] = 6; 3659252884aeSStefan Eßer 3660252884aeSStefan Eßer pow -= 2 - (pow & 1); 3661252884aeSStefan Eßer bc_num_shiftLeft(x0, pow / 2); 3662252884aeSStefan Eßer } 3663252884aeSStefan Eßer 366450696a6eSStefan Eßer // I can set the rdx here directly because neg should be false. 366510328f8bSStefan Eßer x0->scale = x0->rdx = 0; 3666252884aeSStefan Eßer resscale = (scale + BC_BASE_DIGS) + 2; 3667252884aeSStefan Eßer 3668*44d4804dSStefan Eßer // This is the calculation loop. This compare goes to 0 eventually as the 3669*44d4804dSStefan Eßer // difference between the two numbers gets smaller than resscale. 3670252884aeSStefan Eßer while (bc_num_cmp(x1, x0)) { 3671252884aeSStefan Eßer 3672252884aeSStefan Eßer assert(BC_NUM_NONZERO(x0)); 3673252884aeSStefan Eßer 3674*44d4804dSStefan Eßer // This loop directly corresponds to the iteration in Newton's method. 3675*44d4804dSStefan Eßer // If you know the formula, this loop makes sense. Go study the formula. 3676*44d4804dSStefan Eßer 3677252884aeSStefan Eßer bc_num_div(a, x0, &f, resscale); 3678252884aeSStefan Eßer bc_num_add(x0, &f, &fprime, resscale); 367950696a6eSStefan Eßer 368050696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(fprime)); 368150696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(half)); 368250696a6eSStefan Eßer 3683252884aeSStefan Eßer bc_num_mul(&fprime, &half, x1, resscale); 3684252884aeSStefan Eßer 3685*44d4804dSStefan Eßer // Switch. 3686252884aeSStefan Eßer temp = x0; 3687252884aeSStefan Eßer x0 = x1; 3688252884aeSStefan Eßer x1 = temp; 3689252884aeSStefan Eßer } 3690252884aeSStefan Eßer 3691*44d4804dSStefan Eßer // Copy to the result and truncate. 3692252884aeSStefan Eßer bc_num_copy(b, x0); 3693252884aeSStefan Eßer if (b->scale > scale) bc_num_truncate(b, b->scale - scale); 3694252884aeSStefan Eßer 369550696a6eSStefan Eßer assert(!BC_NUM_NEG(b) || BC_NUM_NONZERO(b)); 369650696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(b)); 369750696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(b) <= b->len || !b->len); 369850696a6eSStefan Eßer assert(!b->len || b->num[b->len - 1] || BC_NUM_RDX_VAL(b) == b->len); 3699252884aeSStefan Eßer 3700252884aeSStefan Eßer err: 3701252884aeSStefan Eßer BC_SIG_MAYLOCK; 3702252884aeSStefan Eßer bc_num_free(&fprime); 3703252884aeSStefan Eßer bc_num_free(&f); 3704252884aeSStefan Eßer bc_num_free(&num2); 3705252884aeSStefan Eßer bc_num_free(&num1); 3706252884aeSStefan Eßer BC_LONGJMP_CONT; 3707252884aeSStefan Eßer } 3708252884aeSStefan Eßer 3709252884aeSStefan Eßer void bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) { 3710252884aeSStefan Eßer 3711252884aeSStefan Eßer size_t ts, len; 371250696a6eSStefan Eßer BcNum *ptr_a, num2; 371350696a6eSStefan Eßer bool init = false; 3714252884aeSStefan Eßer 3715*44d4804dSStefan Eßer // The bulk of this function is just doing what bc_num_binary() does for the 3716*44d4804dSStefan Eßer // binary operators. However, it assumes that only c and a can be equal. 3717*44d4804dSStefan Eßer 3718*44d4804dSStefan Eßer // Set up the parameters. 3719252884aeSStefan Eßer ts = BC_MAX(scale + b->scale, a->scale); 3720252884aeSStefan Eßer len = bc_num_mulReq(a, b, ts); 3721252884aeSStefan Eßer 3722252884aeSStefan Eßer assert(a != NULL && b != NULL && c != NULL && d != NULL); 3723252884aeSStefan Eßer assert(c != d && a != d && b != d && b != c); 3724252884aeSStefan Eßer 3725*44d4804dSStefan Eßer // Initialize or expand as necessary. 3726252884aeSStefan Eßer if (c == a) { 3727252884aeSStefan Eßer 3728252884aeSStefan Eßer memcpy(&num2, c, sizeof(BcNum)); 3729252884aeSStefan Eßer ptr_a = &num2; 3730252884aeSStefan Eßer 3731252884aeSStefan Eßer BC_SIG_LOCK; 3732252884aeSStefan Eßer 3733252884aeSStefan Eßer bc_num_init(c, len); 3734252884aeSStefan Eßer 3735252884aeSStefan Eßer init = true; 3736252884aeSStefan Eßer 3737252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3738252884aeSStefan Eßer 3739252884aeSStefan Eßer BC_SIG_UNLOCK; 3740252884aeSStefan Eßer } 3741252884aeSStefan Eßer else { 3742252884aeSStefan Eßer ptr_a = a; 3743252884aeSStefan Eßer bc_num_expand(c, len); 3744252884aeSStefan Eßer } 3745252884aeSStefan Eßer 3746*44d4804dSStefan Eßer // Do the quick version if possible. 374750696a6eSStefan Eßer if (BC_NUM_NONZERO(a) && !BC_NUM_RDX_VAL(a) && 374850696a6eSStefan Eßer !BC_NUM_RDX_VAL(b) && b->len == 1 && !scale) 374950696a6eSStefan Eßer { 3750252884aeSStefan Eßer BcBigDig rem; 3751252884aeSStefan Eßer 3752252884aeSStefan Eßer bc_num_divArray(ptr_a, (BcBigDig) b->num[0], c, &rem); 3753252884aeSStefan Eßer 3754252884aeSStefan Eßer assert(rem < BC_BASE_POW); 3755252884aeSStefan Eßer 3756252884aeSStefan Eßer d->num[0] = (BcDig) rem; 3757252884aeSStefan Eßer d->len = (rem != 0); 3758252884aeSStefan Eßer } 3759*44d4804dSStefan Eßer // Do the slow method. 3760252884aeSStefan Eßer else bc_num_r(ptr_a, b, c, d, scale, ts); 3761252884aeSStefan Eßer 376250696a6eSStefan Eßer assert(!BC_NUM_NEG(c) || BC_NUM_NONZERO(c)); 376350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(c)); 376450696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(c) <= c->len || !c->len); 376550696a6eSStefan Eßer assert(!c->len || c->num[c->len - 1] || BC_NUM_RDX_VAL(c) == c->len); 376650696a6eSStefan Eßer assert(!BC_NUM_NEG(d) || BC_NUM_NONZERO(d)); 376750696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(d)); 376850696a6eSStefan Eßer assert(BC_NUM_RDX_VAL(d) <= d->len || !d->len); 376950696a6eSStefan Eßer assert(!d->len || d->num[d->len - 1] || BC_NUM_RDX_VAL(d) == d->len); 3770252884aeSStefan Eßer 3771252884aeSStefan Eßer err: 3772*44d4804dSStefan Eßer // Only cleanup if we initialized. 3773252884aeSStefan Eßer if (init) { 3774252884aeSStefan Eßer BC_SIG_MAYLOCK; 3775252884aeSStefan Eßer bc_num_free(&num2); 3776252884aeSStefan Eßer BC_LONGJMP_CONT; 3777252884aeSStefan Eßer } 3778252884aeSStefan Eßer } 3779252884aeSStefan Eßer 3780252884aeSStefan Eßer void bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d) { 3781252884aeSStefan Eßer 3782*44d4804dSStefan Eßer BcNum base, exp, two, temp, atemp, btemp, ctemp; 3783252884aeSStefan Eßer BcDig two_digs[2]; 3784252884aeSStefan Eßer 3785252884aeSStefan Eßer assert(a != NULL && b != NULL && c != NULL && d != NULL); 3786252884aeSStefan Eßer assert(a != d && b != d && c != d); 3787252884aeSStefan Eßer 3788*44d4804dSStefan Eßer if (BC_ERR(BC_NUM_ZERO(c))) bc_err(BC_ERR_MATH_DIVIDE_BY_ZERO); 3789252884aeSStefan Eßer 3790*44d4804dSStefan Eßer if (BC_ERR(BC_NUM_NEG(b))) bc_err(BC_ERR_MATH_NEGATIVE); 3791*44d4804dSStefan Eßer 3792*44d4804dSStefan Eßer #ifndef NDEBUG 3793*44d4804dSStefan Eßer // This is entirely for quieting a useless scan-build error. 3794*44d4804dSStefan Eßer btemp.len = 0; 3795*44d4804dSStefan Eßer ctemp.len = 0; 3796*44d4804dSStefan Eßer #endif // NDEBUG 3797*44d4804dSStefan Eßer 3798*44d4804dSStefan Eßer // Eliminate fractional parts that are zero or error if they are not zero. 3799*44d4804dSStefan Eßer if (BC_ERR(bc_num_nonInt(a, &atemp) || bc_num_nonInt(b, &btemp) || 3800*44d4804dSStefan Eßer bc_num_nonInt(c, &ctemp))) 3801*44d4804dSStefan Eßer { 3802*44d4804dSStefan Eßer bc_err(BC_ERR_MATH_NON_INTEGER); 3803*44d4804dSStefan Eßer } 3804*44d4804dSStefan Eßer 3805*44d4804dSStefan Eßer bc_num_expand(d, ctemp.len); 3806252884aeSStefan Eßer 3807252884aeSStefan Eßer BC_SIG_LOCK; 3808252884aeSStefan Eßer 3809*44d4804dSStefan Eßer bc_num_init(&base, ctemp.len); 3810252884aeSStefan Eßer bc_num_setup(&two, two_digs, sizeof(two_digs) / sizeof(BcDig)); 3811*44d4804dSStefan Eßer bc_num_init(&temp, btemp.len + 1); 3812*44d4804dSStefan Eßer bc_num_createCopy(&exp, &btemp); 3813252884aeSStefan Eßer 3814252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 3815252884aeSStefan Eßer 3816252884aeSStefan Eßer BC_SIG_UNLOCK; 3817252884aeSStefan Eßer 3818252884aeSStefan Eßer bc_num_one(&two); 3819252884aeSStefan Eßer two.num[0] = 2; 3820252884aeSStefan Eßer bc_num_one(d); 3821252884aeSStefan Eßer 3822252884aeSStefan Eßer // We already checked for 0. 3823*44d4804dSStefan Eßer bc_num_rem(&atemp, &ctemp, &base, 0); 3824252884aeSStefan Eßer 3825*44d4804dSStefan Eßer // If you know the algorithm I used, the memory-efficient method, then this 3826*44d4804dSStefan Eßer // loop should be self-explanatory because it is the calculation loop. 3827252884aeSStefan Eßer while (BC_NUM_NONZERO(&exp)) { 3828252884aeSStefan Eßer 3829252884aeSStefan Eßer // Num two cannot be 0, so no errors. 3830252884aeSStefan Eßer bc_num_divmod(&exp, &two, &exp, &temp, 0); 3831252884aeSStefan Eßer 383250696a6eSStefan Eßer if (BC_NUM_ONE(&temp) && !BC_NUM_NEG_NP(temp)) { 383350696a6eSStefan Eßer 383450696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(d)); 383550696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(base)); 3836252884aeSStefan Eßer 3837252884aeSStefan Eßer bc_num_mul(d, &base, &temp, 0); 3838252884aeSStefan Eßer 3839252884aeSStefan Eßer // We already checked for 0. 3840*44d4804dSStefan Eßer bc_num_rem(&temp, &ctemp, d, 0); 3841252884aeSStefan Eßer } 3842252884aeSStefan Eßer 384350696a6eSStefan Eßer assert(BC_NUM_RDX_VALID_NP(base)); 384450696a6eSStefan Eßer 3845252884aeSStefan Eßer bc_num_mul(&base, &base, &temp, 0); 3846252884aeSStefan Eßer 3847252884aeSStefan Eßer // We already checked for 0. 3848*44d4804dSStefan Eßer bc_num_rem(&temp, &ctemp, &base, 0); 3849252884aeSStefan Eßer } 3850252884aeSStefan Eßer 3851252884aeSStefan Eßer err: 3852252884aeSStefan Eßer BC_SIG_MAYLOCK; 3853252884aeSStefan Eßer bc_num_free(&exp); 3854252884aeSStefan Eßer bc_num_free(&temp); 3855252884aeSStefan Eßer bc_num_free(&base); 3856252884aeSStefan Eßer BC_LONGJMP_CONT; 385750696a6eSStefan Eßer assert(!BC_NUM_NEG(d) || d->len); 385850696a6eSStefan Eßer assert(BC_NUM_RDX_VALID(d)); 385950696a6eSStefan Eßer assert(!d->len || d->num[d->len - 1] || BC_NUM_RDX_VAL(d) == d->len); 3860252884aeSStefan Eßer } 3861252884aeSStefan Eßer 3862252884aeSStefan Eßer #if BC_DEBUG_CODE 3863252884aeSStefan Eßer void bc_num_printDebug(const BcNum *n, const char *name, bool emptyline) { 38647e5c51e5SStefan Eßer bc_file_puts(&vm.fout, bc_flush_none, name); 38657e5c51e5SStefan Eßer bc_file_puts(&vm.fout, bc_flush_none, ": "); 3866*44d4804dSStefan Eßer bc_num_printDecimal(n, true); 38677e5c51e5SStefan Eßer bc_file_putchar(&vm.fout, bc_flush_err, '\n'); 38687e5c51e5SStefan Eßer if (emptyline) bc_file_putchar(&vm.fout, bc_flush_err, '\n'); 3869252884aeSStefan Eßer vm.nchars = 0; 3870252884aeSStefan Eßer } 3871252884aeSStefan Eßer 3872252884aeSStefan Eßer void bc_num_printDigs(const BcDig *n, size_t len, bool emptyline) { 3873252884aeSStefan Eßer 3874252884aeSStefan Eßer size_t i; 3875252884aeSStefan Eßer 3876252884aeSStefan Eßer for (i = len - 1; i < len; --i) 3877252884aeSStefan Eßer bc_file_printf(&vm.fout, " %lu", (unsigned long) n[i]); 3878252884aeSStefan Eßer 38797e5c51e5SStefan Eßer bc_file_putchar(&vm.fout, bc_flush_err, '\n'); 38807e5c51e5SStefan Eßer if (emptyline) bc_file_putchar(&vm.fout, bc_flush_err, '\n'); 3881252884aeSStefan Eßer vm.nchars = 0; 3882252884aeSStefan Eßer } 3883252884aeSStefan Eßer 3884252884aeSStefan Eßer void bc_num_printWithDigs(const BcNum *n, const char *name, bool emptyline) { 38857e5c51e5SStefan Eßer bc_file_puts(&vm.fout, bc_flush_none, name); 3886252884aeSStefan Eßer bc_file_printf(&vm.fout, " len: %zu, rdx: %zu, scale: %zu\n", 388750696a6eSStefan Eßer name, n->len, BC_NUM_RDX_VAL(n), n->scale); 3888252884aeSStefan Eßer bc_num_printDigs(n->num, n->len, emptyline); 3889252884aeSStefan Eßer } 3890252884aeSStefan Eßer 3891252884aeSStefan Eßer void bc_num_dump(const char *varname, const BcNum *n) { 3892252884aeSStefan Eßer 3893252884aeSStefan Eßer ulong i, scale = n->scale; 3894252884aeSStefan Eßer 3895252884aeSStefan Eßer bc_file_printf(&vm.ferr, "\n%s = %s", varname, 389650696a6eSStefan Eßer n->len ? (BC_NUM_NEG(n) ? "-" : "+") : "0 "); 3897252884aeSStefan Eßer 3898252884aeSStefan Eßer for (i = n->len - 1; i < n->len; --i) { 3899252884aeSStefan Eßer 39007e5c51e5SStefan Eßer if (i + 1 == BC_NUM_RDX_VAL(n)) 39017e5c51e5SStefan Eßer bc_file_puts(&vm.ferr, bc_flush_none, ". "); 3902252884aeSStefan Eßer 390350696a6eSStefan Eßer if (scale / BC_BASE_DIGS != BC_NUM_RDX_VAL(n) - i - 1) 3904252884aeSStefan Eßer bc_file_printf(&vm.ferr, "%lu ", (unsigned long) n->num[i]); 3905252884aeSStefan Eßer else { 3906252884aeSStefan Eßer 3907252884aeSStefan Eßer int mod = scale % BC_BASE_DIGS; 3908252884aeSStefan Eßer int d = BC_BASE_DIGS - mod; 3909252884aeSStefan Eßer BcDig div; 3910252884aeSStefan Eßer 3911252884aeSStefan Eßer if (mod != 0) { 3912252884aeSStefan Eßer div = n->num[i] / ((BcDig) bc_num_pow10[(ulong) d]); 3913252884aeSStefan Eßer bc_file_printf(&vm.ferr, "%lu", (unsigned long) div); 3914252884aeSStefan Eßer } 3915252884aeSStefan Eßer 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 3921252884aeSStefan Eßer bc_file_printf(&vm.ferr, "(%zu | %zu.%zu / %zu) %lu\n", 392250696a6eSStefan Eßer n->scale, n->len, BC_NUM_RDX_VAL(n), n->cap, 3923252884aeSStefan Eßer (unsigned long) (void*) n->num); 39247e5c51e5SStefan Eßer 39257e5c51e5SStefan Eßer bc_file_flush(&vm.ferr, bc_flush_err); 3926252884aeSStefan Eßer } 3927252884aeSStefan Eßer #endif // BC_DEBUG_CODE 3928