From 100931ac2cc3b5c4e0c4dec9d91061de9e09f3da Mon Sep 17 00:00:00 2001 From: mrkn Date: Tue, 31 May 2011 14:43:39 +0000 Subject: * 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31864 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/bigdecimal/bigdecimal.c | 107 +++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 41 deletions(-) (limited to 'ext/bigdecimal') diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index 45dac45645..cd960f4b87 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -131,11 +131,13 @@ ToValue(Real *p) 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,54 +145,71 @@ GetVpValue(VALUE v, int must) 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; + + 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; + } - 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); + 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: @@ -1775,6 +1794,12 @@ BigDecimal_new(int argc, VALUE *argv, VALUE self) 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: -- cgit v1.2.3