@@ -145,6 +145,9 @@ bdvalue_nullable(BDVALUE v)
145145#define BIGDECIMAL_POSITIVE_P (bd ) ((bd)->sign > 0)
146146#define BIGDECIMAL_NEGATIVE_P (bd ) ((bd)->sign < 0)
147147
148+ #define MULT_BY_RB_INTEGER_THRESHOLD 150
149+ #define DIV_BY_RB_INTEGER_THRESHOLD 300
150+
148151/*
149152 * ================== Memory allocation ============================
150153 */
@@ -5873,6 +5876,32 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
58735876 return word_shift ;
58745877}
58755878
5879+ static int
5880+ VpMultWithRubyInteger (Real * c , Real * a , Real * b )
5881+ {
5882+ Real * ap , * bp ;
5883+ VALUE a2 , b2 , ab ;
5884+ BDVALUE c2 ;
5885+ ap = VpCopy (NULL , a );
5886+ bp = VpCopy (NULL , b );
5887+ ap -> exponent = a -> Prec ;
5888+ bp -> exponent = b -> Prec ;
5889+ a2 = TypedData_Wrap_Struct (rb_cBigDecimal , & BigDecimal_data_type , 0 );
5890+ b2 = TypedData_Wrap_Struct (rb_cBigDecimal , & BigDecimal_data_type , 0 );
5891+ BigDecimal_wrap_struct (a2 , ap );
5892+ BigDecimal_wrap_struct (b2 , bp );
5893+ ab = rb_funcall (BigDecimal_to_i (a2 ), '*' , 1 , BigDecimal_to_i (b2 ));
5894+
5895+ c2 = GetBDValueMust (ab );
5896+ VpAsgn (c , c2 .real , 1 );
5897+ if (!AddExponent (c , a -> exponent )) return 0 ;
5898+ if (!AddExponent (c , b -> exponent )) return 0 ;
5899+ if (!AddExponent (c , - a -> Prec )) return 0 ;
5900+ if (!AddExponent (c , - b -> Prec )) return 0 ;
5901+ RB_GC_GUARD (c2 .bigdecimal );
5902+ return 1 ;
5903+ }
5904+
58765905/*
58775906 * Return number of significant digits
58785907 * c = a * b , Where a = a0a1a2 ... an
@@ -5926,6 +5955,11 @@ VpMult(Real *c, Real *a, Real *b)
59265955 MxIndC = c -> MaxPrec - 1 ;
59275956 MxIndAB = a -> Prec + b -> Prec - 1 ;
59285957
5958+ if (a -> Prec >= MULT_BY_RB_INTEGER_THRESHOLD && b -> Prec >= MULT_BY_RB_INTEGER_THRESHOLD ) {
5959+ if (!VpMultWithRubyInteger (c , a , b )) return 0 ;
5960+ goto Exit ;
5961+ }
5962+
59295963 if (MxIndC < MxIndAB ) { /* The Max. prec. of c < Prec(a)+Prec(b) */
59305964w = c ;
59315965 c = NewZeroNolimit (1 , (size_t )((MxIndAB + 1 ) * BASE_FIG ));
@@ -6000,6 +6034,46 @@ VpMult(Real *c, Real *a, Real *b)
60006034 return c -> Prec * BASE_FIG ;
60016035}
60026036
6037+ static void
6038+ VpDivdWithRubyInteger (Real * c , Real * r , Real * a , Real * b )
6039+ {
6040+ Real * ap , * bp ;
6041+ BDVALUE c2 , r2 ;
6042+ VALUE a2 , b2 , divmod , div , mod ;
6043+ size_t div_prec = c -> MaxPrec - 1 ;
6044+ size_t base_prec = b -> Prec ;
6045+
6046+ ap = VpCopy (NULL , a );
6047+ bp = VpCopy (NULL , b );
6048+ VpSetSign (ap , 1 );
6049+ VpSetSign (bp , 1 );
6050+ ap -> exponent = base_prec + div_prec ;
6051+ bp -> exponent = base_prec ;
6052+ a2 = TypedData_Wrap_Struct (rb_cBigDecimal , & BigDecimal_data_type , 0 );
6053+ b2 = TypedData_Wrap_Struct (rb_cBigDecimal , & BigDecimal_data_type , 0 );
6054+ BigDecimal_wrap_struct (a2 , ap );
6055+ BigDecimal_wrap_struct (b2 , bp );
6056+ divmod = rb_funcall (BigDecimal_to_i (a2 ), rb_intern ("divmod" ), 1 , BigDecimal_to_i (b2 ));
6057+ if (RB_TYPE_P (divmod , T_ARRAY ) && RARRAY_LEN (divmod ) == 2 ) {
6058+ div = RARRAY_AREF (divmod , 0 );
6059+ mod = RARRAY_AREF (divmod , 1 );
6060+ } else {
6061+ div = mod = Qnil ;
6062+ }
6063+
6064+ c2 = GetBDValueMust (div );
6065+ r2 = GetBDValueMust (mod );
6066+ VpAsgn (c , c2 .real , VpGetSign (a ) * VpGetSign (b ));
6067+ VpAsgn (r , r2 .real , VpGetSign (a ));
6068+ RB_GC_GUARD (c2 .bigdecimal );
6069+ RB_GC_GUARD (r2 .bigdecimal );
6070+ AddExponent (c , a -> exponent );
6071+ AddExponent (c , - b -> exponent );
6072+ AddExponent (c , - div_prec );
6073+ AddExponent (r , a -> exponent );
6074+ AddExponent (r , - base_prec - div_prec );
6075+ }
6076+
60036077/*
60046078 * c = a / b, remainder = r
60056079 * XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
@@ -6041,6 +6115,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
60416115
60426116 if (word_a > word_r || word_b + word_c - 2 >= word_r ) goto space_error ;
60436117
6118+ if (word_c >= DIV_BY_RB_INTEGER_THRESHOLD && word_b >= DIV_BY_RB_INTEGER_THRESHOLD ) {
6119+ VpDivdWithRubyInteger (c , r , a , b );
6120+ goto Exit ;
6121+ }
6122+
60446123 for (i = 0 ; i < word_a ; ++ i ) r -> frac [i ] = a -> frac [i ];
60456124 for (i = word_a ; i < word_r ; ++ i ) r -> frac [i ] = 0 ;
60466125 for (i = 0 ; i < word_c ; ++ i ) c -> frac [i ] = 0 ;
0 commit comments