@@ -2829,6 +2829,64 @@ BigDecimal_inspect(VALUE self)
2829
2829
return str ;
2830
2830
}
2831
2831
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
+
2832
2890
static VALUE BigMath_s_exp (VALUE , VALUE , VALUE );
2833
2891
static VALUE BigMath_s_log (VALUE , VALUE , VALUE );
2834
2892
@@ -4582,6 +4640,7 @@ Init_bigdecimal(void)
4582
4640
rb_define_method (rb_cBigDecimal , "infinite?" , BigDecimal_IsInfinite , 0 );
4583
4641
rb_define_method (rb_cBigDecimal , "finite?" , BigDecimal_IsFinite , 0 );
4584
4642
rb_define_method (rb_cBigDecimal , "truncate" , BigDecimal_truncate , -1 );
4643
+ rb_define_method (rb_cBigDecimal , "_decimal_shift" , BigDecimal_decimal_shift , 1 );
4585
4644
rb_define_method (rb_cBigDecimal , "_dump" , BigDecimal_dump , -1 );
4586
4645
4587
4646
rb_mBigMath = rb_define_module ("BigMath" );
0 commit comments