Exclusive float range, Range#step result in counterintuitive result

Discussion in 'Ruby' started by Joey Zhou, Apr 14, 2011.

  1. Joey Zhou

    Joey Zhou Guest

    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/.
     
    Joey Zhou, Apr 14, 2011
    #1
    1. Advertising

  2. Joey Zhou

    Joey Zhou Guest

    Re: Exclusive float range, Range#step result in counterintuitiveresult

    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/.
     
    Joey Zhou, Apr 14, 2011
    #2
    1. Advertising

  3. Re: Exclusive float range, Range#step result in counterintuitiveresult

    On Thu, Apr 14, 2011 at 2:42 PM, Joey Zhou <> wrote:
    > 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/
     
    Robert Klemme, Apr 14, 2011
    #3
  4. Joey Zhou

    7stud -- Guest

    Re: Exclusive float range, Range#step result in counterintuitiveresult

    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/.
     
    7stud --, Apr 14, 2011
    #4
  5. Joey Zhou

    Su Zhang Guest

    Re: Exclusive float range, Range#step result in counterintuitiveresult

    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/.
     
    Su Zhang, Apr 14, 2011
    #5
  6. Joey Zhou

    Joey Zhou Guest

    Re: Exclusive float range, Range#step result in counterintuitiveresult

    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/.
     
    Joey Zhou, Apr 15, 2011
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jaap de verwant slachter
    Replies:
    0
    Views:
    1,269
    jaap de verwant slachter
    Jul 1, 2003
  2. Roy in

    need step by step example

    Roy in, Aug 3, 2003, in forum: ASP .Net
    Replies:
    2
    Views:
    360
    Roy in
    Aug 3, 2003
  3. Sierra Bravo
    Replies:
    5
    Views:
    408
    Thomas Hawtin
    Jul 25, 2005
  4. bd
    Replies:
    0
    Views:
    635
  5. Carsten Fuchs
    Replies:
    45
    Views:
    1,560
    James Kanze
    Oct 8, 2009
Loading...

Share This Page