From cca19532c5f71e1bdc0b4947b2fcddd181f27781 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 3 Jan 2019 11:34:35 +0900 Subject: Remove `Kernel#class_defined?` which is not available in CRuby; #3829 --- mrblib/numeric.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrblib/numeric.rb') diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 1b11e92ad..a2eb9c450 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -104,7 +104,7 @@ module Integral raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block - i = if class_defined?("Float") && num.kind_of?(Float) then self.to_f else self end + i = if Object.const_defined?(:Float) && num.kind_of?(Float) then self.to_f else self end if num == nil while true block.call(i) -- cgit v1.2.3 From de5da4b7f6615610ee5935754ae76e71870380aa Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 15 Jan 2019 21:41:54 +0900 Subject: Fix coercing for first step counter in `Numeric#step` Before: a=[]; 7.step(4, -3.0) { |c| a << c }; p a #=> [7, 4.0] After / Ruby: a=[]; 7.step(4, -3.0) { |c| a << c }; p a #=> [7.0, 4.0] --- mrblib/numeric.rb | 11 +++++++++-- test/t/integer.rb | 16 ---------------- test/t/numeric.rb | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 18 deletions(-) (limited to 'mrblib/numeric.rb') diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index a2eb9c450..dfdaf9da8 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -104,11 +104,18 @@ module Integral raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block - i = if Object.const_defined?(:Float) && num.kind_of?(Float) then self.to_f else self end + i = self + if Object.const_defined?(:Float) && + (kind_of?(Float) || num.kind_of?(Float) || step.kind_of?(Float)) + i = i.to_f + num = num.to_f unless num == nil + step = step.to_f + end + if num == nil while true block.call(i) - i+=step + i += step end return self end diff --git a/test/t/integer.rb b/test/t/integer.rb index c37641e9f..4ab49eb0a 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -257,19 +257,3 @@ assert('Integer#divmod', '15.2.8.3.30') do assert_equal [-2, -1], 25.divmod(-13) assert_equal [ 1, -6], -13.divmod(-7) end - -# Not ISO specified - -assert('Integer#step') do - a = [] - b = [] - 1.step(3) do |i| - a << i - end - 1.step(6, 2) do |i| - b << i - end - - assert_equal [1, 2, 3], a - assert_equal [1, 3, 5], b -end diff --git a/test/t/numeric.rb b/test/t/numeric.rb index 9d6dc22cc..f58194fe5 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -42,3 +42,35 @@ end assert('Numeric#**') do assert_equal 8.0, 2.0**3 end + +assert('Numeric#step') do + assert_step = ->(exp, receiver, args) do + inf = !args[0] + act = [] + ret = receiver.step(*args) do |i| + act << i + break if inf && exp.size == act.size + end + expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" + msg = "#{expr}: counters" + diff = assertion_diff(exp, act) + assert_true exp.map{|v|[v,v.class]} == act.map{|v|[v,v.class]}, msg, diff + assert_same receiver, ret, "#{expr}: return value" unless inf + end + + assert_raise(ArgumentError) { 1.step(2, 0) { break } } + assert_step.([2, 3, 4], 2, [4]) + assert_step.([10, 8, 6, 4, 2], 10, [1, -2]) + assert_step.([], 2, [1, 3]) + assert_step.([], -2, [-1, -3]) + assert_step.([10, 11, 12, 13], 10, []) + assert_step.([10, 7, 4], 10, [nil, -3]) + + skip unless Object.const_defined?(:Float) + assert_raise(ArgumentError) { 1.step(2, 0.0) { break } } + assert_step.([2.0, 3.0, 4.0], 2, [4.0]) + assert_step.([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) + assert_step.([2.0, 3.0, 4.0], 2.0, [4]) + assert_step.([10.0, 11.0, 12.0, 13.0], 10.0, []) + assert_step.([10.0, 7.0, 4.0], 10, [nil, -3.0]) +end -- cgit v1.2.3 From 8969edf03b2f4ff8537974c2bd30e9abe2002da6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 16 Jan 2019 19:32:29 +0900 Subject: Avoid runtime evaluation for `MRB_WITHOUT_FLOAT` --- mrblib/numeric.rb | 9 +-------- src/numeric.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'mrblib/numeric.rb') diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index dfdaf9da8..5a3c5eb58 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -104,14 +104,7 @@ module Integral raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block - i = self - if Object.const_defined?(:Float) && - (kind_of?(Float) || num.kind_of?(Float) || step.kind_of?(Float)) - i = i.to_f - num = num.to_f unless num == nil - step = step.to_f - end - + i = __coerce_step_counter(num, step) if num == nil while true block.call(i) diff --git a/src/numeric.c b/src/numeric.c index fc8460300..fa9daf8a7 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -154,6 +154,22 @@ num_div(mrb_state *mrb, mrb_value x) #endif } +static mrb_value +num_coerce_step_counter(mrb_state *mrb, mrb_value self) +{ + mrb_value counter = self, num, step; + + mrb_get_args(mrb, "oo", &num, &step); + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { + counter = mrb_funcall(mrb, counter, "to_f", 0); + } +#endif + + return counter; +} + #ifndef MRB_WITHOUT_FLOAT /******************************************************************** * @@ -1542,6 +1558,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, numeric, "__coerce_step_counter", num_coerce_step_counter, MRB_ARGS_REQ(2)); /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ -- cgit v1.2.3 From 32c2aa10c79e37c53411b1d693c6c8d010fba7bb Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 7 Jul 2019 22:10:32 +0900 Subject: Fix `Numeric#step` to infinity; ref. #4555 --- mrblib/numeric.rb | 8 ++--- test/t/numeric.rb | 88 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 27 deletions(-) (limited to 'mrblib/numeric.rb') diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 5a3c5eb58..5926518d5 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -105,14 +105,14 @@ module Integral return to_enum(:step, num, step) unless block i = __coerce_step_counter(num, step) - if num == nil + if num == self || step.infinite? + block.call(i) if step > 0 && i <= (num||i) || step < 0 && i >= (num||-i) + elsif num == nil while true block.call(i) i += step end - return self - end - if step > 0 + elsif step > 0 while i <= num block.call(i) i += step diff --git a/test/t/numeric.rb b/test/t/numeric.rb index d73dfdb61..bb95f8ef3 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -1,6 +1,19 @@ ## # Numeric ISO Test +def assert_step(exp, receiver, args, inf: false) + act = [] + ret = receiver.step(*args) do |i| + act << i + break if inf && exp.size == act.size + end + expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" + assert do + assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) + assert_same(receiver, ret, "#{expr}: return value") unless inf + end +end + assert('Numeric', '15.2.7') do assert_equal(Class, Numeric.class) end @@ -42,31 +55,60 @@ assert('Numeric#**') do end assert('Numeric#step') do - assert_step = ->(exp, receiver, args) do - inf = !args[0] - act = [] - ret = receiver.step(*args) do |i| - act << i - break if inf && exp.size == act.size - end - expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" - assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) - assert_same(receiver, ret, "#{expr}: return value") unless inf - end - assert_raise(ArgumentError) { 1.step(2, 0) { break } } - assert_step.([2, 3, 4], 2, [4]) - assert_step.([10, 8, 6, 4, 2], 10, [1, -2]) - assert_step.([], 2, [1, 3]) - assert_step.([], -2, [-1, -3]) - assert_step.([10, 11, 12, 13], 10, []) - assert_step.([10, 7, 4], 10, [nil, -3]) + assert_step([2, 3, 4], 2, [4]) + assert_step([10, 8, 6, 4, 2], 10, [1, -2]) + assert_step([], 2, [1, 3]) + assert_step([], -2, [-1, -3]) + assert_step([10, 11, 12, 13], 10, [], inf: true) + assert_step([10, 7, 4], 10, [nil, -3], inf: true) skip unless Object.const_defined?(:Float) + inf = Float::INFINITY assert_raise(ArgumentError) { 1.step(2, 0.0) { break } } - assert_step.([2.0, 3.0, 4.0], 2, [4.0]) - assert_step.([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) - assert_step.([2.0, 3.0, 4.0], 2.0, [4]) - assert_step.([10.0, 11.0, 12.0, 13.0], 10.0, []) - assert_step.([10.0, 7.0, 4.0], 10, [nil, -3.0]) + assert_step([2.0, 3.0, 4.0], 2, [4.0]) + assert_step([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) + assert_step([2.0, 3.0, 4.0], 2.0, [4]) + assert_step([10.0, 11.0, 12.0, 13.0], 10.0, [], inf: true) + assert_step([10.0, 7.0, 4.0], 10, [nil, -3.0], inf: true) + assert_step([1.0], 1, [nil, inf]) + assert_step([1.0], 1, [nil, -inf]) + assert_step([1.0], 1, [3, inf]) + assert_step([], 1, [-3, inf]) + assert_step([], 1, [3, -inf]) + assert_step([1.0], 1, [-3, -inf]) + assert_step([1.0], 1, [inf, inf]) + assert_step([], 1, [inf, -inf]) + assert_step([], 1, [-inf, inf]) + assert_step([1.0], 1, [-inf, -inf]) + assert_step([], inf, [2]) + assert_step([], inf, [-2]) + assert_step([], inf, [2, 3]) + assert_step([inf, inf, inf], inf, [2, -3], inf: true) + assert_step([], inf, [2, inf]) + assert_step([inf], inf, [2, -inf]) + assert_step([], inf, [-2, inf]) + assert_step([inf], inf, [-2, -inf]) + assert_step([], inf, [-2, 3]) + assert_step([inf, inf, inf], inf, [-2, -3], inf: true) + assert_step([inf], inf, [inf]) + assert_step([], inf, [-inf]) + assert_step([inf], inf, [inf, inf]) + assert_step([inf], inf, [inf, -inf]) + assert_step([inf], inf, [-inf, -inf]) + assert_step([-inf, -inf, -inf], -inf, [2], inf: true) + assert_step([-inf, -inf, -inf], -inf, [-2], inf: true) + assert_step([-inf, -inf, -inf], -inf, [2, 3], inf: true) + assert_step([], -inf, [2, -3]) + assert_step([-inf], -inf, [2, inf]) + assert_step([], -inf, [2, -inf]) + assert_step([-inf], -inf, [-2, inf]) + assert_step([], -inf, [-2, -inf]) + assert_step([-inf, -inf, -inf], -inf, [-2, 3], inf: true) + assert_step([], -inf, [-2, -3]) + assert_step([-inf, -inf, -inf], -inf, [inf], inf: true) + assert_step([-inf], -inf, [-inf]) + assert_step([-inf], -inf, [inf, inf]) + assert_step([], -inf, [inf, -inf]) + assert_step([-inf], -inf, [-inf, -inf]) end -- cgit v1.2.3