@@ -2879,6 +2879,64 @@ BigDecimal_inspect(VALUE self)
28792879 return str ;
28802880}
28812881
2882+ /* Returns self * 10**v without changing the precision.
2883+ * This method is currently for internal use.
2884+ *
2885+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
2886+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
2887+ */
2888+ static VALUE
2889+ BigDecimal_decimal_shift (VALUE self , VALUE v )
2890+ {
2891+ ENTER (5 );
2892+ Real * c , * a ;
2893+
2894+ v = rb_to_int (v );
2895+ if (!FIXNUM_P (v )) {
2896+ rb_raise (rb_eTypeError , "invalid shift width" );
2897+ }
2898+ long shift = FIX2LONG (v );
2899+ if (shift == 0 ) return self ;
2900+
2901+ GUARD_OBJ (a , GetVpValue (self , 1 ));
2902+ if (VpIsZero (a ) || VpIsNaN (a ) || VpIsInf (a )) return self ;
2903+
2904+ long exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1 ) / BASE_FIG - 1 ;
2905+ shift -= exponentShift * BASE_FIG ;
2906+ DECDIG ex = 1 ;
2907+ for (int i = 0 ; i < shift ; i ++ ) ex *= 10 ;
2908+ bool shiftDown = a -> frac [0 ] * (DECDIG_DBL )ex >= BASE ;
2909+ DECDIG iex = BASE / ex ;
2910+
2911+ size_t prec = a -> Prec + shiftDown ;
2912+ size_t mx = prec * (VpBaseFig () + 1 );
2913+ GUARD_OBJ (c , NewZeroWrapLimited (1 , mx ));
2914+ if (shift == 0 ) {
2915+ VpAsgn (c , a , 1 );
2916+ } else if (shiftDown ) {
2917+ exponentShift ++ ;
2918+ DECDIG carry = 0 ;
2919+ for (size_t i = 0 ; i < a -> Prec ; i ++ ) {
2920+ DECDIG v = a -> frac [i ];
2921+ c -> frac [i ] = carry * ex + v / iex ;
2922+ carry = v % iex ;
2923+ }
2924+ c -> frac [a -> Prec ] = carry * ex ;
2925+ } else {
2926+ DECDIG carry = 0 ;
2927+ for (ssize_t i = a -> Prec - 1 ; i >= 0 ; i -- ) {
2928+ DECDIG v = a -> frac [i ];
2929+ c -> frac [i ] = v % iex * ex + carry ;
2930+ carry = v / iex ;
2931+ }
2932+ }
2933+ while (c -> frac [prec - 1 ] == 0 ) prec -- ;
2934+ c -> Prec = prec ;
2935+ c -> exponent = a -> exponent + exponentShift ;
2936+ c -> sign = a -> sign ;
2937+ return VpCheckGetValue (c );
2938+ }
2939+
28822940static VALUE BigMath_s_exp (VALUE , VALUE , VALUE );
28832941static VALUE BigMath_s_log (VALUE , VALUE , VALUE );
28842942
@@ -4633,6 +4691,7 @@ Init_bigdecimal(void)
46334691 rb_define_method (rb_cBigDecimal , "infinite?" , BigDecimal_IsInfinite , 0 );
46344692 rb_define_method (rb_cBigDecimal , "finite?" , BigDecimal_IsFinite , 0 );
46354693 rb_define_method (rb_cBigDecimal , "truncate" , BigDecimal_truncate , -1 );
4694+ rb_define_method (rb_cBigDecimal , "_decimal_shift" , BigDecimal_decimal_shift , 1 );
46364695 rb_define_method (rb_cBigDecimal , "_dump" , BigDecimal_dump , -1 );
46374696
46384697 rb_mBigMath = rb_define_module ("BigMath" );
0 commit comments