@@ -1084,7 +1084,12 @@ BigDecimal_to_i(VALUE self)
10841084
10851085 if (v .real -> exponent <= 0 ) return INT2FIX (0 );
10861086 if (v .real -> exponent == 1 ) {
1087- ret = LONG2NUM ((long )(VpGetSign (v .real ) * (DECDIG_DBL_SIGNED )v .real -> frac [0 ]));
1087+ DECDIG_SIGNED value = VpGetSign (v .real ) * (DECDIG_SIGNED )v .real -> frac [0 ];
1088+ #if SIZEOF_DECDIG == 4
1089+ ret = LONG2NUM ((long )value );
1090+ #elif SIZEOF_DECDIG == 8
1091+ ret = LL2NUM ((long long )value );
1092+ #endif
10881093 }
10891094 else {
10901095 VALUE fix = (ssize_t )v .real -> Prec > v .real -> exponent ? BigDecimal_fix (self ) : self ;
@@ -3228,6 +3233,40 @@ BigDecimal_literal(const char *str)
32283233
32293234#define BIGDECIMAL_LITERAL (var , val ) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
32303235
3236+ #if SIZEOF_DECDIG == 4
3237+ # define ntt_multiply ntt_multiply32
3238+ #elif SIZEOF_DECDIG == 8 && BASE_FIG == 18
3239+ static void
3240+ ntt_multiply (size_t a_size , size_t b_size , uint64_t * a , uint64_t * b , uint64_t * c ) {
3241+ size_t c_size = a_size + b_size ;
3242+ BDVALUE bd_a = NewZeroWrap (1 , a_size * BASE_FIG );
3243+ BDVALUE bd_b = NewZeroWrap (1 , b_size * BASE_FIG );
3244+ BDVALUE bd_c = NewZeroWrap (1 , c_size * BASE_FIG );
3245+ uint32_t * a32 = (uint32_t * )bd_a .real -> frac ;
3246+ uint32_t * b32 = (uint32_t * )bd_b .real -> frac ;
3247+ uint32_t * c32 = (uint32_t * )bd_c .real -> frac ;
3248+
3249+ // Pack to 64-bit (BASE_FIG=18) to 32-bit digits(BASE_FIG=9) and call ntt_multiply32
3250+ for (uint32_t i = 0 ; i < a_size ; i ++ ) {
3251+ uint64_t v = a [i ];
3252+ a32 [i * 2 ] = (uint32_t )(v / NTT_DECDIG_BASE );
3253+ a32 [i * 2 + 1 ] = (uint32_t )(v % NTT_DECDIG_BASE );
3254+ }
3255+ for (uint32_t i = 0 ; i < b_size ; i ++ ) {
3256+ uint64_t v = b [i ];
3257+ b32 [i * 2 ] = (uint32_t )(v / NTT_DECDIG_BASE );
3258+ b32 [i * 2 + 1 ] = (uint32_t )(v % NTT_DECDIG_BASE );
3259+ }
3260+ ntt_multiply32 (a_size * 2 , b_size * 2 , a32 , b32 , c32 );
3261+ for (uint32_t i = 0 ; i < c_size ; i ++ ) {
3262+ c [i ] = (uint64_t )c32 [i * 2 ] * NTT_DECDIG_BASE + c32 [i * 2 + 1 ];
3263+ }
3264+ RB_GC_GUARD (bd_a .bigdecimal );
3265+ RB_GC_GUARD (bd_b .bigdecimal );
3266+ RB_GC_GUARD (bd_c .bigdecimal );
3267+ }
3268+ #endif
3269+
32313270#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
32323271VALUE
32333272BigDecimal_vpdivd_generic (VALUE self , VALUE r , VALUE cprec , void (* vpdivd_func )(Real * , Real * , Real * , Real * )) {
@@ -3486,13 +3525,15 @@ Init_bigdecimal(void)
34863525 rb_define_const (rb_cBigDecimal , "VERSION" , rb_str_new2 (BIGDECIMAL_VERSION ));
34873526
34883527 /*
3489- * Base value used in internal calculations. On a 32 bit system, BASE
3490- * is 10000, indicating that calculation is done in groups of 4 digits.
3491- * (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't
3528+ * Base value used in internal calculations.
3529+ * If uint128_t is available, BASE is (uint64_t)1000000000000000000ULL.
3530+ * Otherswise, BASE is 1000000000, indicating that calculation is done
3531+ * in groups of 9 digits.
3532+ * (If it were larger, BASE**2 wouldn't fit in 64 bits, so you couldn't
34923533 * guarantee that two groups could always be multiplied together without
34933534 * overflow.)
34943535 */
3495- rb_define_const (rb_cBigDecimal , "BASE" , INT2FIX (( SIGNED_VALUE ) BASE ));
3536+ rb_define_const (rb_cBigDecimal , "BASE" , ULL2NUM ( BASE ));
34963537
34973538 /* Exceptions */
34983539
0 commit comments