«Поэтому корректировка уровня точности уже была предложена.
опрос о расчете расстояния между двумя точками широты и долготы на земле по формуле haversine для использования в проектах, где вам нужна функция «найди мое ближайшее».
Формула haversine хорошо обсуждается и решается в 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 ;
Вот набор тестовых запросов для определения расстояния между London Eye и Букингемским дворцом, например. Очевидно, что обычно вы заменяете место назначения полями из вашей базы данных «вещей», с которыми вы хотите сравнить.
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 в тесте,радиус в функции) до 3959 точно.
Результат, который я получил, был интересным (в версии сообщества MySQL 5.2.6), подчеркивает:
| longFormat | distanceMiles |
|------------------|-----------------|
| 0.99826000106148 | 0.9982578754425 |
longFormat математика в запросе,distanceMiles является результатом функции.
Результаты разные ... ОК, так что это незначительно, если использовать функцию в проекте, но мне интересно знать, как одна и та же формула внутри или снаружи функции дает разные результаты.
Я предполагаю, что это связано с длинами FLOAT - они не указаны в функции, я попытался указать их (вплоть до 30,15), чтобы освободить место для всех цифр и выходных данных Я ожидаю - но результаты все еще немного отличаются.