2010-08-03 4 views
2

Le code ci-dessous est utilisé pour calculer les miles entre deux villes. Dans ce cas, c'est pour la distance de Yarmouth, ME à Yarmouth, ME - évidemment zéro - ce qui signifie que les résultats pour les villes à moins de X milles de Yarmouth devraient inclure Yarmouth même.Problème de virgule flottante dans SQL Server 2005

Le problème est que la latitude et la longitude Yarmouth semblent causer une sorte de problème à virgule flottante (je ne l'ai pas vu avec d'autres villes):

DECLARE @fromlong FLOAT, @fromlat FLOAT, @tolong FLOAT, @tolat FLOAT, @test FLOAT 

SET @fromlong = 43.8219 
SET @fromlat = -70.1758 
SET @tolong = 43.8219 
SET @tolat = -70.1758 
SET @test = SIN(@fromlong/(180/PI())) * SIN(@tolong/(180/PI())) + COS(@fromlong/(180/PI())) * COS(@tolong/(180/PI())) * COS(@fromlat/(180/PI()) - @tolat/(180/PI())) 

PRINT @test /*** Displays "1" ***/ 

SELECT 3963.0 * ACOS(@test) /*** Displays "a domain error has occurred" ***/ 

D'abord, est-ce un SQL Server punaise? Deuxièmement, que puis-je faire pour contourner le problème? Je sais dans l'exemple ci-dessus que je pourrais avoir une logique pour IF @test > 1, mais cet exemple est distillé à partir d'une requête intégrée dans une application web (pas mon choix), donc je dois corriger la requête, c'est-à-dire corriger le calcul sans recourir à TSQL si possible, et sans distorsion d'autres valeurs de retour. Des idées?

+0

Pourquoi flotter si vous avez besoin de valeurs exactes? – buckbova

+0

Étais-je censé avoir une erreur d'exécution du code? Je n'ai pas obtenu un Juste un résultat de 0. – buckbova

+0

Bonne prise - Je suis retourné et ai regardé la base de données et j'ai réalisé que j'utilisais SSMS 2008 mais la base de données est 2005. Je changerai le poste en conséquence. – gfrizzle

Répondre

3

Le consensus des commentaires semble être l'utilisation de FLOAT. J'ai seulement utilisé FLOAT dans l'exemple parce que c'était le type de données des colonnes à partir desquelles la latitude/longitude était lue, mais cela semble être le coeur du problème. Puisque je ne peux pas changer les types de données des colonnes elles-mêmes, la solution la plus simple était de changer le type de données du calcul résultant, ce qui semble fonctionner très bien dans tous les cas:

SELECT 3963.0 * ACOS(CONVERT(DECIMAL(10, 6), @test)) 

Je réalise en laissant le calcul comme un flotteur Cela pourrait entraîner de petites erreurs d'arrondi, mais elles sont acceptables pour cette application. Merci à tous ceux qui ont commenté.

Questions connexes