3535
3636#define BIGDECIMAL_VERSION "4.1.0"
3737
38- #define NTT_MULTIPLICATION_THRESHOLD 100
39- #define NEWTON_RAPHSON_DIVISION_THRESHOLD 200
38+ #define NTT_MULTIPLICATION_THRESHOLD 200
39+ #define NEWTON_RAPHSON_DIVISION_THRESHOLD 100
4040#define SIGNED_VALUE_MAX INTPTR_MAX
4141#define SIGNED_VALUE_MIN INTPTR_MIN
4242#define MUL_OVERFLOW_SIGNED_VALUE_P (a , b ) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
@@ -4904,17 +4904,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
49044904 * a0 a1 .... an * b0
49054905 * +_____________________________
49064906 * c0 c1 c2 ...... cl
4907- * nc <---|
4908- * MaxAB |--------------------|
49094907 */
49104908VP_EXPORT size_t
49114909VpMult (Real * c , Real * a , Real * b )
49124910{
4913- size_t MxIndA , MxIndB , MxIndAB ;
4914- size_t ind_c , i , ii , nc ;
4915- size_t ind_as , ind_ae , ind_bs ;
4916- DECDIG carry ;
4917- DECDIG_DBL s ;
4911+ ssize_t a_batch_max , b_batch_max ;
4912+ DECDIG_DBL batch [15 ];
49184913
49194914 if (!VpIsDefOP (c , a , b , OP_SW_MULT )) return 0 ; /* No significant digit */
49204915
@@ -4938,9 +4933,6 @@ VpMult(Real *c, Real *a, Real *b)
49384933 a = b ;
49394934 b = w ;
49404935 }
4941- MxIndA = a -> Prec - 1 ;
4942- MxIndB = b -> Prec - 1 ;
4943- MxIndAB = a -> Prec + b -> Prec - 1 ;
49444936
49454937 /* set LHSV c info */
49464938
@@ -4954,51 +4946,40 @@ VpMult(Real *c, Real *a, Real *b)
49544946 goto Cleanup ;
49554947 }
49564948
4957- carry = 0 ;
4958- nc = ind_c = MxIndAB ;
4959- memset (c -> frac , 0 , (nc + 1 ) * sizeof (DECDIG )); /* Initialize c */
4960- c -> Prec = nc + 1 ; /* set precision */
4961- for (nc = 0 ; nc < MxIndAB ; ++ nc , -- ind_c ) {
4962- if (nc < MxIndB ) { /* The left triangle of the Fig. */
4963- ind_as = MxIndA - nc ;
4964- ind_ae = MxIndA ;
4965- ind_bs = MxIndB ;
4966- }
4967- else if (nc <= MxIndA ) { /* The middle rectangular of the Fig. */
4968- ind_as = MxIndA - nc ;
4969- ind_ae = MxIndA - (nc - MxIndB );
4970- ind_bs = MxIndB ;
4971- }
4972- else /* if (nc > MxIndA) */ { /* The right triangle of the Fig. */
4973- ind_as = 0 ;
4974- ind_ae = MxIndAB - nc - 1 ;
4975- ind_bs = MxIndB - (nc - MxIndA );
4976- }
4949+ c -> Prec = a -> Prec + b -> Prec ; /* set precision */
4950+ memset (c -> frac , 0 , c -> Prec * sizeof (DECDIG )); /* Initialize c */
49774951
4978- for (i = ind_as ; i <= ind_ae ; ++ i ) {
4979- s = (DECDIG_DBL )a -> frac [i ] * b -> frac [ind_bs -- ];
4980- carry = (DECDIG )(s / BASE );
4981- s -= (DECDIG_DBL )carry * BASE ;
4982- c -> frac [ind_c ] += (DECDIG )s ;
4983- if (c -> frac [ind_c ] >= BASE ) {
4984- s = c -> frac [ind_c ] / BASE ;
4985- carry += (DECDIG )s ;
4986- c -> frac [ind_c ] -= (DECDIG )(s * BASE );
4952+ // Process 8 decdigits at a time to reduce the number of carry operations.
4953+ a_batch_max = (a -> Prec - 1 ) / 8 ;
4954+ b_batch_max = (b -> Prec - 1 ) / 8 ;
4955+ for (ssize_t ibatch = a_batch_max ; ibatch >= 0 ; ibatch -- ) {
4956+ int isize = ibatch == a_batch_max ? (a -> Prec - 1 ) % 8 + 1 : 8 ;
4957+ for (ssize_t jbatch = b_batch_max ; jbatch >= 0 ; jbatch -- ) {
4958+ int jsize = jbatch == b_batch_max ? (b -> Prec - 1 ) % 8 + 1 : 8 ;
4959+ memset (batch , 0 , (isize + jsize - 1 ) * sizeof (DECDIG_DBL ));
4960+
4961+ // Perform multiplication without carry calculation.
4962+ // 999999999 * 999999999 * 8 < 2**63 - 1, so DECDIG_DBL can hold the intermediate sum without overflow.
4963+ for (int i = 0 ; i < isize ; i ++ ) {
4964+ for (int j = 0 ; j < jsize ; j ++ ) {
4965+ batch [i + j ] += (DECDIG_DBL )a -> frac [ibatch * 8 + i ] * b -> frac [jbatch * 8 + j ];
4966+ }
49874967 }
4988- if (carry ) {
4989- ii = ind_c ;
4990- while (ii -- > 0 ) {
4991- c -> frac [ii ] += carry ;
4992- if (c -> frac [ii ] >= BASE ) {
4993- carry = c -> frac [ii ] / BASE ;
4994- c -> frac [ii ] -= (carry * BASE );
4995- }
4996- else {
4997- break ;
4998- }
4999- }
5000- }
5001- }
4968+
4969+ // Add the batch result to c with carry calculation.
4970+ DECDIG_DBL carry = 0 ;
4971+ for (int k = isize + jsize - 2 ; k >= 0 ; k -- ) {
4972+ size_t l = (ibatch + jbatch ) * 8 + k + 1 ;
4973+ DECDIG_DBL s = c -> frac [l ] + batch [k ] + carry ;
4974+ c -> frac [l ] = (DECDIG )(s % BASE );
4975+ carry = (DECDIG_DBL )(s / BASE );
4976+ }
4977+
4978+ // Adding carry may exceed BASE, but it won't cause overflow of DECDIG.
4979+ // Exceeded value will be normalized in the carry operation of next (ibatch + jbatch - 1) batch.
4980+ // WARNING: This safety strongly relies on the current nested loop execution order.
4981+ c -> frac [(ibatch + jbatch ) * 8 ] += (DECDIG )carry ;
4982+ }
50024983 }
50034984
50044985Cleanup :
0 commit comments