Work the Shell - Calculating the Distance between Two Latitude/Longitude Points
Last month, I closed this column with a script that can return latitude/longitude values for two addresses, with the intent ultimately being to have the script calculate the distance between those two points. As an example:
$ farapart.sh "union station, denver co" \
"union station, chicago il"
Calculating lat/long for union station, denver co
= 39.75288, -105.000473
And calculating lat/long for union station, chicago il
= 41.878658, -87.640404
The formula to calculate distance actually is pretty complicated. Here's a JavaScript implementation of the math I showed last month:
var R = 6371; // kilometers
var dLat = (lat2-lat1);
var dLon = (lon2-lon1);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
This is going to be a wee bit tricky to convert into a shell script, needless to say, but because we have to use a more sophisticated math tool than the built-in capabilities of Bash anyway, this also means we have a number of options to work with, including Perl, awk and bc. For that matter, we also can just write a quick C program that solves this equation given four variables, but really, why make it easy when I can make it complex? If I wanted easy, I would whip out some Perl, right? Last month, I promised some bc, so let's see if we can make that rusty old app do the heavy lifting.
The first step mathematically is to convert the lat/lon values we get from the mapping system from degrees to radians. This turns out to be straightforward:
Radians = degrees * ( pi / 180 )
Pi, of course, is 3.1415926535897932384.
Given values like:
41.878658, -87.640404
The radians equivalent of those is then:
0.7309204767, -1.529613605
To warm up with bc, here's a simple command-line way to calculate one of these values:
echo "scale=8; -87.640404 * ( 3.14159265 / 180)" | bc
That's all well and good, but it turns out that the different equations I explored for calculating the distance between two points requires the atan2() function, which isn't part of bc.
Rather than beat my head against the old-school wall until the bits are bloodied, I'm going to throw in the towel and admit that this might just be a bit too complex a mathematical problem for a shell script and bc.
Having spent way more hours than I want to admit trying to get this to work properly in bc, I'm going to “cry uncle” and switch temporarily into a different programming language. I'm going to jump into C for a few lines and whip out a simple program that, given two lat/lon pairs in degrees, calculates the distance between them in miles (Listing 1).
Listing 1. C Distance Program
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define EARTH_RADIUS (6371.0072 * 0.6214)
#define TORADS(degrees) (degrees * (M_PI / 180))
main(int argc, char **argv)
{
double lat1, long1, lat2, long2;
double dLat, dLong, a, c, d;
lat1 = TORADS(atof(argv[1]));
long1 = TORADS(atof(argv[2]));
lat2 = TORADS(atof(argv[3]));
long2 = TORADS(atof(argv[4]));
dLat = lat2 - lat1;
dLong = long2 - long1;
a = sin(dLat/2) * sin(dLat/2) +
cos(lat1) * cos(lat2) * sin(dLong/2) * sin(dLong/2);
c = 2 * atan2(sqrt(a), sqrt(1-a));
printf("%g\n", EARTH_RADIUS * c);
}
Does it work? Let's find out:
$ distance 39.75288 -105.000473 41.878658 -87.640404 917.984
That seems reasonable. The great circle distance between those two points is 917 miles. Google Maps, of course, shows about 10% greater distance, but perhaps that's because there is no direct-as-the-crow-flies route via roads?
Of course, there also are errors with this formula too, because Earth isn't a perfect sphere but rather an oblate spheroid that has a different diameter depending on where you're measuring. But for our purposes, let's just gloss over that problem. You can Google it to learn about things like the Vincenty formula, but that's beyond the scope of this ridiculous sidetrack.
Now we have all the pieces we need: location to lat/lon and distance between two lat/lon points. Let's put it all together.
Dave Taylor has been hacking shell scripts for over thirty years. Really. He's the author of the popular "Wicked Cool Shell Scripts" and can be found on Twitter as @DaveTaylor and more generally at www.DaveTaylorOnline.com.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- New Products
- Linux Systems Administrator
- Senior Perl Developer
- Technical Support Rep
- Web & UI Developer (JavaScript & j Query)
- UX Designer
- Designing Electronics with Linux
- Dynamic DNS—an Object Lesson in Problem Solving
- Using Salt Stack and Vagrant for Drupal Development
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Nice article, thanks for the
2 hours 54 min ago - I once had a better way I
8 hours 40 min ago - Not only you I too assumed
8 hours 58 min ago - another very interesting
10 hours 51 min ago - Reply to comment | Linux Journal
12 hours 44 min ago - Reply to comment | Linux Journal
19 hours 38 min ago - Reply to comment | Linux Journal
19 hours 55 min ago - Favorite (and easily brute-forced) pw's
21 hours 46 min ago - Have you tried Boxen? It's a
1 day 3 hours ago - seo services in india
1 day 8 hours ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?




