ruby-changes:65488
From: nagachika <ko1@a...>
Date: Sat, 20 Mar 2021 15:35:50 +0900 (JST)
Subject: [ruby-changes:65488] 82bce422ba (ruby_2_7): merge revision(s) 254bed302752a401b5fcc3b6c65a9c93711d91d6,fad3023e94c45e7f03478732f7641b6f39ba9d12,3156fb0f2c3ebf8229f392c8502c08fe165ab181: [Backport #17218]
https://git.ruby-lang.org/ruby.git/commit/?id=82bce422ba From 82bce422ba9e131e62b528854dea69a6e8cc0c04 Mon Sep 17 00:00:00 2001 From: nagachika <nagachika@r...> Date: Sat, 20 Mar 2021 15:35:30 +0900 Subject: merge revision(s) 254bed302752a401b5fcc3b6c65a9c93711d91d6,fad3023e94c45e7f03478732f7641b6f39ba9d12,3156fb0f2c3ebf8229f392c8502c08fe165ab181: [Backport #17218] Renamed `nurat_sub` compliant with `rb_rational_plus` --- internal/rational.h | 1 + rational.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) Fix ArithmeticSequence#last and ArithmeticSequence#each for non-integer sequences (#3870) [Bug #17218] [ruby-core:100312] --- common.mk | 2 + enumerator.c | 99 ++++++++++++++++++++++++++++++++--- internal/numeric.h | 2 + internal/rational.h | 2 + numeric.c | 53 ++++++++++--------- rational.c | 28 +++++++--- test/ruby/test_arithmetic_sequence.rb | 10 ++++ 7 files changed, 156 insertions(+), 40 deletions(-) test/ruby/test_arithmetic_sequence.rb: remove a duplicated test There is another "test_last_bug17218" --- test/ruby/test_arithmetic_sequence.rb | 5 ----- 1 file changed, 5 deletions(-) --- enumerator.c | 98 ++++++++++++++++++++++++++++++++--- internal.h | 5 ++ numeric.c | 53 ++++++++++--------- rational.c | 34 ++++++++---- test/ruby/test_arithmetic_sequence.rb | 5 ++ version.h | 2 +- 6 files changed, 153 insertions(+), 44 deletions(-) diff --git a/enumerator.c b/enumerator.c index 9d0547d..2dc1789 100644 --- a/enumerator.c +++ b/enumerator.c @@ -3535,6 +3535,88 @@ arith_seq_first(int argc, VALUE *argv, VALUE self) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L3535 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, idDiv, 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 @@ -3559,7 +3641,7 @@ arith_seq_last(int argc, VALUE *argv, VALUE self) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L3641 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; @@ -3567,9 +3649,9 @@ arith_seq_last(int argc, VALUE *argv, VALUE self) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L3649 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) { @@ -3778,22 +3860,22 @@ arith_seq_each(VALUE self) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L3860 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 b96c152..47428da 100644 --- a/internal.h +++ b/internal.h @@ -1812,6 +1812,7 @@ VALUE rb_float_uminus(VALUE num); https://github.com/ruby/ruby/blob/trunk/internal.h#L1812 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_float_div(VALUE x, VALUE y); @@ -1840,6 +1841,7 @@ int rb_int_positive_p(VALUE num); https://github.com/ruby/ruby/blob/trunk/internal.h#L1841 int rb_int_negative_p(VALUE num); VALUE rb_num_pow(VALUE x, VALUE y); VALUE rb_float_ceil(VALUE num, int ndigits); +VALUE rb_float_floor(VALUE x, int ndigits); static inline VALUE rb_num_compare_with_zero(VALUE num, ID mid) @@ -2096,13 +2098,16 @@ void rb_last_status_clear(void); https://github.com/ruby/ruby/blob/trunk/internal.h#L2098 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); VALUE rb_float_numerator(VALUE x); VALUE rb_float_denominator(VALUE x); diff --git a/numeric.c b/numeric.c index fa89616..3da0f7f 100644 --- a/numeric.c +++ b/numeric.c @@ -1044,8 +1044,8 @@ rb_float_plus(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1044 * 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)); @@ -1894,6 +1894,31 @@ flo_prev_float(VALUE vx) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1894 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 @@ -1936,31 +1961,11 @@ flo_prev_float(VALUE vx) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1961 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); } /* @@ -5790,7 +5795,7 @@ Init_Numeric(void) https://github.com/ruby/ruby/blob/trunk/numeric.c#L5795 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, "/", rb_float_div, 1); rb_define_method(rb_cFloat, "quo", flo_quo, 1); diff --git a/rational.c b/rational.c index dc01425..9f6964f 100644 --- a/rational.c +++ b/rational.c @@ -774,8 +774,8 @@ rb_rational_plus(VALUE self, VALUE other) https://github.com/ruby/ruby/blob/trunk/rational.c#L774 * Rational(9, 8) - 4 (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/