Exclusive float range, Range#step result in counterintuitive result

Hi everybody,

I find that:

if
  range.exclude_end? == true
and
  [begin_obj, end_obj, step].grep(Float) != []
and
  [begin_obj, end_obj, step].any? {|f| f != f.to_i}
then
  # result will miss the last one
end

for example:

p (1...6.3).step.to_a # => [1.0, 2.0, 3.0, 4.0, 5.0], missing 6.0
p (1.1...6).step.to_a # => [1.1, 2.1, 3.1, 4.1], missing 5.1
p (1...6).step(1.1).to_a # => [1.0, 2.1, 3.2, 4.300000000000001],
missing 5.4

p (1.0...6.6).step(1.9).to_a # => [1.0, 2.9], missing 4.8
p (1.0...6.7).step(1.9).to_a # => [1.0, 2.9, 4.8], 6.7 == 4.8 + 1.9,
it's ok

The results seem so counterintuitive, is it a bug? Maybe I should report
it?

Thank you!

Joey

···

--
Posted via http://www.ruby-forum.com/.

and another one on Range#max, also *exclusive* range:

p (1...9.3).max # cannot exclude non Integer end value (TypeError)
p (1...9.3).max {|a,b| a <=> b} #=> 9

I think the result should be the same. Maybe the first one should
also return 9, not an error.

···

--
Posted via http://www.ruby-forum.com/.

Hmmm... Float and Range generally don't mix very well. Considering
this the results seem at least consistent - if not expected:

irb(main):001:0> (1.0...6.6).step(1.9).to_a
=> [1.0, 2.9]
irb(main):002:0> (1.0..6.6).step(1.9).to_a
=> [1.0, 2.9, 4.8]

Line 2 cannot go beyond 4.8 because then it would pass 6.6, so the
last value which can really be returned is 4.8. The third dot removes
that value from the list.

It's at least a tad weird. +0.5 for opening a bug.

Kind regards

robert

···

On Thu, Apr 14, 2011 at 2:42 PM, Joey Zhou <yimutang@gmail.com> wrote:

Hi everybody,

I find that:

if
range.exclude_end? == true
and
[begin_obj, end_obj, step].grep(Float) !=
and
[begin_obj, end_obj, step].any? {|f| f != f.to_i}
then
# result will miss the last one
end

for example:

p (1...6.3).step.to_a # => [1.0, 2.0, 3.0, 4.0, 5.0], missing 6.0
p (1.1...6).step.to_a # => [1.1, 2.1, 3.1, 4.1], missing 5.1
p (1...6).step(1.1).to_a # => [1.0, 2.1, 3.2, 4.300000000000001],
missing 5.4

p (1.0...6.6).step(1.9).to_a # => [1.0, 2.9], missing 4.8
p (1.0...6.7).step(1.9).to_a # => [1.0, 2.9, 4.8], 6.7 == 4.8 + 1.9,
it's ok

The results seem so counterintuitive, is it a bug? Maybe I should report
it?

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Joey Zhou wrote in post #992758:

The results seem so counterintuitive, is it a bug? Maybe I should report
it?

By definition, floats cannot be used in ranges.

···

--
Posted via http://www.ruby-forum.com/\.

This looks like a bug to me.

(The problem exists as of 1.9.2-p180.)

In <range.c>, `range_step' is the implementation of Range#step. It calls
`ruby_float_step', which is implemented in <numeric.c>, to handle float
stepping.

The call looks like this:

    else if (ruby_float_step(b, e, step, EXCL(range))) {
  /* done */
    }

The problem is that it passes the `exclude_end?' property of the range
to `ruby_float_step', in our case it is false. Inside the implementation
of `ruby_float_step' is something like:

      n = floor(n + err);
      if (!excl) n++;
      for (i=0; i<n; i++) {
    rb_yield(DBL2NUM(i*unit+beg));
      }

And excl is the last parameter. Clearly if the end value of the range is
x, then the iteration only goes to floor(x)-1.

On the other hand -

p 1.step(6.3).to_a # => [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]

This works since `num_step', again implemented in <numeric.c>,
explicitly passes a false to excl:

    else if (!ruby_float_step(from, to, step, FALSE)) {
        ...

···

--
Posted via http://www.ruby-forum.com/.

Hi,

···

In message "Re: Exclusive float range, Range#step result in counterintuitive result" on Fri, 15 Apr 2011 01:47:03 +0900, 7stud -- <bbxx789_05ss@yahoo.com> writes:

Joey Zhou wrote in post #992758:

The results seem so counterintuitive, is it a bug? Maybe I should report
it?

By definition, floats cannot be used in ranges.

By definition, floats cannot be used in ranges, when you want to
iterate over it.

              matz.

Yukihiro Matsumoto wrote in post #992890:

By definition, floats cannot be used in ranges, when you want to
iterate over it.

              matz.

But it seems that floats can be used in a range which can be iterated.

int..float is OK, it can call methods from Enumerable module.

But int..float sometimes result in confusion.

···

--
Posted via http://www.ruby-forum.com/\.