Issue #4576 has been updated by Yui NARUSE.


For people who get this issue, I describe additional comment,

CRuby doesn't specify its internal calculation of floatin point numbers, and ISO C also not.

This issue is by x87 FPU's internal calculation behavior.
x87 always calculates floats with 80bit precision on their register, even if the number is 64bit double.
And if the number is assigned a 64bit double variable, the number is rounded to 64bit.

So if (1.0+1.8*3) is calculated in 80bit precision, it doesn't equals to 6.4 in 64bit precision.
You may force FPU to compare them with 64bit by following ways:
(1) assign the number to a variable
(2) specify -ffloat-store or similar one
(3) specify -msse2 -mfpmath=sse or similar one

(1) is the one Vit suggested and marcandre commited.
It is still problematic because a smart C compiler will optimize out a variable.
Failed test results I showed in [ruby-core:39579] are because of it.
So you must add volatile to guard the variable from such optimization.
But it is barrier for optimization on non x87 FPU.

(2) is not so good because it effects above volatile effect all over the code.
It has speed penalty.

(3) uses SSE2 to calculate floating point numbers.
This doesn't have such speed penalty, but it is less portable.
----------------------------------------
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: Closed
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