1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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
This commit is contained in:
mrkn 2011-05-31 14:43:39 +00:00
parent b54141bb1b
commit 100931ac2c
3 changed files with 94 additions and 41 deletions

View file

@ -1,3 +1,19 @@
Tue May 31 23:43:00 2011 Kenta Murata <mrkn@mrkn.jp>
* 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@mrkn.jp>
* ext/bigdecimal/bigdecimal.c (BigDecimal_new): support instantiation a

View file

@ -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;
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:
@ -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:

View file

@ -36,6 +36,12 @@ class TestBigDecimal < Test::Unit::TestCase
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 @@ class TestBigDecimal < Test::Unit::TestCase
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 }