Comments
Problem of distance variation
I have wrote a bash script (using bc + atan2 definition I found online) to calculate both distances between tree points and angle between two distant points using third as a reference point.
Problem is not your C code, problem is number of decimal places used to calculate.
Using 3 point only 0,5-2Km apart and using 4 to 15 decimal places, I got 15-25% difference in distance calculations. So what your code needs are variables with more decimal points.
Hopes this helps.
in all the code samples
in all the code samples above, "c = 2 * atan2(sqrt(a), sqrt(1-a));" can be written simpler as "c = 2 * asin(sqrt(a));"
listing 1 link fix
It is actually ftp://ftp.linuxjournal.com/pub/lj/listings/issue188/10606l1.txt and not ftp://ftp.linuxjournal.com/pub/lj/listings/issue188/10606.tgz as mentioned above :)
great article! Thanks! - Israel Torres
No bugs I believe, just works as it should
Hello,
I was surprised but the answer is: there is no bug in C program code, the mileage is CORRECT.
The shortest distance between 2 points on earth surface of course is not a straight line, that would be impossible unless you are able to dig a tunnel going underneath!
Remember, when talking about earth you have to think 3D!
This interesting web page shows how the haversine formula works (http://www.movable-type.co.uk/scripts/latlong.html) and a javascript implements the formula on the web page...
Of course the results are shown in Km and not in Miles because Science is polite with numbers...
Anyway using the coordinates Long Beach and Boston the result is 4180 km (that is ~2597 Mi) that is correct.
The hypothetically shortest way to go from East to West on the Northern Earth surface wouldn't be walking on a Parallel (Meridians and Parallels speaking), but would be walking on an arch pushed towards North (for example it would be a route similar to the following Boston-Michigan-NorthDakota-Utha-California-LongBeach).
Just think about what aiplanes do to save as much fuel as possible. Their routes are very different from what you can imagine...
This is php code I use to calculate (in Km) the shortest distance between 2 points on Earth surface (it is raw but it works):
<?php
function getdistance($lat1,$lon1,$lat2,$lon2)
{
$R = 6371;
$dLat = ($lat2 - $lat1) * 3.14159265359 / 180 ;
$dLon = ($lon2 - $lon1) * 3.14159265359 / 180 ;
$lat1 = $lat1 * 3.14159265359 / 180 ;
$lat2 = $lat2 * 3.14159265359 / 180 ;
$a = sin($dLat/2) * sin($dLat/2) + cos($lat1) * cos($lat2) * sin($dLon/2) * sin($dLon/2);
$c = 2 * atan2(sqrt($a),sqrt(1-$a));
$d = $R * $c;
return $d;
}
$LAT1 = $_REQUEST["lat1"];
$LON1 = $_REQUEST["lon1"];
$LAT2 = $_REQUEST["lat2"];
$LON2 = $_REQUEST["lon2"];
print (getdistance($LAT1,$LON1,$LAT2,$LON2));
?>
You can either call it via POST or via GET.
In fact _REQUEST is magic. :)
take care,
Claudio
code
hi, I am gayatri i am writing linux c code for distance calculation using haversine formula i am not getting correct if there is any errors plz correct it and mail me plz.
#include #include main() { //convert degrees to radians float dtor(float degrees) { return(degrees *pi/180); } //convert radians to degrees float rtod(float radians) { return(radians *180.0/pi); } //calculate distance form lat1/lon1 to lat2/log2 using haversine formula //Note lat1/lon1/lat2/lon2 must be in radians //returns float distance in feet float calcDistance(float lat1, float lon1, float lat2, float lon2) { float dlon,dlat,a,c; float dist=0.0; lon1=lon1*-1.0;//make west=positive lon2=lon2*-1.0; dlon=lon2-lon1; dlat=lat2-lat1; a=pow(sin(dlat/2),2)+cos(lat1)*cos(lat2)*pow(sin(dlon/2),2); c=2*atan(sqrt(a),sqrt(1-a)); dist=20925656.2*c; //radius of the earth (6378140 meters) in feet 20925656.2 return(dist); }