* 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:
marcandre 2013-02-05 05:39:33 +00:00
Родитель 075ae2955c
Коммит 8797ebd662
2 изменённых файлов: 66 добавлений и 0 удалений

Просмотреть файл

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