From: Yui NARUSE Date: 2011-09-27T19:47:45+09:00 Subject: [ruby-core:39741] [Ruby 1.9 - Bug #4576] Range#step miss the last value, if end-exclusive and has float number Issue #4576 has been updated by Yui NARUSE. Masahiro Tanaka wrote: > I think your solution [ruby-core:39612] is acceptable because the > modification of the last value is small. If we need more uniformity of > the sequence, a possible algorithm is: I'm pro of this side. > $ ruby -e 'e=1+1E-12; y=0; a=(1.0..e).step(1E-16).map{|x|s=x-y;y=x;s}; > p a[-6..-1]' > [2.220446049250313e-16, 0.0, 2.220446049250313e-16, 0.0, > 2.220446049250313e-16, 0.0] > > The difference is not equal to given step argument. Even though > step*(n-1) == last-begin is still holds, This does not hold if you > decrease n, so I think the repeat times must not be decreased. Hmm, you're correct, I fixed a patch. Updated patch is following: diff --git a/numeric.c b/numeric.c index 973da1f..5702d08 100644 --- a/numeric.c +++ b/numeric.c @@ -1689,7 +1689,6 @@ ruby_float_step(VALUE from, VALUE to, VALUE step, int excl) if (unit > 0 ? beg <= end : beg >= end) rb_yield(DBL2NUM(beg)); } else { - double prev = beg == 0 ? -1 : 0; if (err>0.5) err=0.5; if (excl) { if (n>0) { @@ -1701,15 +1700,15 @@ ruby_float_step(VALUE from, VALUE to, VALUE step, int excl) } else { n = floor(n + err) + 1; } - for (i=0; i= end) { - if (!excl) rb_yield(DBL2NUM(end)); - break; + if (end < (n-1)*unit+beg) { + for (i=0; i [1.0, 2.0, 3.0, 4.0, 5.0], no 6.0 p (1.1...6).step.to_a # => [1.1, 2.1, 3.1, 4.1], no 5.1 p (1...6).step(1.1).to_a # => [1.0, 2.1, 3.2, 4.300000000000001], no 5.4 p (1.0...6.6).step(1.9).to_a # => [1.0, 2.9], no 4.8 p (1.0...6.7).step(1.9).to_a # => [1.0, 2.9, 4.8] p (1.0...6.8).step(1.9).to_a # => [1.0, 2.9, 4.8], no 6.7 Maybe the #step is ok on integers, but there's something wrong if the range is end-exclusive and contain float numbers. =end -- http://redmine.ruby-lang.org