Bugs: Browse | Submit New | Admin

[#17922] PostgreSQL 8.2 returns "input is out of range" for certain distance calculations

Date:
2008-02-09 15:31
Priority:
3
Submitted By:
Oshoma Momoh (osh)
Assigned To:
Brandon Keepers (brandon)
Category:
distance calculations
State:
Open
Summary:
PostgreSQL 8.2 returns "input is out of range" for certain distance calculations

Detailed description
PostgreSQL returns the error "input is out of range" when graticule is calculating the distance between a
given origin point and itself.

I've encountered this bug via acts_as_geocodable, doing something like this:
  Place acts_as_geocodable
  Place.find :all, :origin => bad_place, :within => 1.0
where bad_place has a geocode with latitude 43.767626, longitude -79.272319.

The error stems from the WHERE clause in the following SQL code produced by acts_as_geocodable. The WHERE clause is
generated by Graticule::Distance::Spherical.to_sql.

  SELECT places.*, 
  (ACOS( SIN(RADIANS(43.767626)) * SIN(RADIANS(geocodes.latitude)) +   
  COS(RADIANS(43.767626)) * COS(RADIANS(geocodes.latitude)) * 
  COS(RADIANS(geocodes.longitude) - RADIANS(-79.272319)) ) * 6378.135)  
  AS distance 

  FROM places  

  JOIN geocodings ON places.id = geocodings.geocodable_id AND 
  geocodings.geocodable_type = 'Place'

  JOIN geocodes ON geocodings.geocode_id = geocodes.id 

  WHERE ((ACOS( SIN(RADIANS(43.767626)) * SIN(RADIANS(geocodes.latitude)) + 
  COS(RADIANS(43.767626)) * COS(RADIANS(geocodes.latitude)) * 
  COS(RADIANS(geocodes.longitude) - RADIANS(-79.272319)) ) * 6378.135)  <= 1.0) 

In the WHERE clause, the value within ACOS() evaluates to 1 when calculating the distance between the origin and itself.
I believe this triggers a rounding error, which results in PostgreSQL trying to calculate ACOS of some number bigger
than 1, which is Bad.

I have a simple workaround which adds an ":exclude_origin" option to acts_as_geocodable. This avoids the recursive
distance calc altogether. But it's hacky, since it just sidesteps the underlying issue. Happy to give you this patch
if you want it.

A better fix would bound the value passed to ACOS() within the range [-1..1]. I am not smart enough about PostgreSQL
yet to write this code. (E.g. you could do a ceil or floor call, but those calls don't work with double precision numbers.
Is the type conversion easy? Can't seem to find it.)

Another fix would solve the rounding error in PostgreSQL, but that would only help graticule running on newer versions
of the database.

A similar bug is also described here:
http://www.nabble.com/PGError%3A-input-out-of-range-to12217589.html#a12217589

Add A Comment: Notepad

Please login


Followup

No Followups Have Been Posted

Attached Files:

Name Description Download
No Files Currently Attached

Changes:

No Changes Have Been Made to This Item