Path: blob/main/Modules/_decimal/libmpdec/basearith.c
12 views
/*1* Copyright (c) 2008-2020 Stefan Krah. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/262728#include "mpdecimal.h"2930#include <assert.h>31#include <stdio.h>3233#include "basearith.h"34#include "constants.h"35#include "typearith.h"363738/*********************************************************************/39/* Calculations in base MPD_RADIX */40/*********************************************************************/414243/*44* Knuth, TAOCP, Volume 2, 4.3.1:45* w := sum of u (len m) and v (len n)46* n > 0 and m >= n47* The calling function has to handle a possible final carry.48*/49mpd_uint_t50_mpd_baseadd(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,51mpd_size_t m, mpd_size_t n)52{53mpd_uint_t s;54mpd_uint_t carry = 0;55mpd_size_t i;5657assert(n > 0 && m >= n);5859/* add n members of u and v */60for (i = 0; i < n; i++) {61s = u[i] + (v[i] + carry);62carry = (s < u[i]) | (s >= MPD_RADIX);63w[i] = carry ? s-MPD_RADIX : s;64}65/* if there is a carry, propagate it */66for (; carry && i < m; i++) {67s = u[i] + carry;68carry = (s == MPD_RADIX);69w[i] = carry ? 0 : s;70}71/* copy the rest of u */72for (; i < m; i++) {73w[i] = u[i];74}7576return carry;77}7879/*80* Add the contents of u to w. Carries are propagated further. The caller81* has to make sure that w is big enough.82*/83void84_mpd_baseaddto(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n)85{86mpd_uint_t s;87mpd_uint_t carry = 0;88mpd_size_t i;8990if (n == 0) return;9192/* add n members of u to w */93for (i = 0; i < n; i++) {94s = w[i] + (u[i] + carry);95carry = (s < w[i]) | (s >= MPD_RADIX);96w[i] = carry ? s-MPD_RADIX : s;97}98/* if there is a carry, propagate it */99for (; carry; i++) {100s = w[i] + carry;101carry = (s == MPD_RADIX);102w[i] = carry ? 0 : s;103}104}105106/*107* Add v to w (len m). The calling function has to handle a possible108* final carry. Assumption: m > 0.109*/110mpd_uint_t111_mpd_shortadd(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v)112{113mpd_uint_t s;114mpd_uint_t carry;115mpd_size_t i;116117assert(m > 0);118119/* add v to w */120s = w[0] + v;121carry = (s < v) | (s >= MPD_RADIX);122w[0] = carry ? s-MPD_RADIX : s;123124/* if there is a carry, propagate it */125for (i = 1; carry && i < m; i++) {126s = w[i] + carry;127carry = (s == MPD_RADIX);128w[i] = carry ? 0 : s;129}130131return carry;132}133134/* Increment u. The calling function has to handle a possible carry. */135mpd_uint_t136_mpd_baseincr(mpd_uint_t *u, mpd_size_t n)137{138mpd_uint_t s;139mpd_uint_t carry = 1;140mpd_size_t i;141142assert(n > 0);143144/* if there is a carry, propagate it */145for (i = 0; carry && i < n; i++) {146s = u[i] + carry;147carry = (s == MPD_RADIX);148u[i] = carry ? 0 : s;149}150151return carry;152}153154/*155* Knuth, TAOCP, Volume 2, 4.3.1:156* w := difference of u (len m) and v (len n).157* number in u >= number in v;158*/159void160_mpd_basesub(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,161mpd_size_t m, mpd_size_t n)162{163mpd_uint_t d;164mpd_uint_t borrow = 0;165mpd_size_t i;166167assert(m > 0 && n > 0);168169/* subtract n members of v from u */170for (i = 0; i < n; i++) {171d = u[i] - (v[i] + borrow);172borrow = (u[i] < d);173w[i] = borrow ? d + MPD_RADIX : d;174}175/* if there is a borrow, propagate it */176for (; borrow && i < m; i++) {177d = u[i] - borrow;178borrow = (u[i] == 0);179w[i] = borrow ? MPD_RADIX-1 : d;180}181/* copy the rest of u */182for (; i < m; i++) {183w[i] = u[i];184}185}186187/*188* Subtract the contents of u from w. w is larger than u. Borrows are189* propagated further, but eventually w can absorb the final borrow.190*/191void192_mpd_basesubfrom(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n)193{194mpd_uint_t d;195mpd_uint_t borrow = 0;196mpd_size_t i;197198if (n == 0) return;199200/* subtract n members of u from w */201for (i = 0; i < n; i++) {202d = w[i] - (u[i] + borrow);203borrow = (w[i] < d);204w[i] = borrow ? d + MPD_RADIX : d;205}206/* if there is a borrow, propagate it */207for (; borrow; i++) {208d = w[i] - borrow;209borrow = (w[i] == 0);210w[i] = borrow ? MPD_RADIX-1 : d;211}212}213214/* w := product of u (len n) and v (single word) */215void216_mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v)217{218mpd_uint_t hi, lo;219mpd_uint_t carry = 0;220mpd_size_t i;221222assert(n > 0);223224for (i=0; i < n; i++) {225226_mpd_mul_words(&hi, &lo, u[i], v);227lo = carry + lo;228if (lo < carry) hi++;229230_mpd_div_words_r(&carry, &w[i], hi, lo);231}232w[i] = carry;233}234235/*236* Knuth, TAOCP, Volume 2, 4.3.1:237* w := product of u (len m) and v (len n)238* w must be initialized to zero239*/240void241_mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,242mpd_size_t m, mpd_size_t n)243{244mpd_uint_t hi, lo;245mpd_uint_t carry;246mpd_size_t i, j;247248assert(m > 0 && n > 0);249250for (j=0; j < n; j++) {251carry = 0;252for (i=0; i < m; i++) {253254_mpd_mul_words(&hi, &lo, u[i], v[j]);255lo = w[i+j] + lo;256if (lo < w[i+j]) hi++;257lo = carry + lo;258if (lo < carry) hi++;259260_mpd_div_words_r(&carry, &w[i+j], hi, lo);261}262w[j+m] = carry;263}264}265266/*267* Knuth, TAOCP Volume 2, 4.3.1, exercise 16:268* w := quotient of u (len n) divided by a single word v269*/270mpd_uint_t271_mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v)272{273mpd_uint_t hi, lo;274mpd_uint_t rem = 0;275mpd_size_t i;276277assert(n > 0);278279for (i=n-1; i != MPD_SIZE_MAX; i--) {280281_mpd_mul_words(&hi, &lo, rem, MPD_RADIX);282lo = u[i] + lo;283if (lo < u[i]) hi++;284285_mpd_div_words(&w[i], &rem, hi, lo, v);286}287288return rem;289}290291/*292* Knuth, TAOCP Volume 2, 4.3.1:293* q, r := quotient and remainder of uconst (len nplusm)294* divided by vconst (len n)295* nplusm >= n296*297* If r is not NULL, r will contain the remainder. If r is NULL, the298* return value indicates if there is a remainder: 1 for true, 0 for299* false. A return value of -1 indicates an error.300*/301int302_mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r,303const mpd_uint_t *uconst, const mpd_uint_t *vconst,304mpd_size_t nplusm, mpd_size_t n)305{306mpd_uint_t ustatic[MPD_MINALLOC_MAX];307mpd_uint_t vstatic[MPD_MINALLOC_MAX];308mpd_uint_t *u = ustatic;309mpd_uint_t *v = vstatic;310mpd_uint_t d, qhat, rhat, w2[2];311mpd_uint_t hi, lo, x;312mpd_uint_t carry;313mpd_size_t i, j, m;314int retval = 0;315316assert(n > 1 && nplusm >= n);317m = sub_size_t(nplusm, n);318319/* D1: normalize */320d = MPD_RADIX / (vconst[n-1] + 1);321322if (nplusm >= MPD_MINALLOC_MAX) {323if ((u = mpd_alloc(nplusm+1, sizeof *u)) == NULL) {324return -1;325}326}327if (n >= MPD_MINALLOC_MAX) {328if ((v = mpd_alloc(n+1, sizeof *v)) == NULL) {329mpd_free(u);330return -1;331}332}333334_mpd_shortmul(u, uconst, nplusm, d);335_mpd_shortmul(v, vconst, n, d);336337/* D2: loop */338for (j=m; j != MPD_SIZE_MAX; j--) {339assert(2 <= j+n && j+n <= nplusm); /* annotation for scan-build */340341/* D3: calculate qhat and rhat */342rhat = _mpd_shortdiv(w2, u+j+n-1, 2, v[n-1]);343qhat = w2[1] * MPD_RADIX + w2[0];344345while (1) {346if (qhat < MPD_RADIX) {347_mpd_singlemul(w2, qhat, v[n-2]);348if (w2[1] <= rhat) {349if (w2[1] != rhat || w2[0] <= u[j+n-2]) {350break;351}352}353}354qhat -= 1;355rhat += v[n-1];356if (rhat < v[n-1] || rhat >= MPD_RADIX) {357break;358}359}360/* D4: multiply and subtract */361carry = 0;362for (i=0; i <= n; i++) {363364_mpd_mul_words(&hi, &lo, qhat, v[i]);365366lo = carry + lo;367if (lo < carry) hi++;368369_mpd_div_words_r(&hi, &lo, hi, lo);370371x = u[i+j] - lo;372carry = (u[i+j] < x);373u[i+j] = carry ? x+MPD_RADIX : x;374carry += hi;375}376q[j] = qhat;377/* D5: test remainder */378if (carry) {379q[j] -= 1;380/* D6: add back */381(void)_mpd_baseadd(u+j, u+j, v, n+1, n);382}383}384385/* D8: unnormalize */386if (r != NULL) {387_mpd_shortdiv(r, u, n, d);388/* we are not interested in the return value here */389retval = 0;390}391else {392retval = !_mpd_isallzero(u, n);393}394395396if (u != ustatic) mpd_free(u);397if (v != vstatic) mpd_free(v);398return retval;399}400401/*402* Left shift of src by 'shift' digits; src may equal dest.403*404* dest := area of n mpd_uint_t with space for srcdigits+shift digits.405* src := coefficient with length m.406*407* The case splits in the function are non-obvious. The following408* equations might help:409*410* Let msdigits denote the number of digits in the most significant411* word of src. Then 1 <= msdigits <= rdigits.412*413* 1) shift = q * rdigits + r414* 2) srcdigits = qsrc * rdigits + msdigits415* 3) destdigits = shift + srcdigits416* = q * rdigits + r + qsrc * rdigits + msdigits417* = q * rdigits + (qsrc * rdigits + (r + msdigits))418*419* The result has q zero words, followed by the coefficient that420* is left-shifted by r. The case r == 0 is trivial. For r > 0, it421* is important to keep in mind that we always read m source words,422* but write m+1 destination words if r + msdigits > rdigits, m words423* otherwise.424*/425void426_mpd_baseshiftl(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t n, mpd_size_t m,427mpd_size_t shift)428{429#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)430/* spurious uninitialized warnings */431mpd_uint_t l=l, lprev=lprev, h=h;432#else433mpd_uint_t l, lprev, h;434#endif435mpd_uint_t q, r;436mpd_uint_t ph;437438assert(m > 0 && n >= m);439440_mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS);441442if (r != 0) {443444ph = mpd_pow10[r];445446--m; --n;447_mpd_divmod_pow10(&h, &lprev, src[m--], MPD_RDIGITS-r);448if (h != 0) { /* r + msdigits > rdigits <==> h != 0 */449dest[n--] = h;450}451/* write m-1 shifted words */452for (; m != MPD_SIZE_MAX; m--,n--) {453_mpd_divmod_pow10(&h, &l, src[m], MPD_RDIGITS-r);454dest[n] = ph * lprev + h;455lprev = l;456}457/* write least significant word */458dest[q] = ph * lprev;459}460else {461while (--m != MPD_SIZE_MAX) {462dest[m+q] = src[m];463}464}465466mpd_uint_zero(dest, q);467}468469/*470* Right shift of src by 'shift' digits; src may equal dest.471* Assumption: srcdigits-shift > 0.472*473* dest := area with space for srcdigits-shift digits.474* src := coefficient with length 'slen'.475*476* The case splits in the function rely on the following equations:477*478* Let msdigits denote the number of digits in the most significant479* word of src. Then 1 <= msdigits <= rdigits.480*481* 1) shift = q * rdigits + r482* 2) srcdigits = qsrc * rdigits + msdigits483* 3) destdigits = srcdigits - shift484* = qsrc * rdigits + msdigits - (q * rdigits + r)485* = (qsrc - q) * rdigits + msdigits - r486*487* Since destdigits > 0 and 1 <= msdigits <= rdigits:488*489* 4) qsrc >= q490* 5) qsrc == q ==> msdigits > r491*492* The result has slen-q words if msdigits > r, slen-q-1 words otherwise.493*/494mpd_uint_t495_mpd_baseshiftr(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t slen,496mpd_size_t shift)497{498#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)499/* spurious uninitialized warnings */500mpd_uint_t l=l, h=h, hprev=hprev; /* low, high, previous high */501#else502mpd_uint_t l, h, hprev; /* low, high, previous high */503#endif504mpd_uint_t rnd, rest; /* rounding digit, rest */505mpd_uint_t q, r;506mpd_size_t i, j;507mpd_uint_t ph;508509assert(slen > 0);510511_mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS);512513rnd = rest = 0;514if (r != 0) {515516ph = mpd_pow10[MPD_RDIGITS-r];517518_mpd_divmod_pow10(&hprev, &rest, src[q], r);519_mpd_divmod_pow10(&rnd, &rest, rest, r-1);520521if (rest == 0 && q > 0) {522rest = !_mpd_isallzero(src, q);523}524/* write slen-q-1 words */525for (j=0,i=q+1; i<slen; i++,j++) {526_mpd_divmod_pow10(&h, &l, src[i], r);527dest[j] = ph * l + hprev;528hprev = h;529}530/* write most significant word */531if (hprev != 0) { /* always the case if slen==q-1 */532dest[j] = hprev;533}534}535else {536if (q > 0) {537_mpd_divmod_pow10(&rnd, &rest, src[q-1], MPD_RDIGITS-1);538/* is there any non-zero digit below rnd? */539if (rest == 0) rest = !_mpd_isallzero(src, q-1);540}541for (j = 0; j < slen-q; j++) {542dest[j] = src[q+j];543}544}545546/* 0-4 ==> rnd+rest < 0.5 */547/* 5 ==> rnd+rest == 0.5 */548/* 6-9 ==> rnd+rest > 0.5 */549return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd;550}551552553/*********************************************************************/554/* Calculations in base b */555/*********************************************************************/556557/*558* Add v to w (len m). The calling function has to handle a possible559* final carry. Assumption: m > 0.560*/561mpd_uint_t562_mpd_shortadd_b(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v, mpd_uint_t b)563{564mpd_uint_t s;565mpd_uint_t carry;566mpd_size_t i;567568assert(m > 0);569570/* add v to w */571s = w[0] + v;572carry = (s < v) | (s >= b);573w[0] = carry ? s-b : s;574575/* if there is a carry, propagate it */576for (i = 1; carry && i < m; i++) {577s = w[i] + carry;578carry = (s == b);579w[i] = carry ? 0 : s;580}581582return carry;583}584585/* w := product of u (len n) and v (single word). Return carry. */586mpd_uint_t587_mpd_shortmul_c(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v)588{589mpd_uint_t hi, lo;590mpd_uint_t carry = 0;591mpd_size_t i;592593assert(n > 0);594595for (i=0; i < n; i++) {596597_mpd_mul_words(&hi, &lo, u[i], v);598lo = carry + lo;599if (lo < carry) hi++;600601_mpd_div_words_r(&carry, &w[i], hi, lo);602}603604return carry;605}606607/* w := product of u (len n) and v (single word) */608mpd_uint_t609_mpd_shortmul_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n,610mpd_uint_t v, mpd_uint_t b)611{612mpd_uint_t hi, lo;613mpd_uint_t carry = 0;614mpd_size_t i;615616assert(n > 0);617618for (i=0; i < n; i++) {619620_mpd_mul_words(&hi, &lo, u[i], v);621lo = carry + lo;622if (lo < carry) hi++;623624_mpd_div_words(&carry, &w[i], hi, lo, b);625}626627return carry;628}629630/*631* Knuth, TAOCP Volume 2, 4.3.1, exercise 16:632* w := quotient of u (len n) divided by a single word v633*/634mpd_uint_t635_mpd_shortdiv_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n,636mpd_uint_t v, mpd_uint_t b)637{638mpd_uint_t hi, lo;639mpd_uint_t rem = 0;640mpd_size_t i;641642assert(n > 0);643644for (i=n-1; i != MPD_SIZE_MAX; i--) {645646_mpd_mul_words(&hi, &lo, rem, b);647lo = u[i] + lo;648if (lo < u[i]) hi++;649650_mpd_div_words(&w[i], &rem, hi, lo, v);651}652653return rem;654}655656657