@@ -269,6 +269,7 @@ rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
269
269
static unsigned short VpGetException (void );
270
270
static void VpSetException (unsigned short f );
271
271
static void VpCheckException (Real * p , bool always );
272
+ static int AddExponent (Real * a , SIGNED_VALUE n );
272
273
static VALUE CheckGetValue (BDVALUE v );
273
274
static void VpInternalRound (Real * c , size_t ixDigit , DECDIG vPrev , DECDIG v );
274
275
static int VpLimitRound (Real * c , size_t ixDigit );
@@ -2672,6 +2673,63 @@ BigDecimal_inspect(VALUE self)
2672
2673
return str ;
2673
2674
}
2674
2675
2676
+ /* Returns self * 10**v without changing the precision.
2677
+ * This method is currently for internal use.
2678
+ *
2679
+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
2680
+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
2681
+ */
2682
+ static VALUE
2683
+ BigDecimal_decimal_shift (VALUE self , VALUE v )
2684
+ {
2685
+ BDVALUE a , c ;
2686
+ ssize_t shift , exponentShift ;
2687
+ bool shiftDown ;
2688
+ size_t prec ;
2689
+ DECDIG ex , iex ;
2690
+
2691
+ a = GetBDValueMust (self );
2692
+ shift = NUM2SSIZET (rb_to_int (v ));
2693
+
2694
+ if (VpIsZero (a .real ) || VpIsNaN (a .real ) || VpIsInf (a .real ) || shift == 0 ) return CheckGetValue (a );
2695
+
2696
+ exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1 ) / BASE_FIG - 1 ;
2697
+ shift -= exponentShift * BASE_FIG ;
2698
+ ex = 1 ;
2699
+ for (int i = 0 ; i < shift ; i ++ ) ex *= 10 ;
2700
+ shiftDown = a .real -> frac [0 ] * (DECDIG_DBL )ex >= BASE ;
2701
+ iex = BASE / ex ;
2702
+
2703
+ prec = a .real -> Prec + shiftDown ;
2704
+ c = NewZeroWrapLimited (1 , prec * BASE_FIG );
2705
+ if (shift == 0 ) {
2706
+ VpAsgn (c .real , a .real , 1 );
2707
+ } else if (shiftDown ) {
2708
+ DECDIG carry = 0 ;
2709
+ exponentShift ++ ;
2710
+ for (size_t i = 0 ; i < a .real -> Prec ; i ++ ) {
2711
+ DECDIG v = a .real -> frac [i ];
2712
+ c .real -> frac [i ] = carry * ex + v / iex ;
2713
+ carry = v % iex ;
2714
+ }
2715
+ c .real -> frac [a .real -> Prec ] = carry * ex ;
2716
+ } else {
2717
+ DECDIG carry = 0 ;
2718
+ for (ssize_t i = a .real -> Prec - 1 ; i >= 0 ; i -- ) {
2719
+ DECDIG v = a .real -> frac [i ];
2720
+ c .real -> frac [i ] = v % iex * ex + carry ;
2721
+ carry = v / iex ;
2722
+ }
2723
+ }
2724
+ while (c .real -> frac [prec - 1 ] == 0 ) prec -- ;
2725
+ c .real -> Prec = prec ;
2726
+ c .real -> sign = a .real -> sign ;
2727
+ c .real -> exponent = a .real -> exponent ;
2728
+ AddExponent (c .real , exponentShift );
2729
+ RB_GC_GUARD (a .bigdecimal );
2730
+ return CheckGetValue (c );
2731
+ }
2732
+
2675
2733
inline static int
2676
2734
is_zero (VALUE x )
2677
2735
{
@@ -3796,6 +3854,7 @@ Init_bigdecimal(void)
3796
3854
rb_define_method (rb_cBigDecimal , "infinite?" , BigDecimal_IsInfinite , 0 );
3797
3855
rb_define_method (rb_cBigDecimal , "finite?" , BigDecimal_IsFinite , 0 );
3798
3856
rb_define_method (rb_cBigDecimal , "truncate" , BigDecimal_truncate , -1 );
3857
+ rb_define_method (rb_cBigDecimal , "_decimal_shift" , BigDecimal_decimal_shift , 1 );
3799
3858
rb_define_method (rb_cBigDecimal , "_dump" , BigDecimal_dump , -1 );
3800
3859
3801
3860
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
@@ -3856,7 +3915,6 @@ enum op_sw {
3856
3915
};
3857
3916
3858
3917
static int VpIsDefOP (Real * c , Real * a , Real * b , enum op_sw sw );
3859
- static int AddExponent (Real * a , SIGNED_VALUE n );
3860
3918
static DECDIG VpAddAbs (Real * a ,Real * b ,Real * c );
3861
3919
static DECDIG VpSubAbs (Real * a ,Real * b ,Real * c );
3862
3920
static size_t VpSetPTR (Real * a , Real * b , Real * c , size_t * a_pos , size_t * b_pos , size_t * c_pos , DECDIG * av , DECDIG * bv );
0 commit comments