From 1a38986aedf63f676efded3e834c959059d21760 Mon Sep 17 00:00:00 2001 From: usa Date: Mon, 5 Apr 2021 01:22:11 +0000 Subject: merge revision(s) 254bed302752a401b5fcc3b6c65a9c93711d91d6,fad3023e94c45e7f03478732f7641b6f39ba9d12,3156fb0f2c3ebf8229f392c8502c08fe165ab181: [Backport #17218] Renamed `nurat_sub` compliant with `rb_rational_plus` Fix ArithmeticSequence#last and ArithmeticSequence#each for non-integer sequences (#3870) [Bug #17218] [ruby-core:100312] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@67936 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- enumerator.c | 98 ++++++++++++++++++++++++++++++++--- internal.h | 7 +++ numeric.c | 59 +++++++++++---------- rational.c | 34 ++++++++---- test/ruby/test_arithmetic_sequence.rb | 5 ++ version.h | 2 +- 6 files changed, 158 insertions(+), 47 deletions(-) diff --git a/enumerator.c b/enumerator.c index 6db3bbe50d..686dab0b20 100644 --- a/enumerator.c +++ b/enumerator.c @@ -2939,6 +2939,88 @@ arith_seq_first(int argc, VALUE *argv, VALUE self) return rb_call_super(argc, argv); } +static inline VALUE +num_plus(VALUE a, VALUE b) +{ + if (RB_INTEGER_TYPE_P(a)) { + return rb_int_plus(a, b); + } + else if (RB_FLOAT_TYPE_P(a)) { + return rb_float_plus(a, b); + } + else if (RB_TYPE_P(a, T_RATIONAL)) { + return rb_rational_plus(a, b); + } + else { + return rb_funcallv(a, '+', 1, &b); + } +} + +static inline VALUE +num_minus(VALUE a, VALUE b) +{ + if (RB_INTEGER_TYPE_P(a)) { + return rb_int_minus(a, b); + } + else if (RB_FLOAT_TYPE_P(a)) { + return rb_float_minus(a, b); + } + else if (RB_TYPE_P(a, T_RATIONAL)) { + return rb_rational_minus(a, b); + } + else { + return rb_funcallv(a, '-', 1, &b); + } +} + +static inline VALUE +num_mul(VALUE a, VALUE b) +{ + if (RB_INTEGER_TYPE_P(a)) { + return rb_int_mul(a, b); + } + else if (RB_FLOAT_TYPE_P(a)) { + return rb_float_mul(a, b); + } + else if (RB_TYPE_P(a, T_RATIONAL)) { + return rb_rational_mul(a, b); + } + else { + return rb_funcallv(a, '*', 1, &b); + } +} + +static inline VALUE +num_idiv(VALUE a, VALUE b) +{ + VALUE q; + if (RB_INTEGER_TYPE_P(a)) { + q = rb_int_idiv(a, b); + } + else if (RB_FLOAT_TYPE_P(a)) { + q = rb_float_div(a, b); + } + else if (RB_TYPE_P(a, T_RATIONAL)) { + q = rb_rational_div(a, b); + } + else { + q = rb_funcallv(a, '/', 1, &b); + } + + if (RB_INTEGER_TYPE_P(q)) { + return q; + } + else if (RB_FLOAT_TYPE_P(q)) { + return rb_float_floor(q, 0); + } + else if (RB_TYPE_P(q, T_RATIONAL)) { + return rb_rational_floor(q, 0); + } + else { + return rb_funcall(q, rb_intern("floor"), 0); + } +} + /* * call-seq: * aseq.last -> num or nil @@ -2963,7 +3045,7 @@ arith_seq_last(int argc, VALUE *argv, VALUE self) b = arith_seq_begin(self); s = arith_seq_step(self); - len_1 = rb_int_idiv(rb_int_minus(e, b), s); + len_1 = num_idiv(num_minus(e, b), s); if (rb_num_negative_int_p(len_1)) { if (argc == 0) { return Qnil; @@ -2971,9 +3053,9 @@ arith_seq_last(int argc, VALUE *argv, VALUE self) return rb_ary_new_capa(0); } - last = rb_int_plus(b, rb_int_mul(s, len_1)); + last = num_plus(b, num_mul(s, len_1)); if ((last_is_adjusted = arith_seq_exclude_end_p(self) && rb_equal(last, e))) { - last = rb_int_minus(last, s); + last = num_minus(last, s); } if (argc == 0) { @@ -3183,22 +3265,22 @@ arith_seq_each(VALUE self) return self; } - len_1 = rb_int_idiv(rb_int_minus(e, c), s); - last = rb_int_plus(c, rb_int_mul(s, len_1)); + len_1 = num_idiv(num_minus(e, c), s); + last = num_plus(c, num_mul(s, len_1)); if (x && rb_equal(last, e)) { - last = rb_int_minus(last, s); + last = num_minus(last, s); } if (rb_num_negative_int_p(s)) { while (NUM_GE(c, last)) { rb_yield(c); - c = rb_int_plus(c, s); + c = num_plus(c, s); } } else { while (NUM_GE(last, c)) { rb_yield(c); - c = rb_int_plus(c, s); + c = num_plus(c, s); } } diff --git a/internal.h b/internal.h index 37e5c73d18..13a0424344 100644 --- a/internal.h +++ b/internal.h @@ -1682,9 +1682,11 @@ VALUE rb_float_uminus(VALUE num); VALUE rb_int_plus(VALUE x, VALUE y); VALUE rb_float_plus(VALUE x, VALUE y); VALUE rb_int_minus(VALUE x, VALUE y); +VALUE rb_float_minus(VALUE x, VALUE y); VALUE rb_int_mul(VALUE x, VALUE y); VALUE rb_float_mul(VALUE x, VALUE y); VALUE rb_int_idiv(VALUE x, VALUE y); +VALUE rb_float_div(VALUE x, VALUE y); VALUE rb_int_modulo(VALUE x, VALUE y); VALUE rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode); VALUE rb_int2str(VALUE num, int base); @@ -1709,6 +1711,8 @@ VALUE rb_int_odd_p(VALUE num); int rb_int_positive_p(VALUE num); int rb_int_negative_p(VALUE num); VALUE rb_num_pow(VALUE x, VALUE y); +VALUE rb_float_floor(VALUE x, int ndigits); + static inline VALUE rb_num_compare_with_zero(VALUE num, ID mid) @@ -1975,13 +1979,16 @@ void rb_last_status_clear(void); VALUE rb_rational_canonicalize(VALUE x); VALUE rb_rational_uminus(VALUE self); VALUE rb_rational_plus(VALUE self, VALUE other); +VALUE rb_rational_minus(VALUE self, VALUE other); VALUE rb_rational_mul(VALUE self, VALUE other); +VALUE rb_rational_div(VALUE self, VALUE other); VALUE rb_lcm(VALUE x, VALUE y); VALUE rb_rational_reciprocal(VALUE x); VALUE rb_cstr_to_rat(const char *, int); VALUE rb_rational_abs(VALUE self); VALUE rb_rational_cmp(VALUE self, VALUE other); VALUE rb_rational_pow(VALUE self, VALUE other); +VALUE rb_rational_floor(VALUE self, int ndigits); VALUE rb_numeric_quo(VALUE x, VALUE y); /* re.c */ diff --git a/numeric.c b/numeric.c index d602d0afde..f5ae09b3fd 100644 --- a/numeric.c +++ b/numeric.c @@ -1042,8 +1042,8 @@ rb_float_plus(VALUE x, VALUE y) * Returns a new Float which is the difference of +float+ and +other+. */ -static VALUE -flo_minus(VALUE x, VALUE y) +VALUE +rb_float_minus(VALUE x, VALUE y) { if (RB_TYPE_P(y, T_FIXNUM)) { return DBL2NUM(RFLOAT_VALUE(x) - (double)FIX2LONG(y)); @@ -1120,8 +1120,8 @@ rb_flo_div_flo(VALUE x, VALUE y) * Returns a new Float which is the result of dividing +float+ by +other+. */ -static VALUE -flo_div(VALUE x, VALUE y) +VALUE +rb_float_div(VALUE x, VALUE y) { double num = RFLOAT_VALUE(x); double den; @@ -1891,6 +1891,31 @@ flo_prev_float(VALUE vx) return DBL2NUM(y); } +VALUE +rb_float_floor(VALUE num, int ndigits) +{ + double number, f; + number = RFLOAT_VALUE(num); + if (number == 0.0) { + return ndigits > 0 ? DBL2NUM(number) : INT2FIX(0); + } + if (ndigits > 0) { + int binexp; + frexp(number, &binexp); + if (float_round_overflow(ndigits, binexp)) return num; + if (number > 0.0 && float_round_underflow(ndigits, binexp)) + return DBL2NUM(0.0); + f = pow(10, ndigits); + f = floor(number * f) / f; + return DBL2NUM(f); + } + else { + num = dbl2ival(floor(number)); + if (ndigits < 0) num = rb_int_floor(num, ndigits); + return num; + } +} + /* * call-seq: * float.floor([ndigits]) -> integer or float @@ -1933,31 +1958,11 @@ flo_prev_float(VALUE vx) static VALUE flo_floor(int argc, VALUE *argv, VALUE num) { - double number, f; int ndigits = 0; - if (rb_check_arity(argc, 0, 1)) { ndigits = NUM2INT(argv[0]); } - number = RFLOAT_VALUE(num); - if (number == 0.0) { - return ndigits > 0 ? DBL2NUM(number) : INT2FIX(0); - } - if (ndigits > 0) { - int binexp; - frexp(number, &binexp); - if (float_round_overflow(ndigits, binexp)) return num; - if (number > 0.0 && float_round_underflow(ndigits, binexp)) - return DBL2NUM(0.0); - f = pow(10, ndigits); - f = floor(number * f) / f; - return DBL2NUM(f); - } - else { - num = dbl2ival(floor(number)); - if (ndigits < 0) num = rb_int_floor(num, ndigits); - return num; - } + return rb_float_floor(num, ndigits); } /* @@ -5676,9 +5681,9 @@ Init_Numeric(void) rb_define_method(rb_cFloat, "coerce", flo_coerce, 1); rb_define_method(rb_cFloat, "-@", rb_float_uminus, 0); rb_define_method(rb_cFloat, "+", rb_float_plus, 1); - rb_define_method(rb_cFloat, "-", flo_minus, 1); + rb_define_method(rb_cFloat, "-", rb_float_minus, 1); rb_define_method(rb_cFloat, "*", rb_float_mul, 1); - rb_define_method(rb_cFloat, "/", flo_div, 1); + rb_define_method(rb_cFloat, "/", rb_float_div, 1); rb_define_method(rb_cFloat, "quo", flo_quo, 1); rb_define_method(rb_cFloat, "fdiv", flo_quo, 1); rb_define_method(rb_cFloat, "%", flo_mod, 1); diff --git a/rational.c b/rational.c index 1038059e4f..5058ce1bfa 100644 --- a/rational.c +++ b/rational.c @@ -781,8 +781,8 @@ rb_rational_plus(VALUE self, VALUE other) * Rational(9, 8) - 4 #=> (-23/8) * Rational(20, 9) - 9.8 #=> -7.577777777777778 */ -static VALUE -nurat_sub(VALUE self, VALUE other) +VALUE +rb_rational_minus(VALUE self, VALUE other) { if (RB_INTEGER_TYPE_P(other)) { { @@ -919,8 +919,8 @@ rb_rational_mul(VALUE self, VALUE other) * Rational(9, 8) / 4 #=> (9/32) * Rational(20, 9) / 9.8 #=> 0.22675736961451246 */ -static VALUE -nurat_div(VALUE self, VALUE other) +VALUE +rb_rational_div(VALUE self, VALUE other) { if (RB_INTEGER_TYPE_P(other)) { if (f_zero_p(other)) @@ -972,10 +972,10 @@ nurat_fdiv(VALUE self, VALUE other) { VALUE div; if (f_zero_p(other)) - return nurat_div(self, rb_float_new(0.0)); + return rb_rational_div(self, rb_float_new(0.0)); if (FIXNUM_P(other) && other == LONG2FIX(1)) return nurat_to_f(self); - div = nurat_div(self, other); + div = rb_rational_div(self, other); if (RB_TYPE_P(div, T_RATIONAL)) return nurat_to_f(div); if (RB_FLOAT_TYPE_P(div)) @@ -1410,7 +1410,7 @@ f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE)) s = (*func)(s); - s = nurat_div(f_rational_new_bang1(CLASS_OF(self), s), b); + s = rb_rational_div(f_rational_new_bang1(CLASS_OF(self), s), b); if (RB_TYPE_P(s, T_RATIONAL) && FIX2INT(rb_int_cmp(n, ONE)) < 0) s = nurat_truncate(s); @@ -1418,6 +1418,18 @@ f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE)) return s; } +VALUE +rb_rational_floor(VALUE self, int ndigits) +{ + if (ndigits == 0) { + return nurat_floor(self); + } + else { + VALUE n = INT2NUM(ndigits); + return f_round_common(1, &n, self, nurat_floor); + } +} + /* * call-seq: * rat.floor([ndigits]) -> integer or rational @@ -2013,7 +2025,7 @@ rb_numeric_quo(VALUE x, VALUE y) else { x = rb_convert_type(x, T_RATIONAL, "Rational", "to_r"); } - return nurat_div(x, y); + return rb_rational_div(x, y); } VALUE @@ -2735,10 +2747,10 @@ Init_Rational(void) rb_define_method(rb_cRational, "-@", rb_rational_uminus, 0); rb_define_method(rb_cRational, "+", rb_rational_plus, 1); - rb_define_method(rb_cRational, "-", nurat_sub, 1); + rb_define_method(rb_cRational, "-", rb_rational_minus, 1); rb_define_method(rb_cRational, "*", rb_rational_mul, 1); - rb_define_method(rb_cRational, "/", nurat_div, 1); - rb_define_method(rb_cRational, "quo", nurat_div, 1); + rb_define_method(rb_cRational, "/", rb_rational_div, 1); + rb_define_method(rb_cRational, "quo", rb_rational_div, 1); rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1); rb_define_method(rb_cRational, "**", nurat_expt, 1); diff --git a/test/ruby/test_arithmetic_sequence.rb b/test/ruby/test_arithmetic_sequence.rb index 88fd3136cc..143906f4e2 100644 --- a/test/ruby/test_arithmetic_sequence.rb +++ b/test/ruby/test_arithmetic_sequence.rb @@ -254,6 +254,11 @@ class TestArithmeticSequence < Test::Unit::TestCase '[ruby-core:90648] [Bug #15444]') end + def test_last_bug17218 + seq = (1.0997r .. 1.1r).step(0.0001r) + assert_equal([1.0997r, 1.0998r, 1.0999r, 1.1r], seq.to_a, '[ruby-core:100312] [Bug #17218]') + end + def test_slice seq = 1.step(10, 2) assert_equal([[1, 3, 5], [7, 9]], seq.each_slice(3).to_a) diff --git a/version.h b/version.h index 39a6a3cc89..c435e392b5 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ #define RUBY_VERSION "2.6.7" #define RUBY_RELEASE_DATE "2021-04-05" -#define RUBY_PATCHLEVEL 195 +#define RUBY_PATCHLEVEL 196 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 4 -- cgit v1.2.3