mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* rational.c (nurat_expt): Deal with special cases for rationals 0, ±1
[bug #5713] [bug #5715] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@39063 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
075ae2955c
commit
8797ebd662
2 changed files with 66 additions and 0 deletions
46
rational.c
46
rational.c
|
@ -220,6 +220,26 @@ f_one_p(VALUE x)
|
|||
return rb_funcall(x, id_eqeq_p, 1, ONE);
|
||||
}
|
||||
|
||||
inline static VALUE
|
||||
f_minus_one_p(VALUE x)
|
||||
{
|
||||
switch (TYPE(x)) {
|
||||
case T_FIXNUM:
|
||||
return f_boolcast(FIX2LONG(x) == -1);
|
||||
case T_BIGNUM:
|
||||
return Qfalse;
|
||||
case T_RATIONAL:
|
||||
{
|
||||
VALUE num = RRATIONAL(x)->num;
|
||||
VALUE den = RRATIONAL(x)->den;
|
||||
|
||||
return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == -1 &&
|
||||
FIXNUM_P(den) && FIX2LONG(den) == 1);
|
||||
}
|
||||
}
|
||||
return rb_funcall(x, id_eqeq_p, 1, INT2FIX(-1));
|
||||
}
|
||||
|
||||
inline static VALUE
|
||||
f_kind_of_p(VALUE x, VALUE c)
|
||||
{
|
||||
|
@ -916,6 +936,16 @@ nurat_fdiv(VALUE self, VALUE other)
|
|||
return f_to_f(f_div(self, other));
|
||||
}
|
||||
|
||||
inline static VALUE
|
||||
f_odd_p(VALUE integer)
|
||||
{
|
||||
if (rb_funcall(integer, '%', 1, INT2FIX(2)) != INT2FIX(0)) {
|
||||
return Qtrue;
|
||||
}
|
||||
return Qfalse;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* rat ** numeric -> numeric
|
||||
|
@ -942,6 +972,22 @@ nurat_expt(VALUE self, VALUE other)
|
|||
other = dat->num; /* c14n */
|
||||
}
|
||||
|
||||
/* Deal with special cases of 0**n and 1**n */
|
||||
if (k_numeric_p(other) && k_exact_p(other)) {
|
||||
get_dat1(self);
|
||||
if (f_one_p(dat->den))
|
||||
if (f_one_p(dat->num))
|
||||
return f_rational_new_bang1(CLASS_OF(self), ONE);
|
||||
else if (f_minus_one_p(dat->num) && k_integer_p(other))
|
||||
return f_rational_new_bang1(CLASS_OF(self), INT2FIX(f_odd_p(other) ? -1 : 1));
|
||||
else if (f_zero_p(dat->num))
|
||||
if (FIX2INT(f_cmp(other, ZERO)) == -1)
|
||||
rb_raise_zerodiv();
|
||||
else
|
||||
return f_rational_new_bang1(CLASS_OF(self), ZERO);
|
||||
}
|
||||
|
||||
/* General case */
|
||||
switch (TYPE(other)) {
|
||||
case T_FIXNUM:
|
||||
{
|
||||
|
|
|
@ -1143,6 +1143,26 @@ class Rational_Test < Test::Unit::TestCase
|
|||
assert_equal(1.0, Rational(n + 2, n + 1).to_f, '[ruby-dev:33852]')
|
||||
end
|
||||
|
||||
def test_power_of_1_and_minus_1
|
||||
bug5715 = '[ruby-core:41498]'
|
||||
big = 1 << 66
|
||||
one = Rational( 1, 1)
|
||||
assert_eql one, one ** -big , bug5715
|
||||
assert_eql one, (-one) ** -big , bug5715
|
||||
assert_eql -one, (-one) ** -(big+1) , bug5715
|
||||
assert_equal Complex, ((-one) ** Rational(1,3)).class
|
||||
end
|
||||
|
||||
def test_power_of_0
|
||||
bug5713 = '[ruby-core:41494]'
|
||||
big = 1 << 66
|
||||
zero = Rational(0, 1)
|
||||
assert_eql zero, zero ** big
|
||||
assert_eql zero, zero ** Rational(2, 3)
|
||||
assert_raise(ZeroDivisionError, bug5713) { Rational(0, 1) ** -big }
|
||||
assert_raise(ZeroDivisionError, bug5713) { Rational(0, 1) ** Rational(-2,3) }
|
||||
end
|
||||
|
||||
def test_known_bug
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue