/*
* call-seq:
* num.step(limit, step ) {|i| block } => num
*
* Invokes <em>block</em> with the sequence of numbers starting at
* <i>num</i>, incremented by <i>step</i> on each call. The loop
* finishes when the value to be passed to the block is greater than
* <i>limit</i> (if <i>step</i> is positive) or less than
* <i>limit</i> (if <i>step</i> 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 <i>floor(n + n*epsilon)+ 1</i> times,
* where <i>n = (limit - num)/step</i>. Otherwise, the loop
* starts at <i>num</i>, uses either the <code><</code> or
* <code>></code> operator to compare the counter against
* <i>limit</i>, and increments itself using the <code>+</code>
* operator.
*
* 1.step(10, 2) { |i| print i, " " }
* Math::E.step(Math::PI, 0.2) { |f| print f, " " }
*
* <em>produces:</em>
*
* 1 3 5 7 9
* 2.71828182845905 2.91828182845905 3.11828182845905
*/
static VALUE
num_step(argc, argv, from)
int argc;
VALUE *argv;
VALUE from;
{
VALUE to, step;
RETURN_ENUMERATOR(from, argc, argv);
if (argc == 1) {
to = argv[0];
step = INT2FIX(1);
}
else {
if (argc == 2) {
to = argv[0];
step = argv[1];
}
else {
rb_raise(rb_eArgError, "wrong number of arguments");
}
if (rb_equal(step, INT2FIX(0))) {
rb_raise(rb_eArgError, "step can't be 0");
}
}
if (FIXNUM_P(from) && FIXNUM_P(to) && FIXNUM_P(step)) {
long i, end, diff;
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;
}
}
}
else if (!ruby_float_step(from, to, step, Qfalse)) {
VALUE i = from;
ID cmp;
if (RTEST(rb_funcall(step, '>', 1, INT2FIX(0)))) {
cmp = '>';
}
else {
cmp = '<';
}
for (;;) {
if (RTEST(rb_funcall(i, cmp, 1, to))) break;
rb_yield(i);
i = rb_funcall(i, '+', 1, step);
}
}
return from;
}