@@ -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 );
@@ -2603,6 +2604,63 @@ BigDecimal_inspect(VALUE self)
2603
2604
return str ;
2604
2605
}
2605
2606
2607
+ /* Returns self * 10**v without changing the precision.
2608
+ * This method is currently for internal use.
2609
+ *
2610
+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
2611
+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
2612
+ */
2613
+ static VALUE
2614
+ BigDecimal_decimal_shift (VALUE self , VALUE v )
2615
+ {
2616
+ BDVALUE a , c ;
2617
+ ssize_t shift , exponentShift ;
2618
+ bool shiftDown ;
2619
+ size_t prec ;
2620
+ DECDIG ex , iex ;
2621
+
2622
+ a = GetBDValueMust (self );
2623
+ shift = NUM2SSIZET (rb_to_int (v ));
2624
+
2625
+ if (VpIsZero (a .real ) || VpIsNaN (a .real ) || VpIsInf (a .real ) || shift == 0 ) return CheckGetValue (a );
2626
+
2627
+ exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1 ) / BASE_FIG - 1 ;
2628
+ shift -= exponentShift * BASE_FIG ;
2629
+ ex = 1 ;
2630
+ for (int i = 0 ; i < shift ; i ++ ) ex *= 10 ;
2631
+ shiftDown = a .real -> frac [0 ] * (DECDIG_DBL )ex >= BASE ;
2632
+ iex = BASE / ex ;
2633
+
2634
+ prec = a .real -> Prec + shiftDown ;
2635
+ c = NewZeroWrapLimited (1 , prec * BASE_FIG );
2636
+ if (shift == 0 ) {
2637
+ VpAsgn (c .real , a .real , 1 );
2638
+ } else if (shiftDown ) {
2639
+ DECDIG carry = 0 ;
2640
+ exponentShift ++ ;
2641
+ for (size_t i = 0 ; i < a .real -> Prec ; i ++ ) {
2642
+ DECDIG v = a .real -> frac [i ];
2643
+ c .real -> frac [i ] = carry * ex + v / iex ;
2644
+ carry = v % iex ;
2645
+ }
2646
+ c .real -> frac [a .real -> Prec ] = carry * ex ;
2647
+ } else {
2648
+ DECDIG carry = 0 ;
2649
+ for (ssize_t i = a .real -> Prec - 1 ; i >= 0 ; i -- ) {
2650
+ DECDIG v = a .real -> frac [i ];
2651
+ c .real -> frac [i ] = v % iex * ex + carry ;
2652
+ carry = v / iex ;
2653
+ }
2654
+ }
2655
+ while (c .real -> frac [prec - 1 ] == 0 ) prec -- ;
2656
+ c .real -> Prec = prec ;
2657
+ c .real -> sign = a .real -> sign ;
2658
+ c .real -> exponent = a .real -> exponent ;
2659
+ AddExponent (c .real , exponentShift );
2660
+ RB_GC_GUARD (a .bigdecimal );
2661
+ return CheckGetValue (c );
2662
+ }
2663
+
2606
2664
inline static int
2607
2665
is_zero (VALUE x )
2608
2666
{
@@ -3724,6 +3782,7 @@ Init_bigdecimal(void)
3724
3782
rb_define_method (rb_cBigDecimal , "infinite?" , BigDecimal_IsInfinite , 0 );
3725
3783
rb_define_method (rb_cBigDecimal , "finite?" , BigDecimal_IsFinite , 0 );
3726
3784
rb_define_method (rb_cBigDecimal , "truncate" , BigDecimal_truncate , -1 );
3785
+ rb_define_method (rb_cBigDecimal , "_decimal_shift" , BigDecimal_decimal_shift , 1 );
3727
3786
rb_define_method (rb_cBigDecimal , "_dump" , BigDecimal_dump , -1 );
3728
3787
3729
3788
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
@@ -3784,7 +3843,6 @@ enum op_sw {
3784
3843
};
3785
3844
3786
3845
static int VpIsDefOP (Real * c , Real * a , Real * b , enum op_sw sw );
3787
- static int AddExponent (Real * a , SIGNED_VALUE n );
3788
3846
static DECDIG VpAddAbs (Real * a ,Real * b ,Real * c );
3789
3847
static DECDIG VpSubAbs (Real * a ,Real * b ,Real * c );
3790
3848
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