2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -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) &nbsp; in Nashville, TN, USA, &nbsp; which is:
<big><big> '''N''' 36°7.2', '''W''' 86°40.2' (36.12, -86.67) </big></big> -and-
* Los Angeles International Airport (LAX) &nbsp;in Los Angeles, CA, USA, &nbsp; 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>

View file

@ -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 .' .

View 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'];

View file

@ -0,0 +1,3 @@
r6371
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

View 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]);

View file

@ -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

View 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

View file

@ -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*/

View 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);
}

View 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)

View file

@ -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