From: Masahiro TANAKA <masa16.tanaka@...> Date: 2011-09-21T19:13:28+09:00 Subject: [ruby-core:39655] Re: [Ruby 1.9 - Bug #4576] Range#step miss the last value, if end-exclusive and has float number 2011/9/20 Tanaka Akira <akr@fsij.org>: > However the algorithm doesn't solve [ruby-core:39602] and [ruby-core:39606]. > > % ./ruby -e 'a = (1.0..12.7).step(1.3).to_a; p a.all? {|n| n <= 12.7 }, a.last' > false > 12.700000000000001 In my opinion, this behaviour is acceptable because the last value generated by step method is close to the given Range-end value. In the numerical calculation, the uniformity of sequence is more important. Uniformity means that, if the generated sequence is { x(0), x(1), ..., x(n-1) }, then x(i+1)-x(i) is constant. 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: if (end < (n-1)*unit+beg) { for (i=0; i<n; i++) { rb_yield(DBL2NUM((n-1-i)/(n-1)*beg+i/(n-1)*end)); } } else .. > % ./ruby -e 'e = 1+1E-12; a = (1.0 ... e).step(1E-16).to_a; p a.all? > {|n| n < e }, a.last' > false > 1.000000000001 This problem is hard to solve because this is due to the accuracy of floating point value. The last part of this sequence is; $ ruby -e 'e=1+1E-12; y=0; a=(1.0..e).step(1E-16).map{|x|"%.20f"%x}; p a[-6..-1]' ["1.00000000000099964481", "1.00000000000099964481", "1.00000000000099986686", "1.00000000000099986686", "1.00000000000100008890", "1.00000000000100008890"] The same value appears consecutively. Therefore, even after the last value is excluded, the last value is equal to the range-end. This is because this calculation exceeds the capability of floating point arithmetic. In my opinion, this case is not suitable for the test case. You can also see $ 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. Masahiro Tanaka