2011-06-17 6 views
3

これは、haversine式を使用して地球上の2つの緯度と経度の距離を計算することについての質問です。「最も近いものを見つける」必要があるプロジェクトで使用します。このMySQLのストアド関数は、クエリで計算を行うのとは異なる結果をもたらすのはなぜですか?

haversineの式は、this postのMySQLでよく議論され、解決されています。

次に、this questionに保存された関数に変換するように頼んで、将来のプロジェクトで参照できるようにしました。長い形式の式を覚えたり、再入力する必要はありません。

そのすべてが良好です。私の関数が(わずかに)結果が異なるのは、式に直接入力することだけです。どうしてこれなの?

DELIMITER $$ 

DROP FUNCTION IF EXISTS haversine $$ 

CREATE FUNCTION `haversine` 
    (fromLatitude FLOAT, 
    fromLongitude FLOAT, 
    toLatitude FLOAT, 
    toLongitude FLOAT, 
    unit VARCHAR(20) 
    ) 
    RETURNS FLOAT 
    DETERMINISTIC  
    COMMENT 'Returns the distance on the Earth between two known points of longitude and latitude' 
    BEGIN 
    DECLARE radius FLOAT; 
    DECLARE distance FLOAT; 

    IF unit = 'MILES' THEN SET radius = '3959'; 
    ELSEIF (unit = 'NAUTICAL_MILES' OR unit='NM') THEN SET radius = '3440.27694'; 
    ELSEIF (unit = 'YARDS' OR unit='YD') THEN SET radius = '6967840'; 
    ELSEIF (unit = 'FEET' OR unit='FT') THEN SET radius = '20903520'; 
    ELSEIF (unit = 'KILOMETRES' OR unit='KILOMETERS' OR unit='KM') THEN SET radius = '6371.3929'; 
    ELSEIF (unit = 'METRES' OR UNIT='METERS' OR unit='M') THEN SET radius = '6371392.9'; 
    ELSE SET radius = '3959'; /* default to miles */ 
    END IF; 

    SET distance = (radius * ACOS(COS(RADIANS(fromLatitude)) * COS(RADIANS(toLatitude)) * COS(RADIANS(toLongitude) - RADIANS(fromLongitude)) + SIN(RADIANS(fromLatitude)) * SIN(RADIANS(toLatitude)))); 

    RETURN distance; 
    END$$ 

DELIMITER ; 

はここだけで、たとえば、ロンドンアイ、バッキンガム宮殿の間の距離を見つけるために、設定されたテストクエリのセットです:

は、だからここに私が書いた機能です。明らかに通常は、あなたが比較したい地理的に位置する「物」のデータベースのフィールドで目的地を置き換えます。例では

SET @milesModifier = 3959; 

SET @myLat = 51.503228; 
SET @myLong = -0.119703; 

SET @destLat = 51.501267; 
SET @destLong = -0.142697; 

SELECT @kilometerModifier AS radius, 
    @myLat AS myLat, 
    @myLong AS myLong, 
    @destLat AS destLat, 
    @destLong AS destLong, 
    (@milesModifier * ACOS(COS(RADIANS(@myLat)) * COS(RADIANS(@destLat)) * COS(RADIANS(@destLong) - RADIANS(@myLong)) + SIN(RADIANS(@myLat)) * SIN(RADIANS(@destLat)))) AS longFormat, 
    haversine(@myLat,@myLong,@destLat,@destLong,'MILES') AS distanceMiles, 
    haversine(@myLat,@myLong,@destLat,@destLong,'NAUTICAL_MILES') AS distanceNautical, 
    haversine(@myLat,@myLong,@destLat,@destLong,'KM') AS distanceKm, 
    haversine(@myLat,@myLong,@destLat,@destLong,'METRES') AS distanceMetres,  
    haversine(@myLat,@myLong,@destLat,@destLong,'YARDS') AS distanceYards, 
    haversine(@myLat,@myLong,@destLat,@destLong,'FEET') AS distanceFeet, 
    haversine(@myLat,@myLong,@destLat,@destLong,'') AS distanceDefault 

、我々はマイルを使用している - 私たちは、正確に3959までの半径(テスト中 @milesModifier、関数内 半径)を設定しました。

私が戻った(MySQLの5.2.6コミュニティ版に)面白かった結果、ハイライト:

| longFormat  | distanceMiles | 
|------------------|-----------------| 
| 0.99826000106148 | 0.9982578754425 | 

longFormatは、関数の結果クエリで行わ数学、distanceMilesされています。

結果が異なっている... OK、限りのプロジェクトで関数を使用するなど、取るに足りないそのので、しかし、私は、関数の内部または外部同じ数式が異なる結果を持っているか知って興味があります。

私は、FLOATの長さと関係があると推測しています - 機能には指定されていません。すべての数字のための十分なスペースを与えるために(30,15まで)指定しました。私が期待している出力がありますが、結果は若干異なります。

+0

FLOATデータ型はおおよそのものです。代わりにDECIMALデータ型で試しましたか? http://dev.mysql.com/doc/refman/5.1/en/numeric-types.html – Mike

+0

毎日何か新しいことを学ぶ...近似の利点は何ですか?計算が速くなりますか? – Codecraft

+0

これは[データストレージ要件](http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html)と関連しています。 「浮動小数点値の問題」(http://dev.mysql.com/doc/refman/5.1/en/problems-with-float.html)も参照してください。私はちょうど 'DECIMAL(30,15)'でそれを試して、両方の計算から同じ結果を得ました。あなたはあなたの正確な要求に合うようにそれを調整することができるかもしれません。 – Mike

答えて

5

FLOATは、おおよそのデータ型です - 参照:

Problems with Floating-Point Values
Numeric Types

は、あなたが正しいの精度を持っていることを保証するためにDECIMAL(30,15)FLOATを変更してみてください。あなたは浮動小数点の徹底的な議論をしたい場合は

、あなたがこの記事を試みることができる:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

+0

見る。緯度経度作業のために浮動小数点データ型(32ビット浮動小数点型)によって提供されるより高い精度を使用することには意味がありません。どうして?地球が球体であることの近似、haversine大きな円の公式によって使用される近似は、1メートル程度の距離で作業すると分解し始めるからです。そして、32ビット浮動小数点は、それ以上の精度を提供します。 –

+0

質問の2つの結果の間の距離の差は135ミル(0.135インチ)です。あなたが排水を計画している土木エンジニアなら、これは重要なことかもしれません。それ以外の場合はそうではありません。 –

+0

@Ollie Jones:OPの質問から "*結果は異なります... OK、それはプロジェクトで関数を使用する限り重要ではありませんが、私は同じ式を内部または外部のどのように知ることに興味があります関数は異なる結果を持っています* * "したがって、この状況では精度が必要以上に高いことがわかりましたが、精度のレベルは問題ではありませんでした。 OPはなぜ結果が異なっていたのかを知りたいのですが、理由はFLOATの使用でした。 – Mike

関連する問題