这是一个有关使用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 ;
这是一组测试查询,旨在查找伦敦眼和白金汉宫之间的距离,仅作为示例。显然,通常您会将目的地替换为您要与之比较的地理位置“事物”数据库中的字段。
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),以便为所有图形和输出留出足够的空间我希望-但结果仍然略有不同。
FLOAT 是一种近似的数据类型-请参阅:
FLOAT
浮点值 数字类型的问题
尝试更改FLOAT以DECIMAL(30,15)确保您具有正确的精度。
DECIMAL(30,15)
如果要深入讨论浮点,可以尝试以下文章:
每个计算机科学家都应了解的浮点运算法则