Numeric#step ã®ä»•æ§˜ã®æ‹¡å¼µã‚’ææ¡ˆã—ã¾ã™ã€‚
 ç¾åœ¨ã€ Numeric#step 㯠limit ã‚’å¿…é ˆå¼•æ•°ã¨ã—ã¦ã„ã‚‹ãŸã‚ã€æ‰‹è»½ã«
ç„¡é™æ•°åˆ—を生æˆã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。Float::INFINITY ãªã„ã— 1/0.0
ã®ã‚ˆã†ãªå€¤ã‚’渡ã›ã°å¯èƒ½ã§ã¯ã‚りã¾ã™ãŒã€ã€Œ1ã‹ã‚‰ä¸Šé™ãªã—ã§ã‚«ã‚¦ãƒ³ãƒˆ
アップã™ã‚‹ã€ã®ã‚ˆã†ãªã‚ˆãã‚ã‚‹è¦ä»¶ã‚’満ãŸã™æ–¹æ³•ã¨ã—ã¦ã¯å†—é•·ã§ã™ã€‚
 ãã“ã§ã€ä¸Šé™(下é™)ãªã—ã§ãƒ«ãƒ¼ãƒ—ã™ã‚‹ã‚ˆã†ã« limit ã‚‚çœç•¥å¯èƒ½ã¨ã—ã€
ãªãŠã‹ã¤å¢—分ã®ã¿ã®æŒ‡å®šã‚‚ã§ãるよã†ã«ç–‘ä¼¼ã‚ーワード引数を導入ã—ã¦
ã¿ã¾ã—ãŸã€‚
1.step {|i| … } # i = 1, 2, 3, …
-1.step(by:-1) {|i| … } # i = -1, -2, -3, …
1.0.step(by: 0.1, to: 2.0).to_a # [1.0, 1.1, …, 2.0] (余談:èª¤å·®ã«æ³¨æ„)
2.step(by:2).take(100) # [2, 4, 6, …, 200]
 ã‚ーワードを by: 㨠to: ã«ã—ãŸã®ã§ã€å¾“æ¥ã®ã‚ˆã†ã«é †åºã§æ„味を
