@@ -1823,7 +1823,7 @@ BigDecimal_mult(VALUE self, VALUE r)
18231823 return VpCheckGetValue (c );
18241824}
18251825
1826- static VALUE BigDecimal_DoDivmod (VALUE self , VALUE r , Real * * div , Real * * mod );
1826+ static VALUE BigDecimal_DoDivmod (VALUE self , VALUE r , Real * * div , Real * * mod , bool truncate );
18271827
18281828/* call-seq:
18291829 * a / b -> bigdecimal
@@ -1893,9 +1893,10 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
18931893/*
18941894 * %: mod = a%b = a - (a.to_f/b).floor * b
18951895 * div = (a.to_f/b).floor
1896+ * In truncate mode, use truncate instead of floor.
18961897 */
18971898static VALUE
1898- BigDecimal_DoDivmod (VALUE self , VALUE r , Real * * div , Real * * mod )
1899+ BigDecimal_DoDivmod (VALUE self , VALUE r , Real * * div , Real * * mod , bool truncate )
18991900{
19001901 ENTER (8 );
19011902 Real * c = NULL , * d = NULL , * res = NULL ;
@@ -1978,7 +1979,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
19781979 VpMult (res , d , b );
19791980 VpAddSub (c , a , res , -1 );
19801981
1981- if (!VpIsZero (c ) && (VpGetSign (a ) * VpGetSign (b ) < 0 )) {
1982+ if (!truncate && ! VpIsZero (c ) && (VpGetSign (a ) * VpGetSign (b ) < 0 )) {
19821983 /* result adjustment for negative case */
19831984 res = rbd_reallocate_struct (res , d -> MaxPrec );
19841985 res -> MaxPrec = d -> MaxPrec ;
@@ -2017,66 +2018,13 @@ BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
20172018 ENTER (3 );
20182019 Real * div = NULL , * mod = NULL ;
20192020
2020- if (BigDecimal_DoDivmod (self , r , & div , & mod )) {
2021- SAVE (div ); SAVE (mod );
2021+ if (BigDecimal_DoDivmod (self , r , & div , & mod , false )) {
2022+ SAVE (div ); SAVE (mod );
20222023 return VpCheckGetValue (mod );
20232024 }
20242025 return DoSomeOne (self , r , '%' );
20252026}
20262027
2027- static VALUE
2028- BigDecimal_divremain (VALUE self , VALUE r , Real * * dv , Real * * rv )
2029- {
2030- ENTER (10 );
2031- size_t mx ;
2032- Real * a = NULL , * b = NULL , * c = NULL , * res = NULL , * d = NULL , * rr = NULL , * ff = NULL ;
2033- Real * f = NULL ;
2034-
2035- GUARD_OBJ (a , GetVpValue (self , 1 ));
2036- if (RB_TYPE_P (r , T_FLOAT )) {
2037- b = GetVpValueWithPrec (r , 0 , 1 );
2038- }
2039- else if (RB_TYPE_P (r , T_RATIONAL )) {
2040- b = GetVpValueWithPrec (r , a -> Prec * VpBaseFig (), 1 );
2041- }
2042- else {
2043- b = GetVpValue (r , 0 );
2044- }
2045-
2046- if (!b ) return Qfalse ;
2047- SAVE (b );
2048-
2049- if (VpIsPosInf (b ) || VpIsNegInf (b )) {
2050- GUARD_OBJ (* dv , NewZeroWrapLimited (1 , 1 ));
2051- VpSetZero (* dv , 1 );
2052- * rv = a ;
2053- return Qtrue ;
2054- }
2055-
2056- mx = (a -> MaxPrec + b -> MaxPrec ) * VpBaseFig ();
2057- GUARD_OBJ (c , NewZeroWrapLimited (1 , mx ));
2058- GUARD_OBJ (res , NewZeroWrapNolimit (1 , (mx + 1 ) * 2 + (VpBaseFig () + 1 )));
2059- GUARD_OBJ (rr , NewZeroWrapNolimit (1 , (mx + 1 ) * 2 + (VpBaseFig () + 1 )));
2060- GUARD_OBJ (ff , NewZeroWrapNolimit (1 , (mx + 1 ) * 2 + (VpBaseFig () + 1 )));
2061-
2062- VpDivd (c , res , a , b );
2063-
2064- mx = c -> Prec * (VpBaseFig () + 1 );
2065-
2066- GUARD_OBJ (d , NewZeroWrapLimited (1 , mx ));
2067- GUARD_OBJ (f , NewZeroWrapLimited (1 , mx ));
2068-
2069- VpActiveRound (d , c , VP_ROUND_DOWN , 0 ); /* 0: round off */
2070-
2071- VpFrac (f , c );
2072- VpMult (rr , f , b );
2073- VpAddSub (ff , res , rr , 1 );
2074-
2075- * dv = d ;
2076- * rv = ff ;
2077- return Qtrue ;
2078- }
2079-
20802028/* call-seq:
20812029 * remainder(value)
20822030 *
@@ -2087,9 +2035,12 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
20872035static VALUE
20882036BigDecimal_remainder (VALUE self , VALUE r ) /* remainder */
20892037{
2090- Real * d , * rv = 0 ;
2091- if (BigDecimal_divremain (self , r , & d , & rv )) {
2092- return VpCheckGetValue (rv );
2038+ ENTER (3 );
2039+ Real * div = NULL , * mod = NULL ;
2040+
2041+ if (BigDecimal_DoDivmod (self , r , & div , & mod , true)) {
2042+ SAVE (div ); SAVE (mod );
2043+ return VpCheckGetValue (mod );
20932044 }
20942045 return DoSomeOne (self , r , rb_intern ("remainder" ));
20952046}
@@ -2122,7 +2073,7 @@ BigDecimal_divmod(VALUE self, VALUE r)
21222073 ENTER (5 );
21232074 Real * div = NULL , * mod = NULL ;
21242075
2125- if (BigDecimal_DoDivmod (self , r , & div , & mod )) {
2076+ if (BigDecimal_DoDivmod (self , r , & div , & mod , false )) {
21262077 SAVE (div ); SAVE (mod );
21272078 return rb_assoc_new (VpCheckGetValue (div ), VpCheckGetValue (mod ));
21282079 }
@@ -2145,7 +2096,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
21452096 if (NIL_P (n )) { /* div in Float sense */
21462097 Real * div = NULL ;
21472098 Real * mod ;
2148- if (BigDecimal_DoDivmod (self , b , & div , & mod )) {
2099+ if (BigDecimal_DoDivmod (self , b , & div , & mod , false )) {
21492100 return BigDecimal_to_i (VpCheckGetValue (div ));
21502101 }
21512102 return DoSomeOne (self , b , rb_intern ("div" ));
0 commit comments