Exclusive float range, Range#step result in counterintuitive result

J

Joey Zhou

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
 
J

Joey Zhou

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.
 
R

Robert Klemme

Hi everybody,

I find that:

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

for example:

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

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

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

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
=3D> [1.0, 2.9]
irb(main):002:0> (1.0..6.6).step(1.9).to_a
=3D> [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

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

7stud --

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.
 
S

Su Zhang

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)) {
...
 
J

Joey Zhou

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top