< :前の番号
^ :番号順リスト
> :次の番号
P :前の記事(スレッド移動)
N :次の記事(スレッド移動)
|<:前のスレッド
>|:次のスレッド
^ :返事先
_:自分への返事
>:同じ返事先を持つ記事(前)
<:同じ返事先を持つ記事(後)
---:分割してスレッド表示、再表示
| :分割して(縦)スレッド表示、再表示
~ :スレッドのフレーム消去
.:インデックス
..:インデックスのインデックス
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<n; i++) {
- double d = i*unit+beg;
- if (d == prev) continue;
- if (d >= end) {
- if (!excl) rb_yield(DBL2NUM(end));
- break;
+ 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 {
+ for (i=0; i<n; i++) {
+ rb_yield(DBL2NUM(i*unit+beg));
}
- prev = d;
- rb_yield(DBL2NUM(d));
}
}
return TRUE;
diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb
index 4fc8a6b..531ff04 100644
--- a/test/ruby/test_float.rb
+++ b/test/ruby/test_float.rb
@@ -517,11 +517,7 @@ class TestFloat < Test::Unit::TestCase
assert_equal(11, (a..b).step(s).to_a.length)
end
- prev = 0
- (1.0..(1.0+1E-15)).step(1E-16) do |current|
- assert_not_equal(prev, current)
- prev = current
- end
+ assert_equal(11, (1.0..(1.0+1E-15)).step(1E-16).to_a.length)
(1.0..12.7).step(1.3).each do |n|
assert_operator(n, :<=, 12.7)
----------------------------------------
Bug #4576: Range#step miss the last value, if end-exclusive and has float number
http://redmine.ruby-lang.org/issues/4576
Author: Joey Zhou
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: 1.9.4
ruby -v: -
=begin
Hi, I find that:
* if: range.exclude_end? == true
* and: any one in [begin_obj, end_obj, step] is a true Float(f.to_i != f)
* and: unless begin_obj + step*int == end_obj
* then: the result will miss the last value.
for example:
p (1...6.3).step.to_a # => [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