2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,13 +1,19 @@
|
|||
{{Wikipedia}}The '''haversine formula''' is an equation important in navigation,
|
||||
giving great-circle distances between two points on a sphere
|
||||
from their longitudes and latitudes.
|
||||
It is a special case of a more general formula in spherical trigonometry,
|
||||
the '''law of haversines''', relating the sides and angles of spherical "triangles".
|
||||
{{Wikipedia}}
|
||||
|
||||
'''Task:''' Implement a great-circle distance function, or use a library function,
|
||||
to show the great-circle distance between Nashville International Airport (BNA)
|
||||
in Nashville, TN, USA: N 36°7.2', W 86°40.2' (36.12, -86.67)
|
||||
and Los Angeles International Airport (LAX) in Los Angeles, CA, USA: N 33°56.4', W 118°24.0' (33.94, -118.40).
|
||||
<br>
|
||||
The '''haversine formula''' is an equation important in navigation, giving great-circle distances between two points on a sphere from their longitudes and latitudes.
|
||||
|
||||
It is a special case of a more general formula in spherical trigonometry, the '''law of haversines''', relating the sides and angles of spherical "triangles".
|
||||
|
||||
|
||||
;Task:
|
||||
Implement a great-circle distance function, or use a library function,
|
||||
to show the great-circle distance between:
|
||||
* Nashville International Airport (BNA) in Nashville, TN, USA, which is:
|
||||
<big><big> '''N''' 36°7.2', '''W''' 86°40.2' (36.12, -86.67) </big></big> -and-
|
||||
* Los Angeles International Airport (LAX) in Los Angeles, CA, USA, which is:
|
||||
<big><big> '''N''' 33°56.4', '''W''' 118°24.0' (33.94, -118.40) </big></big>
|
||||
<br>
|
||||
|
||||
<pre>
|
||||
User Kaimbridge clarified on the Talk page:
|
||||
|
|
@ -40,3 +46,4 @@ examples in real applications, it is better to use the
|
|||
6371 km. This value is recommended by the International Union of
|
||||
Geodesy and Geophysics and it minimizes the RMS relative error between the
|
||||
great circle and geodesic distance.
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,22 @@
|
|||
DATA : lat1 TYPE char20 VALUE '36.12' ,
|
||||
lon1 TYPE char20 VALUE '-86.67' ,
|
||||
lat2 TYPE char20 VALUE '33.94' ,
|
||||
lon2 TYPE char20 VALUE '-118.4' ,
|
||||
distance TYPE p DECIMALS 1 .
|
||||
CONSTANTS : pi TYPE char20 VALUE '3.141592654',
|
||||
earth_radius TYPE char20 VALUE '6372.8' ."in km
|
||||
distance = earth_radius * acos( cos( ( 90 - lat1 ) * ( pi / 180 ) ) * cos( ( 90 - lat2 ) * ( pi / 180 ) ) + sin( ( 90 - lat1 ) * ( pi / 180 ) ) * sin( ( 90 - lat2 ) * ( pi / 180 ) ) * cos( ( lon1 - lon2 ) * ( pi / 180 ) ) ) .
|
||||
DATA: X1 TYPE F, Y1 TYPE F,
|
||||
X2 TYPE F, Y2 TYPE F, YD TYPE F,
|
||||
PI TYPE F,
|
||||
PI_180 TYPE F,
|
||||
MINUS_1 TYPE F VALUE '-1'.
|
||||
|
||||
PI = ACOS( MINUS_1 ).
|
||||
PI_180 = PI / 180.
|
||||
|
||||
LATITUDE1 = 36,12 . LONGITUDE1 = -86,67 .
|
||||
LATITUDE2 = 33,94 . LONGITUDE2 = -118,4 .
|
||||
|
||||
X1 = LATITUDE1 * PI_180.
|
||||
Y1 = LONGITUDE1 * PI_180.
|
||||
X2 = LATITUDE2 * PI_180.
|
||||
Y2 = LONGITUDE2 * PI_180.
|
||||
YD = Y2 - Y1.
|
||||
|
||||
DISTANCE = 20000 / PI *
|
||||
ACOS( SIN( X1 ) * SIN( X2 ) + COS( X1 ) * COS( X2 ) * COS( YD ) ).
|
||||
|
||||
WRITE : 'Distance between given points = ' , distance , 'km .' .
|
||||
|
|
|
|||
21
Task/Haversine-formula/AMPL/haversine-formula.ampl
Normal file
21
Task/Haversine-formula/AMPL/haversine-formula.ampl
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
set location;
|
||||
set geo;
|
||||
|
||||
param coord{i in location, j in geo};
|
||||
param dist{i in location, j in location};
|
||||
|
||||
data;
|
||||
|
||||
set location := BNA LAX;
|
||||
set geo := LAT LON;
|
||||
|
||||
param coord:
|
||||
LAT LON :=
|
||||
BNA 36.12 -86.67
|
||||
LAX 33.94 -118.4
|
||||
;
|
||||
|
||||
let dist['BNA','LAX'] := 2 * 6372.8 * asin (sqrt(sin(atan(1)/45*(coord['LAX','LAT']-coord['BNA','LAT'])/2)^2 + cos(atan(1)/45*coord['BNA','LAT']) * cos(atan(1)/45*coord['LAX','LAT']) * sin(atan(1)/45*(coord['LAX','LON'] - coord
|
||||
['BNA','LON'])/2)^2));
|
||||
|
||||
printf "The distance between the two points is approximately %f km.\n", dist['BNA','LAX'];
|
||||
3
Task/Haversine-formula/APL/haversine-formula.apl
Normal file
3
Task/Haversine-formula/APL/haversine-formula.apl
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
r←6371
|
||||
hf←{(p q)←○⍺ ⍵÷180 ⋄ 2×rׯ1○(+/(2*⍨1○(p-q)÷2)×1(×/2○⊃¨p q))*÷2}
|
||||
36.12 ¯86.67 hf 33.94 ¯118.40
|
||||
36
Task/Haversine-formula/JavaScript/haversine-formula-2.js
Normal file
36
Task/Haversine-formula/JavaScript/haversine-formula-2.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
((x, y) => {
|
||||
'use strict';
|
||||
|
||||
// haversine :: (Num, Num) -> (Num, Num) -> Num
|
||||
let haversine = ([lat1, lon1], [lat2, lon2]) => {
|
||||
// Math lib function names
|
||||
let [pi, asin, sin, cos, sqrt, pow, round] =
|
||||
['PI', 'asin', 'sin', 'cos', 'sqrt', 'pow', 'round']
|
||||
.map(k => Math[k]),
|
||||
|
||||
// degrees as radians
|
||||
[rlat1, rlat2, rlon1, rlon2] = [lat1, lat2, lon1, lon2]
|
||||
.map(x => x / 180 * pi),
|
||||
|
||||
dLat = rlat2 - rlat1,
|
||||
dLon = rlon2 - rlon1,
|
||||
radius = 6372.8; // km
|
||||
|
||||
// km
|
||||
return round(
|
||||
radius * 2 * asin(
|
||||
sqrt(
|
||||
pow(sin(dLat / 2), 2) +
|
||||
pow(sin(dLon / 2), 2) *
|
||||
cos(rlat1) * cos(rlat2)
|
||||
)
|
||||
) * 100
|
||||
) / 100;
|
||||
};
|
||||
|
||||
// TEST
|
||||
return haversine(x, y);
|
||||
|
||||
// --> 2887.26
|
||||
|
||||
})([36.12, -86.67], [33.94, -118.40]);
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Add-Type -AssemblyName System.Device
|
||||
|
||||
$BNA = New-Object System.Device.Location.GeoCoordinate 36.12, -86.67
|
||||
$LAX = New-Object System.Device.Location.GeoCoordinate 33.94, -118.40
|
||||
|
||||
$BNA.GetDistanceTo( $LAX ) / 1000
|
||||
28
Task/Haversine-formula/PowerShell/haversine-formula-2.psh
Normal file
28
Task/Haversine-formula/PowerShell/haversine-formula-2.psh
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
function Get-GreatCircleDistance ( $Coord1, $Coord2 )
|
||||
{
|
||||
# Convert decimal degrees to radians
|
||||
$Lat1 = $Coord1[0] / 180 * [math]::Pi
|
||||
$Long1 = $Coord1[1] / 180 * [math]::Pi
|
||||
$Lat2 = $Coord2[0] / 180 * [math]::Pi
|
||||
$Long2 = $Coord2[1] / 180 * [math]::Pi
|
||||
|
||||
# Mean Earth radius (km)
|
||||
$R = 6371
|
||||
|
||||
# Haversine formula
|
||||
$ArcLength = 2 * $R *
|
||||
[math]::Asin(
|
||||
[math]::Sqrt(
|
||||
[math]::Sin( ( $Lat1 - $Lat2 ) / 2 ) *
|
||||
[math]::Sin( ( $Lat1 - $Lat2 ) / 2 ) +
|
||||
[math]::Cos( $Lat1 ) *
|
||||
[math]::Cos( $Lat2 ) *
|
||||
[math]::Sin( ( $Long1 - $Long2 ) / 2 ) *
|
||||
[math]::Sin( ( $Long1 - $Long2 ) / 2 ) ) )
|
||||
return $ArcLength
|
||||
}
|
||||
|
||||
$BNA = 36.12, -86.67
|
||||
$LAX = 33.94, -118.40
|
||||
|
||||
Get-GreatCircleDistance $BNA $LAX
|
||||
|
|
@ -1,59 +1,53 @@
|
|||
/*REXX program calculates distance between Nashville and Los Angles airports.*/
|
||||
call pi; numeric digits length(pi)%2 /*use ½ of the decimal digs that PI has*/
|
||||
/*REXX program calculates the distance between Nashville and Los Angles airports.*/
|
||||
call pi; numeric digits length(pi)%2 /*use half of decimal digits of PI. */
|
||||
say " Nashville: north 36º 7.2', west 86º 40.2' = 36.12º, -86.67º"
|
||||
say " Los Angles: north 33º 56.4', west 118º 24.0' = 33.94º, -118.40º"
|
||||
@using_radius='using the mean radius of the earth as ' /*literal for SAY.*/
|
||||
radii.=.; radii.1=6372.8; radii.2=6371 /*mean radii of the earth in kilometers*/
|
||||
say; m=1/0.621371192237 /*M: length of one mile in kilometers.*/
|
||||
do radius=1 while radii.radius\==. /*calc. distance using specific radius.*/
|
||||
d=surfaceDistance( 36.12, -86.67, 33.94, -118.4, radii.radius)
|
||||
say
|
||||
say center(@using_radius radii.radius ' kilometers', 75, '─')
|
||||
say ' Distance between: ' format(d/1 ,,2) " kilometers,"
|
||||
say ' or ' format(d/m ,,2) " statute miles,"
|
||||
say ' or ' format(d/m*5280/6076.1,,2) " nautical (or air miles)."
|
||||
end /*radius*/ /*only display └───◄ 2 digits of dist.*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
surfaceDistance: arg th1,ph1,th2,ph2,r /*use haversine formula for distance.*/
|
||||
numeric digits digits()*2 /*double the number of decimal digits. */
|
||||
ph1 = d2r(ph1-ph2) /*convert degrees ──► radians & reduce.*/
|
||||
th1 = d2r(th1); th2 = d2r(th2) /* " " " " " " */
|
||||
x = cos(ph1) * cos(th1) - cos(th2)
|
||||
y = sin(ph1) * cos(th1)
|
||||
z = sin(th1) - sin(th2)
|
||||
return Asin( sqrt( x**2 + y**2 + z**2) / 2 ) * r * 2
|
||||
/*═════════════════════════════general subroutines════════════════════════════*/
|
||||
d2d: return arg(1) // 360 /*normalize degrees to a unit circle. */
|
||||
d2r: return r2r(arg(1)*pi() / 180) /*normalize and convert deg ──► radians*/
|
||||
r2d: return d2d((arg(1)*180 / pi())) /*normalize and convert rad ──► degrees*/
|
||||
r2r: return arg(1) // (pi()*2) /*normalize radians to a unit circle. */
|
||||
p: return word(arg(1),1) /*pick the first of two words (numbers)*/
|
||||
pi: pi=3.141592653589793238462643383279502884197169399375105820975; return pi
|
||||
|
||||
Acos: procedure; parse arg x; if x<-1 | x>1 then call $81r -1,1,x,"ACOS"
|
||||
return .5*pi()-Asin(x) /*$81R says argument X is out of range,*/
|
||||
/* ··· and the sub isn't included here.*/
|
||||
Asin: procedure; parse arg x 1 z 1 o 1 p; a=abs(x); aa=a*a
|
||||
if a>1 then call $81r -1,1,x,"ASIN" /*X argument is out of range.*/
|
||||
if a>=sqrt(2)*.5 then return sign(x) * Acos(sqrt(1-aa), '-ASIN')
|
||||
do j=2 by 2 until p=z; p=z; o=o*aa*(j-1)/j; z=z+o/(j+1); end
|
||||
return z /* [↑] compute until no more noise. */
|
||||
|
||||
@using_radius= 'using the mean radius of the earth as ' /*a literal for SAY.*/
|
||||
radii.=.; radii.1=6372.8; radii.2=6371 /*mean radii of the earth in kilometers*/
|
||||
say; m=1/0.621371192237 /*M: one statute mile in " */
|
||||
do radius=1 while radii.radius\==. /*calc. distance using specific radius.*/
|
||||
d=surfaceDistance( 36.12, -86.67, 33.94, -118.4, radii.radius); say
|
||||
say center(@using_radius radii.radius ' kilometers', 75, '─')
|
||||
say ' Distance between: ' format(d/1 ,,2) " kilometers,"
|
||||
say ' or ' format(d/m ,,2) " statute miles,"
|
||||
say ' or ' format(d/m*5280/6076.1,,2) " nautical (or air miles)."
|
||||
end /*radius*/ /*these └───◄ displays 2 decimal digs.*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
Acos: return .5*pi() - aSin( arg(1) )
|
||||
d2d: return arg(1) // 360 /*normalize degrees to a unit circle. */
|
||||
d2r: return r2r(arg(1)*pi() / 180) /*normalize and convert deg ──► radians*/
|
||||
r2d: return d2d((arg(1)*180 / pi())) /*normalize and convert rad ──► degrees*/
|
||||
r2r: return arg(1) // (pi()*2) /*normalize radians to a unit circle. */
|
||||
p: return word(arg(1),1) /*pick the first of two words (numbers)*/
|
||||
pi: pi=3.141592653589793238462643383279502884197169399375105820975; return pi
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
surfaceDistance: parse arg th1,ph1,th2,ph2,r /*use haversine formula for distance.*/
|
||||
numeric digits digits() * 2 /*double the number of decimal digits. */
|
||||
ph1= d2r(ph1 - ph2) /*convert degrees ──► radians & reduce.*/
|
||||
th1= d2r(th1); th2 = d2r(th2) /* " " " " " " */
|
||||
x= cos(ph1) * cos(th1) - cos(th2)
|
||||
y= sin(ph1) * cos(th1)
|
||||
z= sin(th1) - sin(th2)
|
||||
return Asin( sqrt( x**2 + y**2 + z**2) / 2 ) * r * 2
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
Asin: procedure; parse arg x 1 z 1 o 1 p; a=abs(x); aa=a*a
|
||||
if a>=sqrt(2) * .5 then return sign(x) * Acos(sqrt(1-aa))
|
||||
do j=2 by 2 until p=z; p=z; o=o*aa*(j-1)/j; z=z+o/(j+1); end /*j*/
|
||||
return z /* [↑] compute until no more noise. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
cos: procedure; parse arg x; x=r2r(x); a=abs(x); Hpi=pi*.5
|
||||
numeric fuzz min(6,digits()-3); if a=pi() then return -1
|
||||
if a=Hpi | a=Hpi*3 then return 0; if a=pi()/3 then return .5
|
||||
if a=pi()*2/3 then return -.5; return .sinCos(1,1,-1)
|
||||
|
||||
sin: procedure; parse arg x; x=r2r(x); numeric fuzz min(5, digits()-3)
|
||||
if abs(x)=pi() then return 0; return .sinCos(x,x,1)
|
||||
|
||||
.sinCos: parse arg z,_,i; q=x*x; p=z; do k=2 by 2; _=-_*q/(k*(k+i)); z=z+_
|
||||
if z=p then leave; p=z; end; return z /*used by SIN & COS*/
|
||||
|
||||
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); i=; m.=9
|
||||
numeric digits 9; numeric form; h=d+6; if x<0 then do; x=-x; i='i'; end
|
||||
parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g*.5'e'_%2
|
||||
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
|
||||
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/
|
||||
numeric digits d; return (g/1)i /*make complex if X < 0.*/
|
||||
if a=pi()*2/3 then return -.5; return .sinCos(1,1,-1)
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
sin: procedure; parse arg x; x=r2r(x); numeric fuzz min(5, digits()-3)
|
||||
if abs(x)=pi() then return 0; return .sinCos(x,x,1)
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
.sinCos: parse arg z 1 p,_,i; q=x*x
|
||||
do k=2 by 2; _=-_*q/(k*(k+i)); z=z+_; if z=p then leave; p=z; end; return z
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); m.=9; numeric form; h=d+6
|
||||
numeric digits; parse value format(x,2,1,,0) 'E0' with g "E" _ .; g=g * .5'e'_ % 2
|
||||
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
|
||||
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/
|
||||
|
|
|
|||
19
Task/Haversine-formula/Rust/haversine-formula.rust
Normal file
19
Task/Haversine-formula/Rust/haversine-formula.rust
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use std::f64;
|
||||
|
||||
static R: f64 = 6372.8;
|
||||
|
||||
fn haversine_dist(mut th1: f64, mut ph1: f64, mut th2: f64, ph2: f64) -> f64 {
|
||||
ph1 -= ph2;
|
||||
ph1 = ph1.to_radians();
|
||||
th1 = th1.to_radians();
|
||||
th2 = th2.to_radians();
|
||||
let dz: f64 = th1.sin() - th2.sin();
|
||||
let dx: f64 = ph1.cos() * th1.cos() - th2.cos();
|
||||
let dy: f64 = ph1.sin() * th1.cos();
|
||||
((dx * dx + dy * dy + dz * dz).sqrt() / 2.0).asin() * 2.0 * R
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let d: f64 = haversine_dist(36.12, -86.67, 33.94, -118.4);
|
||||
println!("Distance: {} km ({} mi)", d, d / 1.609344);
|
||||
}
|
||||
16
Task/Haversine-formula/XQuery/haversine-formula.xquery
Normal file
16
Task/Haversine-formula/XQuery/haversine-formula.xquery
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
declare namespace xsd = "http://www.w3.org/2001/XMLSchema";
|
||||
declare namespace math = "http://www.w3.org/2005/xpath-functions/math";
|
||||
|
||||
declare function local:haversine($lat1 as xsd:float, $lon1 as xsd:float, $lat2 as xsd:float, $lon2 as xsd:float)
|
||||
as xsd:float
|
||||
{
|
||||
let $dlat := ($lat2 - $lat1) * math:pi() div 180
|
||||
let $dlon := ($lon2 - $lon1) * math:pi() div 180
|
||||
let $rlat1 := $lat1 * math:pi() div 180
|
||||
let $rlat2 := $lat2 * math:pi() div 180
|
||||
let $a := math:sin($dlat div 2) * math:sin($dlat div 2) + math:sin($dlon div 2) * math:sin($dlon div 2) * math:cos($rlat1) * math:cos($rlat2)
|
||||
let $c := 2 * math:atan2(math:sqrt($a), math:sqrt(1-$a))
|
||||
return xsd:float($c * 6371.0)
|
||||
};
|
||||
|
||||
local:haversine(36.12, -86.67, 33.94, -118.4)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
10 LET diam=2*6372.8
|
||||
20 LET Lg1m2=FN r((-86.67)-(-118.4))
|
||||
30 LET Lt1=FN r(36.12)
|
||||
40 LET Lt2=FN r(33.94)
|
||||
50 LET dz=SIN (Lt1)-SIN (Lt2)
|
||||
60 LET dx=COS (Lg1m2)*COS (Lt1)-COS (Lt2)
|
||||
70 LET dy=SIN (Lg1m2)*COS (Lt1)
|
||||
80 LET hDist=ASN ((dx*dx+dy*dy+dz*dz)^0.5/2)*diam
|
||||
90 PRINT "Haversine distance: ";hDist;" km."
|
||||
100 STOP
|
||||
1000 DEF FN r(a)=a*0.017453293: REM convert degree to radians
|
||||
Loading…
Add table
Add a link
Reference in a new issue