aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2021-03-20 15:35:30 +0900
committernagachika <nagachika@ruby-lang.org>2021-03-20 15:35:30 +0900
commit82bce422ba9e131e62b528854dea69a6e8cc0c04 (patch)
treecf44dea8aaa0f021c4fcf97990ce28d43de8cd35
parentc02f4c1c5aa5056d6eae8f0c2d6414adf5293b2b (diff)
downloadruby-82bce422ba9e131e62b528854dea69a6e8cc0c04.tar.gz
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(-)
-rw-r--r--enumerator.c98
-rw-r--r--internal.h5
-rw-r--r--numeric.c53
-rw-r--r--rational.c34
-rw-r--r--test/ruby/test_arithmetic_sequence.rb5
-rw-r--r--version.h2
6 files changed, 153 insertions, 44 deletions
diff --git a/enumerator.c b/enumerator.c
index 9d0547da05..2dc1789974 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -3535,6 +3535,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, 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)
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)
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)
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 b96c152252..47428da27f 100644
--- a/internal.h
+++ b/internal.h
@@ -1812,6 +1812,7 @@ 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_float_div(VALUE x, VALUE y);
@@ -1840,6 +1841,7 @@ 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_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);
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 fa8961652b..3da0f7f6b0 100644
--- a/numeric.c
+++ b/numeric.c
@@ -1044,8 +1044,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));
@@ -1894,6 +1894,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
@@ -1936,31 +1961,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);
}
/*
@@ -5790,7 +5795,7 @@ 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, "/", rb_float_div, 1);
rb_define_method(rb_cFloat, "quo", flo_quo, 1);
diff --git a/rational.c b/rational.c
index dc01425298..9f6964f0aa 100644
--- a/rational.c
+++ b/rational.c
@@ -774,8 +774,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)) {
{
@@ -912,8 +912,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))
@@ -965,10 +965,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))
@@ -1403,7 +1403,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);
@@ -1411,6 +1411,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
@@ -2027,7 +2039,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
@@ -2734,10 +2746,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 45a0ab9222..755f54ac5a 100644
--- a/test/ruby/test_arithmetic_sequence.rb
+++ b/test/ruby/test_arithmetic_sequence.rb
@@ -284,6 +284,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 21f37b93dd..c10798ff99 100644
--- a/version.h
+++ b/version.h
@@ -2,7 +2,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 3
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 172
+#define RUBY_PATCHLEVEL 173
#define RUBY_RELEASE_YEAR 2021
#define RUBY_RELEASE_MONTH 3