aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-10-02 16:42:21 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-10-02 16:42:21 +0000
commit603f95a0ed37d90854f80393881fb38ab29128a7 (patch)
tree2f76d289cf541c53cb29dff917569d0846a12613
parent25ea4dc6230f3141dcb3b9d04c9124bc07146bca (diff)
downloadruby-603f95a0ed37d90854f80393881fb38ab29128a7.tar.gz
Fix Rational of Float
[ruby-core:89239] [Bug #15189] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64897 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--bignum.c10
-rw-r--r--numeric.c9
-rw-r--r--object.c15
-rw-r--r--rational.c21
-rw-r--r--test/ruby/test_integer.rb23
5 files changed, 66 insertions, 12 deletions
diff --git a/bignum.c b/bignum.c
index ee481e1bd7..e53b2bd2c1 100644
--- a/bignum.c
+++ b/bignum.c
@@ -6207,6 +6207,7 @@ rb_big_pow(VALUE x, VALUE y)
again:
if (y == INT2FIX(0)) return INT2FIX(1);
+ if (y == INT2FIX(1)) return x;
if (RB_FLOAT_TYPE_P(y)) {
d = RFLOAT_VALUE(y);
if ((BIGNUM_NEGATIVE_P(x) && !BIGZEROP(x))) {
@@ -6223,8 +6224,13 @@ rb_big_pow(VALUE x, VALUE y)
else if (FIXNUM_P(y)) {
yy = FIX2LONG(y);
- if (yy < 0)
- return rb_rational_raw(INT2FIX(1), rb_big_pow(x, INT2NUM(-yy)));
+ if (yy < 0) {
+ x = rb_big_pow(x, INT2NUM(-yy));
+ if (RB_INTEGER_TYPE_P(x))
+ return rb_rational_raw(INT2FIX(1), x);
+ else
+ return DBL2NUM(1.0 / NUM2DBL(x));
+ }
else {
VALUE z = 0;
SIGNED_VALUE mask;
diff --git a/numeric.c b/numeric.c
index c8a240b778..292af0af27 100644
--- a/numeric.c
+++ b/numeric.c
@@ -4015,7 +4015,8 @@ fix_pow(VALUE x, VALUE y)
}
if (b < 0) {
if (a == 0) rb_num_zerodiv();
- return rb_rational_raw(INT2FIX(1), rb_int_pow(x, LONG2NUM(-b)));
+ y = rb_int_pow(x, LONG2NUM(-b));
+ goto inverted;
}
if (b == 0) return INT2FIX(1);
@@ -4035,10 +4036,10 @@ fix_pow(VALUE x, VALUE y)
if (BIGNUM_NEGATIVE_P(y)) {
if (a == 0) rb_num_zerodiv();
y = rb_int_pow(x, rb_big_uminus(y));
- if (0 && RB_FLOAT_TYPE_P(y)) {
- /* Maybe should return a Float */
+ inverted:
+ if (RB_FLOAT_TYPE_P(y)) {
double d = pow((double)a, RFLOAT_VALUE(y));
- return DBL2NUM(d);
+ return DBL2NUM(1.0 / d);
}
return rb_rational_raw(INT2FIX(1), y);
}
diff --git a/object.c b/object.c
index 7d6e47932c..6a66159a94 100644
--- a/object.c
+++ b/object.c
@@ -3421,9 +3421,18 @@ rb_str_to_dbl(VALUE str, int badcheck)
#define big2dbl_without_to_f(x) rb_big2dbl(x)
#define int2dbl_without_to_f(x) \
(FIXNUM_P(x) ? fix2dbl_without_to_f(x) : big2dbl_without_to_f(x))
-#define rat2dbl_without_to_f(x) \
- (int2dbl_without_to_f(rb_rational_num(x)) / \
- int2dbl_without_to_f(rb_rational_den(x)))
+static inline double
+rat2dbl_without_to_f(VALUE x)
+{
+ VALUE num = rb_rational_num(x);
+ VALUE den = rb_rational_den(x);
+ if (RB_INTEGER_TYPE_P(num) && RB_INTEGER_TYPE_P(den)) {
+ return int2dbl_without_to_f(num) / int2dbl_without_to_f(den);
+ }
+ else {
+ return NUM2DBL(num) / NUM2DBL(den);
+ }
+}
#define special_const_to_float(val, pre, post) \
switch (val) { \
diff --git a/rational.c b/rational.c
index 3fcf82bce5..6426f2327c 100644
--- a/rational.c
+++ b/rational.c
@@ -696,7 +696,8 @@ f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
a = rb_int_idiv(bden, g);
den = rb_int_mul(a, b);
}
- else {
+ else if (RB_INTEGER_TYPE_P(anum) && RB_INTEGER_TYPE_P(aden) &&
+ RB_INTEGER_TYPE_P(bnum) && RB_INTEGER_TYPE_P(bden)) {
VALUE g = f_gcd(aden, bden);
VALUE a = rb_int_mul(anum, rb_int_idiv(bden, g));
VALUE b = rb_int_mul(bnum, rb_int_idiv(aden, g));
@@ -713,6 +714,12 @@ f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
a = rb_int_idiv(bden, g);
den = rb_int_mul(a, b);
}
+ else {
+ double a = NUM2DBL(anum) / NUM2DBL(aden);
+ double b = NUM2DBL(bnum) / NUM2DBL(bden);
+ double c = k == '+' ? a + b : a - b;
+ return DBL2NUM(c);
+ }
return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
}
@@ -1144,9 +1151,9 @@ static VALUE
nurat_eqeq_p(VALUE self, VALUE other)
{
if (RB_INTEGER_TYPE_P(other)) {
- {
- get_dat1(self);
+ get_dat1(self);
+ if (RB_INTEGER_TYPE_P(dat->num) && RB_INTEGER_TYPE_P(dat->den)) {
if (INT_ZERO_P(dat->num) && INT_ZERO_P(other))
return Qtrue;
@@ -1156,6 +1163,10 @@ nurat_eqeq_p(VALUE self, VALUE other)
return Qfalse;
return rb_int_equal(dat->num, other);
}
+ else {
+ const double d = nurat_to_double(self);
+ return f_boolcast(FIXNUM_ZERO_P(rb_dbl_cmp(d, NUM2DBL(other))));
+ }
}
else if (RB_FLOAT_TYPE_P(other)) {
const double d = nurat_to_double(self);
@@ -1544,6 +1555,10 @@ static double
nurat_to_double(VALUE self)
{
get_dat1(self);
+ if (!RB_INTEGER_TYPE_P(dat->num) || !RB_INTEGER_TYPE_P(dat->den)) {
+ double d = NUM2DBL(dat->num) / NUM2DBL(dat->den);
+ return DBL2NUM(d);
+ }
return rb_int_fdiv_double(dat->num, dat->den);
}
diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb
index acba5aca1a..a991683773 100644
--- a/test/ruby/test_integer.rb
+++ b/test/ruby/test_integer.rb
@@ -27,6 +27,29 @@ class TestInteger < Test::Unit::TestCase
x = EnvUtil.suppress_warning {2 ** -0x4000000000000000}
assert_in_delta(0.0, (x / 2), Float::EPSILON)
+
+ <<~EXPRS.each_line.with_index(__LINE__+1) do |expr, line|
+ crash01: 111r+11**-11111161111111
+ crash02: 1118111111111**-1111111111111111**1+1==11111
+ crash03: -1111111**-1111*11 - -1111111** -111111111
+ crash04: 1118111111111** -1111111111111111**1+11111111111**1 ===111
+ crash05: 11** -111155555555555555 -55 !=5-555
+ crash07: 1 + 111111111**-1111811111
+ crash08: 18111111111**-1111111111111111**1 + 1111111111**-1111**1
+ crash10: -7 - -1111111** -1111**11
+ crash12: 1118111111111** -1111111111111111**1 + 1111 - -1111111** -1111*111111111119
+ crash13: 1.0i - -1111111** -111111111
+ crash14: 11111**111111111**111111 * -11111111111111111111**-111111111111
+ crash15: ~1**1111 + -~1**~1**111
+ crash17: 11** -1111111**1111 /11i
+ crash18: 5555i**-5155 - -9111111**-1111**11
+ crash19: 111111*-11111111111111111111**-1111111111111111
+ crash20: 1111**111-11**-11111**11
+ crash21: 11**-10111111119-1i -1r
+ EXPRS
+ name, expr = expr.split(':', 2)
+ assert_ruby_status(%w"-W0", expr, name)
+ end
end
def test_lshift