ruby-changes:19818
From: mrkn <ko1@a...>
Date: Tue, 31 May 2011 23:44:23 +0900 (JST)
Subject: [ruby-changes:19818] mrkn:r31864 (trunk): * ext/bigdecimal/bigdecimal.c (GetVpValueWithPrec): replace the algorithm for
mrkn 2011-05-31 23:43:39 +0900 (Tue, 31 May 2011) New Revision: 31864 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=31864 Log: * ext/bigdecimal/bigdecimal.c (GetVpValueWithPrec): replace the algorithm for coercing from a Rational to stop requiring "bigecimal/util.rb". [ruby-core:34318] * ext/bigdecimal/bigdecimal.c (GetVpValue): refactoring. * ext/bigdecimal/bigdecimal.c (BigDecimal_new): support instantiation from a Rational. * test/bigdecimal/test_bigdecimal.rb (test_global_new_with_rationao): add a test for the above change. * test/bigdecimal/test_bigdecimal.rb (test_new_with_rationao): ditto. Modified files: trunk/ChangeLog trunk/ext/bigdecimal/bigdecimal.c trunk/test/bigdecimal/test_bigdecimal.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 31863) +++ ChangeLog (revision 31864) @@ -1,3 +1,19 @@ +Tue May 31 23:43:00 2011 Kenta Murata <mrkn@m...> + + * ext/bigdecimal/bigdecimal.c (GetVpValueWithPrec): replace the algorithm for + coercing from a Rational to stop requiring "bigecimal/util.rb". + [ruby-core:34318] + + * ext/bigdecimal/bigdecimal.c (GetVpValue): refactoring. + + * ext/bigdecimal/bigdecimal.c (BigDecimal_new): support instantiation from a + Rational. + + * test/bigdecimal/test_bigdecimal.rb (test_global_new_with_rationao): add a + test for the above change. + + * test/bigdecimal/test_bigdecimal.rb (test_new_with_rationao): ditto. + Tue May 31 22:44:00 2011 Kenta Murata <mrkn@m...> * ext/bigdecimal/bigdecimal.c (BigDecimal_new): support instantiation a Index: ext/bigdecimal/bigdecimal.c =================================================================== --- ext/bigdecimal/bigdecimal.c (revision 31863) +++ ext/bigdecimal/bigdecimal.c (revision 31864) @@ -131,11 +131,13 @@ return p->obj; } -static Real * -GetVpValue(VALUE v, int must) +static VALUE BigDecimal_div2(int, VALUE*, VALUE); + +static Real* +GetVpValueWithPrec(VALUE v, long prec, int must) { Real *pv; - VALUE bg; + VALUE num, bg, args[2]; char szD[128]; VALUE orig = Qundef; int util_loaded = 0; @@ -143,56 +145,73 @@ again: switch(TYPE(v)) { - case T_RATIONAL: - if(orig == Qundef ? (orig = v, 1) : orig != v) { - if(!util_loaded) { - rb_require("bigdecimal/util"); - util_loaded = 1; - } - v = rb_funcall2(v, rb_intern("to_d"), 0, 0); - goto again; - } - v = orig; - goto SomeOneMayDoIt; + case T_RATIONAL: + if (prec < 0) goto unable_to_coerce_without_prec; - case T_DATA: - if(rb_typeddata_is_kind_of(v, &BigDecimal_data_type)) { - pv = DATA_PTR(v); - return pv; - } else { - goto SomeOneMayDoIt; - } - break; - case T_FIXNUM: - sprintf(szD, "%ld", FIX2LONG(v)); - return VpCreateRbObject(VpBaseFig() * 2 + 1, szD); + if (orig == Qundef ? (orig = v, 1) : orig != v) { + num = RRATIONAL(v)->num; + pv = GetVpValueWithPrec(num, -1, must); + if (pv == NULL) goto SomeOneMayDoIt; + args[0] = RRATIONAL(v)->den; + args[1] = LONG2NUM(prec); + v = BigDecimal_div2(2, args, ToValue(pv)); + goto again; + } + + v = orig; + goto SomeOneMayDoIt; + + case T_DATA: + if (rb_typeddata_is_kind_of(v, &BigDecimal_data_type)) { + pv = DATA_PTR(v); + return pv; + } + else { + goto SomeOneMayDoIt; + } + break; + case T_FIXNUM: + sprintf(szD, "%ld", FIX2LONG(v)); + return VpCreateRbObject(VpBaseFig() * 2 + 1, szD); + #ifdef ENABLE_NUMERIC_STRING - case T_STRING: - SafeStringValue(v); - return VpCreateRbObject(strlen(RSTRING_PTR(v)) + VpBaseFig() + 1, - RSTRING_PTR(v)); + case T_STRING: + SafeStringValue(v); + return VpCreateRbObject(strlen(RSTRING_PTR(v)) + VpBaseFig() + 1, + RSTRING_PTR(v)); #endif /* ENABLE_NUMERIC_STRING */ - case T_BIGNUM: - bg = rb_big2str(v, 10); - return VpCreateRbObject(strlen(RSTRING_PTR(bg)) + VpBaseFig() + 1, - RSTRING_PTR(bg)); - default: - goto SomeOneMayDoIt; + case T_BIGNUM: + bg = rb_big2str(v, 10); + return VpCreateRbObject(strlen(RSTRING_PTR(bg)) + VpBaseFig() + 1, + RSTRING_PTR(bg)); + default: + goto SomeOneMayDoIt; } SomeOneMayDoIt: - if(must) { - rb_raise(rb_eTypeError, "%s can't be coerced into BigDecimal", - rb_special_const_p(v)? - RSTRING_PTR(rb_inspect(v)): - rb_obj_classname(v) - ); + if (must) { + rb_raise(rb_eTypeError, "%s can't be coerced into BigDecimal", + rb_special_const_p(v) ? RSTRING_PTR(rb_inspect(v)) : rb_obj_classname(v)); } return NULL; /* NULL means to coerce */ + +unable_to_coerce_without_prec: + if (must) { + rb_raise(rb_eArgError, + "%s can't be coerced into BigDecimal without a precision", + rb_obj_classname(v)); + } + return NULL; } +static Real* +GetVpValue(VALUE v, int must) +{ + return GetVpValueWithPrec(v, -1, must); +} + /* call-seq: * BigDecimal.double_fig * @@ -1775,6 +1794,12 @@ case T_BIGNUM: return ToValue(GetVpValue(iniValue, 1)); + case T_RATIONAL: + if (NIL_P(nFig)) { + rb_raise(rb_eArgError, "can't omit precision for a Rational."); + } + return ToValue(GetVpValueWithPrec(iniValue, mf, 1)); + case T_STRING: /* fall through */ default: Index: test/bigdecimal/test_bigdecimal.rb =================================================================== --- test/bigdecimal/test_bigdecimal.rb (revision 31863) +++ test/bigdecimal/test_bigdecimal.rb (revision 31864) @@ -36,6 +36,12 @@ assert_equal(BigDecimal((-2**100).to_s), BigDecimal(-2**100)) end + def test_global_new_with_rational + assert_equal(BigDecimal("0.333333333333333333333"), BigDecimal(1.quo(3), 21)) + assert_equal(BigDecimal("-0.333333333333333333333"), BigDecimal(-1.quo(3), 21)) + assert_raise(ArgumentError) { BigDecimal(1.quo(3)) } + end + def test_new assert_equal(1, BigDecimal.new("1")) assert_equal(1, BigDecimal.new("1", 1)) @@ -58,6 +64,12 @@ assert_equal(BigDecimal((-2**100).to_s), BigDecimal.new(-2**100)) end + def test_new_with_rational + assert_equal(BigDecimal("0.333333333333333333333"), BigDecimal.new(1.quo(3), 21)) + assert_equal(BigDecimal("-0.333333333333333333333"), BigDecimal.new(-1.quo(3), 21)) + assert_raise(ArgumentError) { BigDecimal.new(1.quo(3)) } + end + def _test_mode(type) BigDecimal.mode(type, true) assert_raise(FloatDomainError) { yield } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/