表ã™ã‚ˆã‚Šèªã¿ã‚„ã™ã„ã¨æ€ã„ã¾ã™ã€‚ã„ã‹ãŒã§ã—ょã†ã‹ã€‚
commit 5835d772b01da4f048834ec33b2ca4399f0051d6
Author: Akinori MUSHA [email protected]
Date: Wed Sep 8 21:11:27 2010 +0900
Enhance Numeric#step.
diff --git a/ChangeLog b/ChangeLog
index 5e9b53d…6227f68 100644
— a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Wed Sep 8 21:04:21 2010 Akinori MUSHA [email protected]
+
-
- numeric.c (num_step): Introduce keyword arguments (by: and to:),
- allowing user to generate an infinite sequence of numbers
- without a pain.
Wed Sep 8 06:25:41 2010 Tanaka A. [email protected]
- ext/pathname/pathname.c (path_setuid_p): Pathname#setuid?
translated
diff --git a/numeric.c b/numeric.c
index 25c9e73…98b03c3 100644
— a/numeric.c
+++ b/numeric.c
@@ -107,6 +107,8 @@ VALUE rb_cFixnum;
VALUE rb_eZeroDivError;
VALUE rb_eFloatDomainError;
+static VALUE sym_to, sym_by;
+
void
rb_num_zerodiv(void)
{
@@ -1605,18 +1607,26 @@ ruby_float_step(VALUE from, VALUE to, VALUE
step, int excl)
/*
- call-seq:
-
-
num.step(limit[, step]) {|i| block } -> self
-
-
-
num.step(limit[, step]) -> an_enumerator
-
-
-
num.step(by: step, to: limit]) {|i| block } -> self
-
-
-
num.step(by: step, to: limit]) -> an_enumerator
-
-
-
num.step(limit, step=1) {|i| block } -> self
-
-
-
num.step(limit, step=1) -> an_enumerator
- Invokes block with the sequence of numbers starting at
- num, incremented by step (default 1) on each
- call. The loop finishes when the value to be passed to the block
- is greater than limit (if step is positive) or less
-
-
- than limit (if step is negative). If all the
-
- arguments are integers, the loop operates using an integer
-
- counter. If any of the arguments are floating point numbers, all
-
- are converted to floats, and the loop is executed floor(n +
-
- n*epsilon)+ 1 times, where n = (limit -
-
- than limit (if step is negative), where limit
-
- is defaulted to infinity. In the keyword argument style
-
- (recommended), any of step and limit (default
-
- infinity) can be omitted. In the fixed position argument style,
-
- integer zero as a step (i.e. num.step(limit, 0)) is not allowed
-
- for historical reasons.
-
-
- If all the arguments are integers, the loop operates using an
-
- integer counter. If any of the arguments are floating point
-
- numbers, all are converted to floats, and the loop is executed
-
- floor(n + n*epsilon)+ 1 times, where n = (limit -
- num)/step. Otherwise, the loop starts at num, uses
- either the
<
or>
operator to compare - the counter against limit, and increments itself using the
@@ -1624,11 +1634,17 @@ ruby_float_step(VALUE from, VALUE to, VALUE
step, int excl) - If no block is given, an enumerator is returned instead.
-
-
p 1.step.take(4)
-
-
-
p 10.step(by: -1).take(4)
-
-
-
3.step(to: 5) { |i| print i, " " }
-
1.step(10, 2) { |i| print i, " " }
-
-
-
Math::E.step(Math::PI, 0.2) { |f| print f, " " }
-
-
-
Math::E.step(to: Math::PI, by: 0.2) { |f| print f, " " }
- produces:
-
-
-
[1, 2, 3, 4]
-
-
-
[10, 9, 8, 7]
-
-
-
3 4 5
-
1 3 5 7 9
-
2.71828182845905 2.91828182845905 3.11828182845905
@@ -1636,43 +1652,75 @@ ruby_float_step(VALUE from, VALUE to, VALUE
step, int excl)
static VALUE
num_step(int argc, VALUE *argv, VALUE from)
{ -
- VALUE to, step;
-
VALUE to, step, hash;
-
int inf = 0;
RETURN_ENUMERATOR(from, argc, argv);
- if (argc == 1) {
- switch (argc) {
-
case 0:
- to = DBL2NUM(INFINITY);
- step = INT2FIX(1);
- break;
-
to = argv[0];case 1:
step = INT2FIX(1);
- }
- else {
- if (argc == 2) {
-
to = argv[0];
-
step = argv[1];
- }
- else {
-
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..2)",
argc);
- switch (TYPE(to)) {
- case T_FIXNUM:
- case T_BIGNUM:
- case T_FLOAT:
- case T_RATIONAL:
-
break;
- default:
-
hash = rb_check_convert_type(to, T_HASH, "Hash", "to_hash");
-
if (!NIL_P(hash)) {
- step = rb_hash_aref(hash, sym_by);
- if (NIL_P(step)) step = INT2FIX(1);
- to = rb_hash_aref(hash, sym_to);
- if (NIL_P(to)) to = DBL2NUM(INFINITY);
-
}}
- break;
-
case 2:
- to = argv[0];
- step = argv[1];
if (rb_equal(step, INT2FIX(0))) {
rb_raise(rb_eArgError, “step can’t be 0”);
} - break;
-
default:
- rb_raise(rb_eArgError, “wrong number of arguments (%d for 0…2)”,
argc);
}
- if (FIXNUM_P(from) && FIXNUM_P(to) && FIXNUM_P(step)) {
- if (TYPE(to) == T_FLOAT && isinf(RFLOAT_VALUE(to)))
- inf = 1;
- if (FIXNUM_P(from) && (inf || FIXNUM_P(to)) && FIXNUM_P(step)) {
long i, end, diff;
- i = FIX2LONG(from);
- end = FIX2LONG(to);
- diff = FIX2LONG(step);
- if (inf) {
-
i = FIX2LONG(from);
-
diff = FIX2LONG(step);
- if (diff > 0) {
-
while (i <= end) {
-
rb_yield(LONG2FIX(i));for (;;) {
i += diff;
}
- }
- else {
-
while (i >= end) {
- rb_yield(LONG2FIX(i));
- i += diff;
-
} else {
-
i = FIX2LONG(from);
-
end = FIX2LONG(to);
-
diff = FIX2LONG(step);
-
if (diff > 0) {
-
while (i <= end) {
-
rb_yield(LONG2FIX(i));
-
i += diff;
-
}
-
}
-
else {
-
while (i >= end) {
-
rb_yield(LONG2FIX(i));
-
i += diff;
-
}
}
}
}
@@ -3491,4 +3539,7 @@ Init_Numeric(void)
rb_define_method(rb_cFloat, “nan?”, flo_is_nan_p, 0);
rb_define_method(rb_cFloat, “infinite?”, flo_is_infinite_p, 0);
rb_define_method(rb_cFloat, “finite?”, flo_is_finite_p, 0); -
sym_to = ID2SYM(rb_intern(“to”));
-
sym_by = ID2SYM(rb_intern(“by”));
}
diff --git a/test/ruby/test_numeric.rb b/test/ruby/test_numeric.rb
index f4fbea4…5525634 100644
— a/test/ruby/test_numeric.rb
+++ b/test/ruby/test_numeric.rb
@@ -181,27 +181,58 @@ class TestNumeric < Test::Unit::TestCase
assert_equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)a = []
-
1.step(to: 10) {|x| a << x }
-
assert_equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)
-
a = []
1.step(10, 2) {|x| a << x }
assert_equal([1, 3, 5, 7, 9], a) -
a = []
-
1.step(to: 10, by: 2) {|x| a << x }
-
assert_equal([1, 3, 5, 7, 9], a)
-
assert_raise(ArgumentError) { 1.step(10, 1, 0) { } }
assert_raise(ArgumentError) { 1.step(10, 0) { } } -
assert_nothing_raised { 1.step(by: 0) }
a = []
10.step(1, -2) {|x| a << x }
assert_equal([10, 8, 6, 4, 2], a)a = []
-
10.step(to: 1, by: -2) {|x| a << x }
-
assert_equal([10, 8, 6, 4, 2], a)
-
a = []
1.0.step(10.0, 2.0) {|x| a << x }
assert_equal([1.0, 3.0, 5.0, 7.0, 9.0], a)a = []
-
1.0.step(to: 10.0, by: 2.0) {|x| a << x }
-
assert_equal([1.0, 3.0, 5.0, 7.0, 9.0], a)
-
a = []
1.step(10, 2**32) {|x| a << x }
assert_equal([1], a)a = []
-
1.step(to: 10, by: 2**32) {|x| a << x }
-
assert_equal([1], a)
-
a = []
10.step(1, -(2**32)) {|x| a << x }
assert_equal([10], a) -
a = []
-
10.step(to: 1, by: -(2**32)) {|x| a << x }
-
assert_equal([10], a)
-
a = 10.step.take(4)
-
assert_equal([10, 11, 12, 13], a)
-
a = 10.step(by: -1).take(4)
-
assert_equal([10, 9, 8, 7], a)
end
def test_num2long