@@ -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. */
35223551static 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