Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.ruby > #2841 > unrolled thread

Exclusive float range, Range#step result in counterintuitive result

Started byJoey Zhou <yimutang@gmail.com>
First post2011-04-14 07:42 -0500
Last post2011-04-14 13:01 -0500
Articles 5 — 4 participants

Back to article view | Back to comp.lang.ruby


Contents

  Exclusive float range, Range#step result in counterintuitive result Joey Zhou <yimutang@gmail.com> - 2011-04-14 07:42 -0500
    Re: Exclusive float range, Range#step result in counterintuitive result Joey Zhou <yimutang@gmail.com> - 2011-04-14 07:58 -0500
    Re: Exclusive float range, Range#step result in counterintuitive result Robert Klemme <shortcutter@googlemail.com> - 2011-04-14 08:28 -0500
    Re: Exclusive float range, Range#step result in counterintuitive result 7stud -- <bbxx789_05ss@yahoo.com> - 2011-04-14 11:47 -0500
    Re: Exclusive float range, Range#step result in counterintuitive result Su Zhang <zhangsu@live.com> - 2011-04-14 13:01 -0500

#2841 — Exclusive float range, Range#step result in counterintuitive result

FromJoey Zhou <yimutang@gmail.com>
Date2011-04-14 07:42 -0500
SubjectExclusive float range, Range#step result in counterintuitive result
Message-ID<a1e005bd5510e4b0931e34c1d6147eaf@ruby-forum.com>
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/.

[toc] | [next] | [standalone]


#2842

FromJoey Zhou <yimutang@gmail.com>
Date2011-04-14 07:58 -0500
Message-ID<d54e3dd816891c03898fcb2db40b3ae2@ruby-forum.com>
In reply to#2841
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/.

[toc] | [prev] | [next] | [standalone]


#2843

FromRobert Klemme <shortcutter@googlemail.com>
Date2011-04-14 08:28 -0500
Message-ID<BANLkTi=-qJWaDLHkeEDv3Vnj_jmP_mNB3g@mail.gmail.com>
In reply to#2841
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?

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

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

[toc] | [prev] | [next] | [standalone]


#2859

From7stud -- <bbxx789_05ss@yahoo.com>
Date2011-04-14 11:47 -0500
Message-ID<ea9c70684501a99b8ceb08fb50b72503@ruby-forum.com>
In reply to#2841
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/.

[toc] | [prev] | [next] | [standalone]


#2866

FromSu Zhang <zhangsu@live.com>
Date2011-04-14 13:01 -0500
Message-ID<ffe293204df05d4f329c392eb4767bb6@ruby-forum.com>
In reply to#2841
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/.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.ruby


csiph-web