@@ -2829,6 +2829,64 @@ BigDecimal_inspect(VALUE self)
28292829 return str ;
28302830}
28312831
2832+ /* Returns self * 10**v without changing the precision.
2833+ * This method is currently for internal use.
2834+ *
2835+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
2836+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
2837+ */
2838+ static VALUE
2839+ BigDecimal_decimal_shift (VALUE self , VALUE v )
2840+ {
2841+ ENTER (5 );
2842+ Real * c , * a ;
2843+
2844+ v = rb_to_int (v );
2845+ if (!FIXNUM_P (v )) {
2846+ rb_raise (rb_eTypeError , "invalid shift width" );
2847+ }
2848+ long shift = FIX2LONG (v );
2849+ if (shift == 0 ) return self ;
2850+
2851+ GUARD_OBJ (a , GetVpValue (self , 1 ));
2852+ if (VpIsZero (a ) || VpIsNaN (a ) || VpIsInf (a )) return self ;
2853+
2854+ long exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1 ) / BASE_FIG - 1 ;
2855+ shift -= exponentShift * BASE_FIG ;
2856+ DECDIG ex = 1 ;
2857+ for (int i = 0 ; i < shift ; i ++ ) ex *= 10 ;
2858+ bool shiftDown = a -> frac [0 ] * (DECDIG_DBL )ex >= BASE ;
2859+ DECDIG iex = BASE / ex ;
2860+
2861+ size_t prec = a -> Prec + shiftDown ;
2862+ size_t mx = prec * (VpBaseFig () + 1 );
2863+ GUARD_OBJ (c , NewZeroWrapLimited (1 , mx ));
2864+ if (shift == 0 ) {
2865+ VpAsgn (c , a , 1 );
2866+ } else if (shiftDown ) {
2867+ exponentShift ++ ;
2868+ DECDIG carry = 0 ;
2869+ for (size_t i = 0 ; i < a -> Prec ; i ++ ) {
2870+ DECDIG v = a -> frac [i ];
2871+ c -> frac [i ] = carry * ex + v / iex ;
2872+ carry = v % iex ;
2873+ }
2874+ c -> frac [a -> Prec ] = carry * ex ;
2875+ } else {
2876+ DECDIG carry = 0 ;
2877+ for (ssize_t i = a -> Prec - 1 ; i >= 0 ; i -- ) {
2878+ DECDIG v = a -> frac [i ];
2879+ c -> frac [i ] = v % iex * ex + carry ;
2880+ carry = v / iex ;
2881+ }
2882+ }
2883+ while (c -> frac [prec - 1 ] == 0 ) prec -- ;
2884+ c -> Prec = prec ;
2885+ c -> exponent = a -> exponent + exponentShift ;
2886+ c -> sign = a -> sign ;
2887+ return VpCheckGetValue (c );
2888+ }
2889+
28322890static VALUE BigMath_s_exp (VALUE , VALUE , VALUE );
28332891static VALUE BigMath_s_log (VALUE , VALUE , VALUE );
28342892
@@ -4582,6 +4640,7 @@ Init_bigdecimal(void)
45824640 rb_define_method (rb_cBigDecimal , "infinite?" , BigDecimal_IsInfinite , 0 );
45834641 rb_define_method (rb_cBigDecimal , "finite?" , BigDecimal_IsFinite , 0 );
45844642 rb_define_method (rb_cBigDecimal , "truncate" , BigDecimal_truncate , -1 );
4643+ rb_define_method (rb_cBigDecimal , "_decimal_shift" , BigDecimal_decimal_shift , 1 );
45854644 rb_define_method (rb_cBigDecimal , "_dump" , BigDecimal_dump , -1 );
45864645
45874646 rb_mBigMath = rb_define_module ("BigMath" );
0 commit comments