2

to_a over a range of integers behaves differently in this case. Upto 15 decimals, include? returns false but once it reached 16 decimals array considers the decimal digit as part of array.

Why?

2.2.1 :020 > (1..9).to_a.include?(8.999999999999999)
 => false 
2.2.1 :021 > (1..9).to_a.include?(8.9999999999999999)
 => true 
2.2.1 :022 >

And why range only says this is true

2.2.1 :001 > (1..9).include?(8.9)
 => true 
swapab
  • 2,402
  • 1
  • 27
  • 44
  • 1
    `(1..9).include?(8.9)` is the same than `1 <= 8.9 && 8.9 <= 9`. I think it is obvious why this returns `true`. But `(1..9).to_a` returns the array `[1,2,3,4,5,6,7,8,9]`. This leads to the question why does `8.9999999999999999 == 9` eval to `true`, but `8.999999999999999 == 9` to `false`? Floating point shenanigans... – spickermann May 17 '16 at 14:18
  • 1
    Yet another ***"why don't numbers work in language x"*** question. xd – ndnenkov May 17 '16 at 14:44
  • 1
    @spickermann, you should write that as an answer. – ndnenkov May 17 '16 at 14:45

1 Answers1

4

(1..9).include?(8.9) is the same than 1 <= 8.9 && 8.9 <= 9. I think it is obvious why this returns true.

But (1..9).to_a returns the array [1,2,3,4,5,6,7,8,9]. This leads to the another observation:

8.999999999999999 == 9   #=> false
8.9999999999999999 == 9  #=> true

Floating point shenanigans.

You might want to use next_float to investigate the next representable floating-point number (as Tom Lord pointed out in the comments):

8.999999999999999.next_float   #=> 9.0
8.9999999999999999.next_float  #=> 9.000000000000002

Et voilà.

spickermann
  • 100,941
  • 9
  • 101
  • 131
  • 3
    Just to add to this - assuming you are using ruby `v2.2+`, you can use `Float#next_float` to help understand what's happening: `(8.999999999999999).next_float == 9.0; (8.9999999999999999).next_float == 9.000000000000002` - In other words, `8.9999999999999999` is literally the same thing as `9.0` in ruby. Such floating point rounding errors are NOT specific to ruby. – Tom Lord May 17 '16 at 14:54
  • Yes it is same as 9 when you run 8.9999999999999999 on irb its return 9.0 but when you run 8.999999999999999 it returns 8.999999999999998 – Thorin May 17 '16 at 17:23
  • Definitely floating point shenanigans, but remember that a Range is not an Array, so asking why 8.99 is included in `1..9` but not in `(1..9).to_a` is not really possible. Conceptually, `(1..9).to_a` is the same as `(1..9).step(1).to_a`. Take it smaller: `(8.1)..(9.0).to_a` will fail with a `TypeError`, but `(8.1)..(9.0).step(0.1).to_a` will not. – Austin Ziegler May 17 '16 at 18:44