Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5d0d2e2

Browse files
author
Stefan Krah
committed
Explain the strategy to avoid huge alignment shifts in _mpd_qadd() in detail.
1 parent ed4b21f commit 5d0d2e2

1 file changed

Lines changed: 35 additions & 6 deletions

File tree

Modules/_decimal/libmpdec/mpdecimal.c

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3103,22 +3103,51 @@ _mpd_qaddsub(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b,
31033103
_mpd_ptrswap(&big, &small);
31043104
swap++;
31053105
}
3106+
/* align the coefficients */
31063107
if (!mpd_iszerocoeff(big)) {
3107-
/* Test for adjexp(small) + big->digits < adjexp(big), if big-digits > prec
3108-
* Test for adjexp(small) + prec + 1 < adjexp(big), if big-digits <= prec
3109-
* If true, the magnitudes of the numbers are so far apart that one can as
3110-
* well add or subtract 1*10**big->exp. */
31113108
exp = big->exp - 1;
31123109
exp += (big->digits > ctx->prec) ? 0 : big->digits-ctx->prec-1;
31133110
if (mpd_adjexp(small) < exp) {
3111+
/*
3112+
* Avoid huge shifts by substituting a value for small that is
3113+
* guaranteed to produce the same results.
3114+
*
3115+
* adjexp(small) < exp if and only if:
3116+
*
3117+
* bdigits <= prec AND
3118+
* bdigits+shift >= prec+2+sdigits AND
3119+
* exp = bexp+bdigits-prec-2
3120+
*
3121+
* 1234567000000000 -> bdigits + shift
3122+
* ----------XX1234 -> sdigits
3123+
* ----------X1 -> tiny-digits
3124+
* |- prec -|
3125+
*
3126+
* OR
3127+
*
3128+
* bdigits > prec AND
3129+
* shift > sdigits AND
3130+
* exp = bexp-1
3131+
*
3132+
* 1234567892100000 -> bdigits + shift
3133+
* ----------XX1234 -> sdigits
3134+
* ----------X1 -> tiny-digits
3135+
* |- prec -|
3136+
*
3137+
* If tiny is zero, adding or subtracting is a no-op.
3138+
* Otherwise, adding tiny generates a non-zero digit either
3139+
* below the rounding digit or the least significant digit
3140+
* of big. When subtracting, tiny is in the same position as
3141+
* the carry that would be generated by subtracting sdigits.
3142+
*/
31143143
mpd_copy_flags(&tiny, small);
31153144
tiny.exp = exp;
31163145
tiny.digits = 1;
31173146
tiny.len = 1;
31183147
tiny.data[0] = mpd_iszerocoeff(small) ? 0 : 1;
31193148
small = &tiny;
31203149
}
3121-
/* this cannot wrap: the difference is positive and <= maxprec+1 */
3150+
/* This cannot wrap: the difference is positive and <= maxprec */
31223151
shift = big->exp - small->exp;
31233152
if (!mpd_qshiftl(&big_aligned, big, shift, status)) {
31243153
mpd_seterror(result, MPD_Malloc_error, status);
@@ -3521,7 +3550,7 @@ mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b,
35213550
/* Internal function. */
35223551
static void
35233552
_mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
3524-
const mpd_context_t *ctx, uint32_t *status)
3553+
const mpd_context_t *ctx, uint32_t *status)
35253554
{
35263555
MPD_NEW_STATIC(aligned,0,0,0,0);
35273556
mpd_ssize_t qsize, rsize;

0 commit comments

Comments
 (0)