mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/bigdecimal/bigdecimal.c (BigDecimal_power): support non-integral
exponent. fixes #3271 * ext/bigdecimal/bigdecimal.c (rmpd_power_by_big_decimal): ditto. * ext/bigdecimal/bigdecimal.c (BigDecimal_power_op): add a function to only use for "**" operator. * test/bigdecimal/test_bigdecimal.rb: add a bunch of tests for the above changes. * ext/bigdecimal/bigdecimal.c (is_integer): add an utility function. * ext/bigdecimal/bigdecimal.c (is_negative): ditto. * ext/bigdecimal/bigdecimal.c (is_positive): ditto. * ext/bigdecimal/bigdecimal.c (is_zero): ditto. * ext/bigdecimal/bigdecimal.c (is_one): ditto. * ext/bigdecimal/bigdecimal.c (is_even): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@32485 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
b88daae7ec
commit
ebd61e5f28
3 changed files with 547 additions and 34 deletions
25
ChangeLog
25
ChangeLog
|
@ -1,3 +1,28 @@
|
||||||
|
Sun Jul 10 12:18:00 2011 Kenta Murata <mrkn@mrkn.jp>
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (BigDecimal_power): support non-integral
|
||||||
|
exponent. fixes [Bug #3271]
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (rmpd_power_by_big_decimal): ditto.
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (BigDecimal_power_op): add a function to
|
||||||
|
only use for "**" operator.
|
||||||
|
|
||||||
|
* test/bigdecimal/test_bigdecimal.rb: add a bunch of tests for the
|
||||||
|
above changes.
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (is_integer): add an utility function.
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (is_negative): ditto.
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (is_positive): ditto.
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (is_zero): ditto.
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (is_one): ditto.
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (is_even): ditto.
|
||||||
|
|
||||||
Sun Jul 10 12:08:39 2011 Yusuke Endoh <mame@tsg.ne.jp>
|
Sun Jul 10 12:08:39 2011 Yusuke Endoh <mame@tsg.ne.jp>
|
||||||
|
|
||||||
* compile.c (when_vals): when a string literal is written on when
|
* compile.c (when_vals): when a string literal is written on when
|
||||||
|
|
|
@ -52,6 +52,7 @@ static ID id_ceiling;
|
||||||
static ID id_ceil;
|
static ID id_ceil;
|
||||||
static ID id_floor;
|
static ID id_floor;
|
||||||
static ID id_to_r;
|
static ID id_to_r;
|
||||||
|
static ID id_eq;
|
||||||
|
|
||||||
/* MACRO's to guard objects from GC by keeping them in stack */
|
/* MACRO's to guard objects from GC by keeping them in stack */
|
||||||
#define ENTER(n) volatile VALUE vStack[n];int iStack=0
|
#define ENTER(n) volatile VALUE vStack[n];int iStack=0
|
||||||
|
@ -1834,28 +1835,331 @@ BigDecimal_inspect(VALUE self)
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
|
||||||
|
static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
|
||||||
|
|
||||||
|
#define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
|
||||||
|
#define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
|
||||||
|
|
||||||
|
inline static int
|
||||||
|
is_integer(VALUE x)
|
||||||
|
{
|
||||||
|
return (TYPE(x) == T_FIXNUM || TYPE(x) == T_BIGNUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static int
|
||||||
|
is_negative(VALUE x)
|
||||||
|
{
|
||||||
|
if (FIXNUM_P(x)) {
|
||||||
|
return FIX2LONG(x) < 0;
|
||||||
|
}
|
||||||
|
else if (TYPE(x) == T_BIGNUM) {
|
||||||
|
return RBIGNUM_NEGATIVE_P(x);
|
||||||
|
}
|
||||||
|
else if (TYPE(x) == T_FLOAT) {
|
||||||
|
return RFLOAT_VALUE(x) < 0.0;
|
||||||
|
}
|
||||||
|
return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define is_positive(x) (!is_negative(x))
|
||||||
|
|
||||||
|
inline static int
|
||||||
|
is_zero(VALUE x)
|
||||||
|
{
|
||||||
|
VALUE num;
|
||||||
|
|
||||||
|
switch (TYPE(x)) {
|
||||||
|
case T_FIXNUM:
|
||||||
|
return FIX2LONG(x) == 0;
|
||||||
|
|
||||||
|
case T_BIGNUM:
|
||||||
|
return Qfalse;
|
||||||
|
|
||||||
|
case T_RATIONAL:
|
||||||
|
num = RRATIONAL(x)->num;
|
||||||
|
return FIXNUM_P(num) && FIX2LONG(num) == 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static int
|
||||||
|
is_one(VALUE x)
|
||||||
|
{
|
||||||
|
VALUE num, den;
|
||||||
|
|
||||||
|
switch (TYPE(x)) {
|
||||||
|
case T_FIXNUM:
|
||||||
|
return FIX2LONG(x) == 1;
|
||||||
|
|
||||||
|
case T_BIGNUM:
|
||||||
|
return Qfalse;
|
||||||
|
|
||||||
|
case T_RATIONAL:
|
||||||
|
num = RRATIONAL(x)->num;
|
||||||
|
den = RRATIONAL(x)->den;
|
||||||
|
return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
|
||||||
|
FIXNUM_P(num) && FIX2LONG(num) == 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static int
|
||||||
|
is_even(VALUE x)
|
||||||
|
{
|
||||||
|
switch (TYPE(x)) {
|
||||||
|
case T_FIXNUM:
|
||||||
|
return (FIX2LONG(x) % 2) == 0;
|
||||||
|
|
||||||
|
case T_BIGNUM:
|
||||||
|
return (RBIGNUM_DIGITS(x)[0] % 2) == 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rmpd_power_by_big_decimal(Real const* x, Real const* exp, ssize_t const n)
|
||||||
|
{
|
||||||
|
VALUE log_x, multiplied, y;
|
||||||
|
|
||||||
|
if (VpIsZero(exp)) {
|
||||||
|
return ToValue(VpCreateRbObject(n, "1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
log_x = BigMath_log(x->obj, n);
|
||||||
|
multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n));
|
||||||
|
y = BigMath_exp(multiplied, n);
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
/* call-seq:
|
/* call-seq:
|
||||||
* power(n)
|
* power(n)
|
||||||
|
* power(n, prec)
|
||||||
*
|
*
|
||||||
* Returns the value raised to the power of n. Note that n must be an Integer.
|
* Returns the value raised to the power of n. Note that n must be an Integer.
|
||||||
*
|
*
|
||||||
* Also available as the operator **
|
* Also available as the operator **
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
BigDecimal_power(VALUE self, VALUE p)
|
BigDecimal_power(VALUE self, VALUE vexp, VALUE prec)
|
||||||
{
|
{
|
||||||
ENTER(5);
|
ENTER(5);
|
||||||
|
Real* exp = NULL;
|
||||||
Real *x, *y;
|
Real *x, *y;
|
||||||
ssize_t mp, ma;
|
ssize_t mp, ma, n;
|
||||||
SIGNED_VALUE n;
|
SIGNED_VALUE int_exp;
|
||||||
|
double d;
|
||||||
|
|
||||||
Check_Type(p, T_FIXNUM);
|
GUARD_OBJ(x, GetVpValue(self, 1));
|
||||||
n = FIX2INT(p);
|
n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
|
||||||
ma = n;
|
|
||||||
|
if (VpIsNaN(x)) {
|
||||||
|
y = VpCreateRbObject(n, "0#");
|
||||||
|
RB_GC_GUARD(y->obj);
|
||||||
|
VpSetNaN(y);
|
||||||
|
return ToValue(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
|
switch (TYPE(vexp)) {
|
||||||
|
case T_FIXNUM:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_BIGNUM:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_FLOAT:
|
||||||
|
d = RFLOAT_VALUE(vexp);
|
||||||
|
if (d == round(d)) {
|
||||||
|
vexp = LL2NUM((LONG_LONG)round(d));
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
exp = GetVpValueWithPrec(vexp, DBL_DIG+1, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_RATIONAL:
|
||||||
|
if (is_zero(RRATIONAL(vexp)->num)) {
|
||||||
|
if (is_positive(vexp)) {
|
||||||
|
vexp = INT2FIX(0);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (is_one(RRATIONAL(vexp)->den)) {
|
||||||
|
vexp = RRATIONAL(vexp)->num;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
exp = GetVpValueWithPrec(vexp, n, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_DATA:
|
||||||
|
if (is_kind_of_BigDecimal(vexp)) {
|
||||||
|
VALUE zero = INT2FIX(0);
|
||||||
|
VALUE rounded = BigDecimal_round(1, &zero, vexp);
|
||||||
|
if (RTEST(BigDecimal_eq(vexp, rounded))) {
|
||||||
|
vexp = BigDecimal_to_i(vexp);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
exp = DATA_PTR(vexp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
rb_raise(rb_eTypeError,
|
||||||
|
"wrong argument type %s (expected scalar Numeric)",
|
||||||
|
rb_obj_classname(vexp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VpIsZero(x)) {
|
||||||
|
if (is_negative(vexp)) {
|
||||||
|
y = VpCreateRbObject(n, "#0");
|
||||||
|
RB_GC_GUARD(y->obj);
|
||||||
|
if (VpGetSign(x) < 0) {
|
||||||
|
if (is_integer(vexp)) {
|
||||||
|
if (is_even(vexp)) {
|
||||||
|
/* (-0) ** (-even_integer) -> Infinity */
|
||||||
|
VpSetPosInf(y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* (-0) ** (-odd_integer) -> -Infinity */
|
||||||
|
VpSetNegInf(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* (-0) ** (-non_integer) -> Infinity */
|
||||||
|
VpSetPosInf(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* (+0) ** (-num) -> Infinity */
|
||||||
|
VpSetPosInf(y);
|
||||||
|
}
|
||||||
|
return ToValue(y);
|
||||||
|
}
|
||||||
|
else if (is_zero(vexp)) {
|
||||||
|
return ToValue(VpCreateRbObject(n, "1"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ToValue(VpCreateRbObject(n, "0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_zero(vexp)) {
|
||||||
|
return ToValue(VpCreateRbObject(n, "1"));
|
||||||
|
}
|
||||||
|
else if (is_one(vexp)) {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VpIsInf(x)) {
|
||||||
|
if (is_negative(vexp)) {
|
||||||
|
if (VpGetSign(x) < 0) {
|
||||||
|
if (is_integer(vexp)) {
|
||||||
|
if (is_even(vexp)) {
|
||||||
|
/* (-Infinity) ** (-even_integer) -> +0 */
|
||||||
|
return ToValue(VpCreateRbObject(n, "0"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* (-Infinity) ** (-odd_integer) -> -0 */
|
||||||
|
return ToValue(VpCreateRbObject(n, "-0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* (-Infinity) ** (-non_integer) -> -0 */
|
||||||
|
return ToValue(VpCreateRbObject(n, "-0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ToValue(VpCreateRbObject(n, "0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
y = VpCreateRbObject(n, "0#");
|
||||||
|
if (VpGetSign(x) < 0) {
|
||||||
|
if (is_integer(vexp)) {
|
||||||
|
if (is_even(vexp)) {
|
||||||
|
VpSetPosInf(y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VpSetNegInf(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* TODO: support complex */
|
||||||
|
rb_raise(rb_eMathDomainError,
|
||||||
|
"a non-integral exponent for a negative base");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VpSetPosInf(y);
|
||||||
|
}
|
||||||
|
return ToValue(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp != NULL) {
|
||||||
|
return rmpd_power_by_big_decimal(x, exp, n);
|
||||||
|
}
|
||||||
|
else if (TYPE(vexp) == T_BIGNUM) {
|
||||||
|
VALUE abs_value = BigDecimal_abs(self);
|
||||||
|
if (is_one(abs_value)) {
|
||||||
|
return ToValue(VpCreateRbObject(n, "1"));
|
||||||
|
}
|
||||||
|
else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
|
||||||
|
if (is_negative(vexp)) {
|
||||||
|
y = VpCreateRbObject(n, "0#");
|
||||||
|
if (is_even(vexp)) {
|
||||||
|
VpSetInf(y, VpGetSign(x));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VpSetInf(y, -VpGetSign(x));
|
||||||
|
}
|
||||||
|
return ToValue(y);
|
||||||
|
}
|
||||||
|
else if (VpGetSign(x) < 0 && is_even(vexp)) {
|
||||||
|
return ToValue(VpCreateRbObject(n, "-0"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ToValue(VpCreateRbObject(n, "0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (is_positive(vexp)) {
|
||||||
|
y = VpCreateRbObject(n, "0#");
|
||||||
|
if (is_even(vexp)) {
|
||||||
|
VpSetInf(y, VpGetSign(x));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VpSetInf(y, -VpGetSign(x));
|
||||||
|
}
|
||||||
|
return ToValue(y);
|
||||||
|
}
|
||||||
|
else if (VpGetSign(x) < 0 && is_even(vexp)) {
|
||||||
|
return ToValue(VpCreateRbObject(n, "-0"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ToValue(VpCreateRbObject(n, "0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int_exp = FIX2INT(vexp);
|
||||||
|
ma = int_exp;
|
||||||
if (ma < 0) ma = -ma;
|
if (ma < 0) ma = -ma;
|
||||||
if (ma == 0) ma = 1;
|
if (ma == 0) ma = 1;
|
||||||
|
|
||||||
GUARD_OBJ(x, GetVpValue(self, 1));
|
|
||||||
if (VpIsDef(x)) {
|
if (VpIsDef(x)) {
|
||||||
mp = x->Prec * (VpBaseFig() + 1);
|
mp = x->Prec * (VpBaseFig() + 1);
|
||||||
GUARD_OBJ(y, VpCreateRbObject(mp * (ma + 1), "0"));
|
GUARD_OBJ(y, VpCreateRbObject(mp * (ma + 1), "0"));
|
||||||
|
@ -1863,10 +2167,21 @@ BigDecimal_power(VALUE self, VALUE p)
|
||||||
else {
|
else {
|
||||||
GUARD_OBJ(y, VpCreateRbObject(1, "0"));
|
GUARD_OBJ(y, VpCreateRbObject(1, "0"));
|
||||||
}
|
}
|
||||||
VpPower(y, x, n);
|
VpPower(y, x, int_exp);
|
||||||
return ToValue(y);
|
return ToValue(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* call-seq:
|
||||||
|
* big_decimal ** exp -> big_decimal
|
||||||
|
*
|
||||||
|
* It is a synonym of big_decimal.power(exp).
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
BigDecimal_power_op(VALUE self, VALUE exp)
|
||||||
|
{
|
||||||
|
return BigDecimal_power(self, exp, Qnil);
|
||||||
|
}
|
||||||
|
|
||||||
/* call-seq:
|
/* call-seq:
|
||||||
* new(initial, digits)
|
* new(initial, digits)
|
||||||
*
|
*
|
||||||
|
@ -2595,8 +2910,8 @@ Init_bigdecimal(void)
|
||||||
rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
|
rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
|
||||||
rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
|
rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
|
||||||
rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
|
rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
|
||||||
rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, 1);
|
rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, 2);
|
||||||
rb_define_method(rb_cBigDecimal, "**", BigDecimal_power, 1);
|
rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
|
||||||
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
|
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
|
||||||
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
|
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
|
||||||
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
|
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
|
||||||
|
@ -2638,6 +2953,7 @@ Init_bigdecimal(void)
|
||||||
id_ceil = rb_intern_const("ceil");
|
id_ceil = rb_intern_const("ceil");
|
||||||
id_floor = rb_intern_const("floor");
|
id_floor = rb_intern_const("floor");
|
||||||
id_to_r = rb_intern_const("to_r");
|
id_to_r = rb_intern_const("to_r");
|
||||||
|
id_eq = rb_intern_const("==");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3963,7 +4279,7 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
||||||
VpAsgn(c, a, VpGetSign(b));
|
VpAsgn(c, a, VpGetSign(b));
|
||||||
VpSetZero(r,VpGetSign(a));
|
VpSetZero(r,VpGetSign(a));
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
word_a = a->Prec;
|
word_a = a->Prec;
|
||||||
word_b = b->Prec;
|
word_b = b->Prec;
|
||||||
|
|
|
@ -19,6 +19,30 @@ class TestBigDecimal < Test::Unit::TestCase
|
||||||
[ BigDecimal::ROUND_FLOOR, :floor],
|
[ BigDecimal::ROUND_FLOOR, :floor],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def assert_nan(x)
|
||||||
|
assert(x.nan?, "Expected #{x.inspect} to be NaN")
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_positive_infinite(x)
|
||||||
|
assert(x.infinite?, "Expected #{x.inspect} to be positive infinite")
|
||||||
|
assert_operator(x, :>, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_negative_infinite(x)
|
||||||
|
assert(x.infinite?, "Expected #{x.inspect} to be negative infinite")
|
||||||
|
assert_operator(x, :<, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_positive_zero(x)
|
||||||
|
assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, x.sign,
|
||||||
|
"Expected #{x.inspect} to be positive zero")
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_negative_zero(x)
|
||||||
|
assert_equal(BigDecimal::SIGN_NEGATIVE_ZERO, x.sign,
|
||||||
|
"Expected #{x.inspect} to be negative zero")
|
||||||
|
end
|
||||||
|
|
||||||
def test_version
|
def test_version
|
||||||
assert_equal("1.0.1", BigDecimal.ver)
|
assert_equal("1.0.1", BigDecimal.ver)
|
||||||
end
|
end
|
||||||
|
@ -764,32 +788,180 @@ class TestBigDecimal < Test::Unit::TestCase
|
||||||
assert_match(/^#<BigDecimal:[0-9a-f]+,'0.12345678E4',#{prec}\(#{maxprec}\)>$/, x.inspect)
|
assert_match(/^#<BigDecimal:[0-9a-f]+,'0.12345678E4',#{prec}\(#{maxprec}\)>$/, x.inspect)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_power
|
def test_power_with_nil
|
||||||
x = BigDecimal.new("3")
|
assert_raise(TypeError) do
|
||||||
assert_equal(81, x ** 4)
|
BigDecimal(3) ** nil
|
||||||
assert_equal(1.0/81, (x ** -4).to_f)
|
end
|
||||||
assert_equal(1.quo(81), x ** -4)
|
end
|
||||||
|
|
||||||
|
def test_power_of_nan
|
||||||
|
BigDecimal.save_exception_mode do
|
||||||
|
BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)
|
||||||
|
assert_nan(BigDecimal::NAN ** 0)
|
||||||
|
assert_nan(BigDecimal::NAN ** 1)
|
||||||
|
assert_nan(BigDecimal::NAN ** 42)
|
||||||
|
assert_nan(BigDecimal::NAN ** -42)
|
||||||
|
assert_nan(BigDecimal::NAN ** 42.0)
|
||||||
|
assert_nan(BigDecimal::NAN ** -42.0)
|
||||||
|
assert_nan(BigDecimal::NAN ** BigDecimal(42))
|
||||||
|
assert_nan(BigDecimal::NAN ** BigDecimal(-42))
|
||||||
|
assert_nan(BigDecimal::NAN ** BigDecimal::INFINITY)
|
||||||
|
BigDecimal.save_exception_mode do
|
||||||
|
BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, false)
|
||||||
|
assert_nan(BigDecimal::NAN ** (-BigDecimal::INFINITY))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_power_with_Bignum
|
||||||
|
BigDecimal.save_exception_mode do
|
||||||
|
BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, false)
|
||||||
|
assert_equal(0, BigDecimal(0) ** (2**100))
|
||||||
|
|
||||||
|
assert_positive_infinite(BigDecimal(0) ** -(2**100))
|
||||||
|
assert_positive_infinite((-BigDecimal(0)) ** -(2**100))
|
||||||
|
assert_negative_infinite((-BigDecimal(0)) ** -(2**100 + 1))
|
||||||
|
|
||||||
|
assert_equal(1, BigDecimal(1) ** (2**100))
|
||||||
|
|
||||||
|
assert_positive_infinite(BigDecimal(3) ** (2**100))
|
||||||
|
assert_positive_zero(BigDecimal(3) ** (-2**100))
|
||||||
|
|
||||||
|
assert_negative_infinite(BigDecimal(-3) ** (2**100))
|
||||||
|
assert_positive_infinite(BigDecimal(-3) ** (2**100 + 1))
|
||||||
|
assert_negative_zero(BigDecimal(-3) ** (-2**100))
|
||||||
|
assert_positive_zero(BigDecimal(-3) ** (-2**100 - 1))
|
||||||
|
|
||||||
|
assert_positive_zero(BigDecimal(0.5, Float::DIG) ** (2**100))
|
||||||
|
assert_positive_infinite(BigDecimal(0.5, Float::DIG) ** (-2**100))
|
||||||
|
|
||||||
|
assert_negative_zero(BigDecimal(-0.5, Float::DIG) ** (2**100))
|
||||||
|
assert_positive_zero(BigDecimal(-0.5, Float::DIG) ** (2**100 - 1))
|
||||||
|
assert_negative_infinite(BigDecimal(-0.5, Float::DIG) ** (-2**100))
|
||||||
|
assert_positive_infinite(BigDecimal(-0.5, Float::DIG) ** (-2**100 - 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_power_with_BigDecimal
|
||||||
|
assert_nothing_raised do
|
||||||
|
assert_in_delta(3 ** 3, BigDecimal(3) ** BigDecimal(3))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_power_of_finite_with_zero
|
||||||
|
x = BigDecimal(1)
|
||||||
assert_equal(1, x ** 0)
|
assert_equal(1, x ** 0)
|
||||||
assert_raise(TypeError) { x ** x }
|
assert_equal(1, x ** 0.quo(1))
|
||||||
assert_equal(0, BigDecimal.new("0") ** 4)
|
assert_equal(1, x ** 0.0)
|
||||||
assert_equal(1, BigDecimal.new("0") ** 0)
|
assert_equal(1, x ** BigDecimal(0))
|
||||||
BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
|
|
||||||
assert_equal(BigDecimal.new("Infinity"), BigDecimal.new("0") ** -1)
|
|
||||||
assert_equal(BigDecimal.new("-Infinity"), BigDecimal.new("-0") ** -1)
|
|
||||||
BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)
|
|
||||||
assert_equal(true, (BigDecimal.new("NaN") ** 1).nan?)
|
|
||||||
|
|
||||||
assert_equal(BigDecimal::SIGN_POSITIVE_INFINITE, (BigDecimal.new("Infinity") ** 2).sign)
|
x = BigDecimal(42)
|
||||||
assert_equal(BigDecimal::SIGN_POSITIVE_INFINITE, (BigDecimal.new("Infinity") ** 1).sign)
|
assert_equal(1, x ** 0)
|
||||||
assert_equal(1, BigDecimal.new("Infinity") ** 0)
|
assert_equal(1, x ** 0.quo(1))
|
||||||
assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("Infinity") ** -1).sign)
|
assert_equal(1, x ** 0.0)
|
||||||
assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("Infinity") ** -2).sign)
|
assert_equal(1, x ** BigDecimal(0))
|
||||||
|
|
||||||
assert_equal(BigDecimal::SIGN_POSITIVE_INFINITE, (BigDecimal.new("-Infinity") ** 2).sign)
|
x = BigDecimal(-42)
|
||||||
assert_equal(BigDecimal::SIGN_NEGATIVE_INFINITE, (BigDecimal.new("-Infinity") ** 1).sign)
|
assert_equal(1, x ** 0)
|
||||||
assert_equal(1, BigDecimal.new("-Infinity") ** 0)
|
assert_equal(1, x ** 0.quo(1))
|
||||||
assert_equal(BigDecimal::SIGN_NEGATIVE_ZERO, (BigDecimal.new("-Infinity") ** -1).sign)
|
assert_equal(1, x ** 0.0)
|
||||||
assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("-Infinity") ** -2).sign)
|
assert_equal(1, x ** BigDecimal(0))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_power_of_three
|
||||||
|
x = BigDecimal(3)
|
||||||
|
assert_equal(81, x ** 4)
|
||||||
|
assert_equal(1.quo(81), x ** -4)
|
||||||
|
assert_in_delta(1.0/81, x ** -4)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_power_of_zero
|
||||||
|
zero = BigDecimal(0)
|
||||||
|
assert_equal(0, zero ** 4)
|
||||||
|
assert_equal(0, zero ** 4.quo(1))
|
||||||
|
assert_equal(0, zero ** 4.0)
|
||||||
|
assert_equal(0, zero ** BigDecimal(4))
|
||||||
|
assert_equal(1, zero ** 0)
|
||||||
|
assert_equal(1, zero ** 0.quo(1))
|
||||||
|
assert_equal(1, zero ** 0.0)
|
||||||
|
assert_equal(1, zero ** BigDecimal(0))
|
||||||
|
BigDecimal.save_exception_mode do
|
||||||
|
BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, false)
|
||||||
|
BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
|
||||||
|
assert_positive_infinite(zero ** -1)
|
||||||
|
assert_positive_infinite(zero ** -1.quo(1))
|
||||||
|
assert_positive_infinite(zero ** -1.0)
|
||||||
|
assert_positive_infinite(zero ** BigDecimal(-1))
|
||||||
|
|
||||||
|
m_zero = BigDecimal("-0")
|
||||||
|
assert_negative_infinite(m_zero ** -1)
|
||||||
|
assert_negative_infinite(m_zero ** -1.quo(1))
|
||||||
|
assert_negative_infinite(m_zero ** -1.0)
|
||||||
|
assert_negative_infinite(m_zero ** BigDecimal(-1))
|
||||||
|
assert_positive_infinite(m_zero ** -2)
|
||||||
|
assert_positive_infinite(m_zero ** -2.quo(1))
|
||||||
|
assert_positive_infinite(m_zero ** -2.0)
|
||||||
|
assert_positive_infinite(m_zero ** BigDecimal(-2))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_power_of_positive_infinity
|
||||||
|
BigDecimal.save_exception_mode do
|
||||||
|
BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** 3)
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** 3.quo(1))
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** 3.0)
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** BigDecimal(3))
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** 2)
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** 2.quo(1))
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** 2.0)
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** BigDecimal(2))
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** 1)
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** 1.quo(1))
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** 1.0)
|
||||||
|
assert_positive_infinite(BigDecimal::INFINITY ** BigDecimal(1))
|
||||||
|
assert_equal(1, BigDecimal::INFINITY ** 0)
|
||||||
|
assert_equal(1, BigDecimal::INFINITY ** 0.quo(1))
|
||||||
|
assert_equal(1, BigDecimal::INFINITY ** 0.0)
|
||||||
|
assert_equal(1, BigDecimal::INFINITY ** BigDecimal(0))
|
||||||
|
assert_positive_zero(BigDecimal::INFINITY ** -1)
|
||||||
|
assert_positive_zero(BigDecimal::INFINITY ** -1.quo(1))
|
||||||
|
assert_positive_zero(BigDecimal::INFINITY ** -1.0)
|
||||||
|
assert_positive_zero(BigDecimal::INFINITY ** BigDecimal(-1))
|
||||||
|
assert_positive_zero(BigDecimal::INFINITY ** -2)
|
||||||
|
assert_positive_zero(BigDecimal::INFINITY ** -2.0)
|
||||||
|
assert_positive_zero(BigDecimal::INFINITY ** BigDecimal(-2))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_power_of_negative_infinity
|
||||||
|
BigDecimal.save_exception_mode do
|
||||||
|
BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
|
||||||
|
assert_negative_infinite((-BigDecimal::INFINITY) ** 3)
|
||||||
|
assert_negative_infinite((-BigDecimal::INFINITY) ** 3.quo(1))
|
||||||
|
assert_negative_infinite((-BigDecimal::INFINITY) ** 3.0)
|
||||||
|
assert_negative_infinite((-BigDecimal::INFINITY) ** BigDecimal(3))
|
||||||
|
assert_positive_infinite((-BigDecimal::INFINITY) ** 2)
|
||||||
|
assert_positive_infinite((-BigDecimal::INFINITY) ** 2.quo(1))
|
||||||
|
assert_positive_infinite((-BigDecimal::INFINITY) ** 2.0)
|
||||||
|
assert_positive_infinite((-BigDecimal::INFINITY) ** BigDecimal(2))
|
||||||
|
assert_negative_infinite((-BigDecimal::INFINITY) ** 1)
|
||||||
|
assert_negative_infinite((-BigDecimal::INFINITY) ** 1.quo(1))
|
||||||
|
assert_negative_infinite((-BigDecimal::INFINITY) ** 1.0)
|
||||||
|
assert_negative_infinite((-BigDecimal::INFINITY) ** BigDecimal(1))
|
||||||
|
assert_equal(1, (-BigDecimal::INFINITY) ** 0)
|
||||||
|
assert_equal(1, (-BigDecimal::INFINITY) ** 0.quo(1))
|
||||||
|
assert_equal(1, (-BigDecimal::INFINITY) ** 0.0)
|
||||||
|
assert_equal(1, (-BigDecimal::INFINITY) ** BigDecimal(0))
|
||||||
|
assert_negative_zero((-BigDecimal::INFINITY) ** -1)
|
||||||
|
assert_negative_zero((-BigDecimal::INFINITY) ** -1.quo(1))
|
||||||
|
assert_negative_zero((-BigDecimal::INFINITY) ** -1.0)
|
||||||
|
assert_negative_zero((-BigDecimal::INFINITY) ** BigDecimal(-1))
|
||||||
|
assert_positive_zero((-BigDecimal::INFINITY) ** -2)
|
||||||
|
assert_positive_zero((-BigDecimal::INFINITY) ** -2.quo(1))
|
||||||
|
assert_positive_zero((-BigDecimal::INFINITY) ** -2.0)
|
||||||
|
assert_positive_zero((-BigDecimal::INFINITY) ** BigDecimal(-2))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_limit
|
def test_limit
|
||||||
|
|
Loading…
Reference in a new issue