3

これは、「最も近い場所を見つける」機能が必要なプロジェクトで使用するために、harsine 式を使用して地球上の緯度と経度の 2 点間の距離を計算することに関する質問です。

hasersine 式は、この投稿で MySQL でよく説明され、解決されています。

次に、数式を長い形式で検索、記憶、または再入力することなく、将来のプロジェクトで使用できるように、それをストアド関数に変換することについてこの質問をしました。

大丈夫だよー。私の関数は結果が(わずかに)異なり、数式をクエリに直接入力するだけで、他のすべての条件は同じです。どうしてこれなの?

だからここに私が書いた関数があります:

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

この例では、マイルを使用しているため、半径 (テストでは@milesModifier 、関数ではradius ) を正確に 3959 に設定しました。

返された結果は興味深いものでした (MySQL 5.2.6 コミュニティ エディションで)。ハイライト:

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

longFormatはクエリで実行される計算であり、distanceMilesは関数の結果です。

結果は異なります...プロジェクトで関数を使用する限り、それは重要ではありませんが、関数の内部または外部で同じ式がどのように異なる結果になるかを知りたいです。

私はそれがFLOATの長さに関係していると推測しています-それらは関数で指定されていません.私が持っているすべての数値と出力に十分なスペースを与えるためにそれらを指定しようとしました(30,15まで)期待していますが、結果はまだわずかに異なります。

4

1 に答える 1

5

FLOAT近似データ型です - 以下を参照してください:

浮動小数点値の
数値型の問題

正しい精度になるように、 に変更FLOATしてみてください。DECIMAL(30,15)

浮動小数点について詳しく知りたい場合は、次の記事をお試しください。

すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと

于 2011-06-23T18:33:59.667 に答える