0

Why on earth does comparing a float value of 1.0, to an integer value of 1, return true?

puts '1.0'.to_i
puts '1.0'.to_i == 1.0 #so 1 == 1.0 is true?
puts 1.0 == 1 #wtf?

Does Ruby only read the first part of the floatin point value and then short circuit? Wuld someone be able to explain with a link to some documentation please? I have flipped through the API but I don't even know what to look for in this case...

5 Answers5

5

== compares the value, the value of 1.0 is equal to 1 in math, so it's not much surprising. To compare value as well as type, you can use eql?:

1.0 == 1
#=> true
1.0.eql? 1
#=> false
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • Intuitively, this answer is correct. But this doesn't explain _at all_ how `==` does this. – Max Oct 22 '14 at 16:00
1

In Ruby, == is a method. That means to understand it you need to look at the specific class calling it.

1 == 1.0

The caller is 1, a Fixnum. So you need to look at Fixnum#==.

1.0 == 1

The caller is 1.0, a Float. So you need to look at Float#==.

A surprising result of this is that == is not necessarily symmetric: a == b and b == a could call completely different methods and return completely different results. In this case though, both == methods end up calling the C function rb_integer_float_eq which converts both operands to the same data type before comparing them.

Max
  • 21,123
  • 5
  • 49
  • 71
  • Max you answered this question perfectly. I checked the API and you are indeed correct. –  Oct 22 '14 at 17:16
0

Most languages will automatically increase the precision of a variable's type in order to perform operations on them such as compare, add, multiply, etc. They "usually" do not decrease the precision, nor unnecessarily increase it. E.g. 1/2 = 0, but 1.0/2.0 = 0.5.

Greg Miller
  • 469
  • 4
  • 11
  • This sounds like a guess, at best. – Max Oct 22 '14 at 16:05
  • http://books.google.com/books?id=jcUbTcr5XWwC&pg=PA80&lpg=PA80&dq=ruby+implicit+type+conversion&source=bl&ots=fJBjAi7ugA&sig=a474yV66is29Hw6Gg0u-aXoQLWQ&hl=en&sa=X&ei=YttHVJKmLqj_8AH59oDoDw&ved=0CCsQ6AEwAjgK#v=onepage&q=ruby%20implicit%20type%20conversion&f=false – Greg Miller Oct 22 '14 at 16:30
  • You should read that section more closely. It says nothing about implicit conversions being used for `==` with Fixnum and Float. My answer details the exact mechanism causing the behavior in the question. tl;dr it works by calling a function _specifically designed_ to compare Fixnums and Floats. – Max Oct 22 '14 at 16:36
  • "Unfortunately, the circumstances under which these implicit conversion methods are called are not well documented." – Greg Miller Oct 22 '14 at 16:55
  • Could you speak to me rather than quoting at me? It doesn't matter that the conversions are not well documented: my answer points out the exact code path that is used for this comparison and it has nothing to do with implicit conversion as described in that book. – Max Oct 22 '14 at 17:01
  • The question was "why" it does what it does, not "how". I believe my answer correctly addresses the "why", yours addresses the "how". But the issue with referring to the source code is that it's not documented, and will be implementation specific. – Greg Miller Oct 22 '14 at 18:49
0

Actually there already is a nice answer "What's the difference between equal?, eql?, ===, and ==?" about equality in Ruby, with references and stuff. There is a surprising amount of ways to compare for equality in Ruby, each with its own purpose.

Since mathematical meaning is not enough for you, you can compare differently. Like, say, eql? that is heavily used in Hashes to determine if two keys are the same. And it turns out that 1.0 and 1 are different keys! his is what I get in IRB of Ruby 2.1.2:

> 1.0.eql?(1.0)
 => true 
> 1.eql?(1)
 => true 
> 1.eql?(1.0)
 => false
Community
  • 1
  • 1
D-side
  • 9,150
  • 3
  • 28
  • 44
-1

Ruby is coercing the operands of == (as needed) to the same type, then performing a comparison of their numeric values. This is normally what you want for numeric comparisons.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Crap, this isn't what I want at all, but I understand the concept of promotion. I guess I will have to use the to_i method when doing comparisons of this type. –  Oct 22 '14 at 14:46
  • Editing "promoting" to the more accurate term "coercing". The idea is still the same. – John Bollinger Oct 22 '14 at 14:48
  • `coerce` only affects numeric operations (+-*/ etc.). `==` is common to all objects. – Max Oct 22 '14 at 16:17
  • @Max Actually `==` is redefined for most of the core Ruby types. [`Fixnum#==` performs coercion](https://github.com/ruby/ruby/blob/trunk/numeric.c#L3265-L3279) just like the other methods you mentioned. – toro2k Oct 31 '14 at 15:17
  • 1
    @toro2k Coercion in Ruby refers to a very specific thing: calling the `coerce` method. Although `Fixnum#==` does try to compare by value by converting operands, it does _not_ perform coercion in this literal sense. If you were to define a new numeric class with a coerce method, you would not get automatic correct behavior with `==`. – Max Oct 31 '14 at 18:06