Find with floats

I can't seem to seem to get this find condition to work properly.

I have an object stored in @ip_range, with a float-longitude:

@ip_range.lng

=> 11.967

I then want to match this longitude to a City:

@city = City.find(:first, :conditions => ["lng = ?", @ip_range.lng])

=> nil

But I know that it should work, since there is a match in the table,
with an id of 4:

@city_debug = City.find(4)
=> #<City id: 4, name: "goteborg", lng: 11.967, lat: 57.717, created_at:
"2008-09-29 23:30:34", updated_at: "2008-09-30 16:46:02">

@city_debug.lng

=> 11.967

@city_debug.lng == @ip_range.lng

=> true

Something is wrong in my find-condition, but I can't seem to figure out
what it is... maybe something to with floats in find conditions?

Thanks!

g.

But I know that it should work, since there is a match in the table,
with an id of 4:

@city_debug = City.find(4)
=> #<City id: 4, name: "goteborg", lng: 11.967, lat: 57.717,
created_at:
"2008-09-29 23:30:34", updated_at: "2008-09-30 16:46:02">

@city_debug.lng

=> 11.967

@city_debug.lng == @ip_range.lng

=> true

Short version: using equality with floats isn't a foot idea (not just
in this case - in general)

Fred

Short version: using equality with floats isn't a foot idea (not just
in this case - in general)

Fred

Should I just convert the floats into strings instead perhaps?

Short version: using equality with floats isn't a foot idea (not just
in this case - in general)

Fred

Should I just convert the floats into strings instead perhaps?

I doubt that would help - that's happening anyway when rails generates
the query. == Is fundamentally dangerous with floats, almost all the
time you want to be searching in a range.

I doubt that would help - that's happening anyway when rails generates
the query. == Is fundamentally dangerous with floats, almost all the
time you want to be searching in a range.

Thanks. What would be the correct measure for me to take?

I doubt that would help - that's happening anyway when rails
generates
the query. == Is fundamentally dangerous with floats, almost all the
time you want to be searching in a range.

Thanks. What would be the correct measure for me to take?

instead of x == y, you typically want x => y - delta && x <= y + delta
for some suitable value of delta

Fred

Thanks. What would be the correct measure for me to take?

instead of x == y, you typically want x => y - delta && x <= y + delta
for some suitable value of delta

Fred

Ok. Any ideas how I should implement this is my find condition?

I ended up taking the chicken way out, converting my floats to strings
in new columns and adapting my find conditions to look for those
instead. Works like charm. Thanks anyways, I wonder why it didnt work.

Gu stav wrote:

I ended up taking the chicken way out, converting my floats to strings
in new columns and adapting my find conditions to look for those
instead. Works like charm. Thanks anyways, I wonder why it didnt work.

As indicated by Frederick that's just the nature of a float data type.
It doesn't matter whether it's Ruby, SQL, Java or C. It is never safe to
compare equality on floating point values due to the inherent nature of
how they are stored.

Example: You may be seeing 11.967 but that value is going to get
converted to an IEEE floating point hexadecimal value. Depending on the
loss of precision it is quite possible to have 11.967 == 11.967 =>
false. Depending on how the two values get translated to and from the
IEEE floating point hexadecimal values. 11.967 might actually be stored
in the hex equivalent of 11.9669999999999.

There are a few techniques for dealing with this problem:

Given:
x = 11.967
y = 11.966999999999 <-- loss of precision due to hex<->decimal
conversion

1. Compare based on a range (as suggested in a prior post)
11.9670 <= x < 11.968.

2. Compare string representations of the floating point values:
x == y
=> false
("%.3f" % x) == ("%.3f" % y)
=> true

3. Store values using a fixed point data type (such as DECIMAL in
MySQL):
lng DECIMAL(5,3)
x -> lng
=> 11.967
y -> lng
=> 11.967 <-- rounded based on the rules defined in the database
Making it safe to compare equality on the two values

4. Store fixed decimal values as integers in the database and convert
them when displaying them. I only mention this technique because it is
an option for storing currency values. Rather than store dollars, store
cents instead and convert to dollars with displaying the values on the
view.
$1.60 -> 160 (in the database)

I'll give option 3 a shot, just for fun :wink: Thanks a million for clearing
this out!

g.