Calling math and php gurus

Take the following function that I shamelessly stole from somewhere on google:


function distance($lat1, $lon1, $lat2, $lon2, $unit) {
    $theta = $lon1 - $lon2;
    $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
    $dist = acos($dist);
    $dist = rad2deg($dist);
    $miles = $dist * 60 * 1.1515;
    $unit = strtoupper($unit);

    if ($unit == "K") {
        return ($miles * 1.609344);
    } else if ($unit == "N") {
        return ($miles * 0.8684);
    } else {
        return $miles;
    }
}

Appears to work great. Then I tried comparing the same long / lat to each other, and the result is not 0…

I’m not sure if this is a crazy happening of PHP and the way it stores the number or perhaps the math itself? I found another function that was written differently and the same thing happens.

Can you provide samples?

Here is what I did:

// Lima 40.329796, -84.210205
// Columbus 39.968701, -83.001709
$distance1 = distance(40.329796, -84.210205, 40.329796, -84.210205, 'N');
$distance2 = distance(40.329796, -84.210205, 40.329796, -84.210205, 'N');
var_dump($distance1, $distance2); // float(0) float(0) is the output

// Lima 40.329796, -84.210205
// Columbus 39.968701, -83.001709
$distance1 = distance(40.329796, -84.210205, 39.968701, -83.001709, 'N');
$distance2 = distance(40.329796, -84.210205, 39.968701, -83.001709, 'N');
var_dump($distance1, $distance2); // float(59.505373431747) float(59.505373431747) is the output

Yes, that works great, try this:

echo distance(40.329796, -84.210205, 40.329796, -84.210205, ‘N’);

I get an output of float(0) when I do a var_dump.

<?php
function distance($lat1, $lon1, $lat2, $lon2, $unit) {
    $theta = $lon1 - $lon2;
    $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
    $dist = acos($dist);
    $dist = rad2deg($dist);
    $miles = $dist * 60 * 1.1515;
    $unit = strtoupper($unit);

    if ($unit == "K") {
        return ($miles * 1.609344);
    } else if ($unit == "N") {
        return ($miles * 0.8684);
    } else {
        return $miles;
    }
}

// Lima 40.329796, -84.210205
// Columbus 39.968701, -83.001709
$distance1 = distance(40.329796, -84.210205, 39.968701, -83.001709, 'N');
$distance2 = distance(40.329796, -84.210205, 39.968701, -83.001709, 'N');
$distance3 = distance(40.329796, -84.210205, 40.329796, -84.210205,'N');
var_dump($distance1, $distance2, $distance3);
?>

That’s right, it was only on a few examples was I seeing this happen. I’ll try to find one of them.

The only thing i can think of is a rounding error in deg2rad? But… no, that should come up with the same number even if it rounds wrong…

Please do, as I’m interested in tracking that down. I imagine it is a floating point scenario or something with precision but without a sample that produces it, it is hard for me to verify that.

Simplifying the math;
$theta = 0;
cos(0) = 1;

$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));

becomes

$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2));

or, because $lat1 and $lat2 are the same;

$dist = sin(deg2rad($lat1))^2 +  cos(deg2rad($lat1))^2

the values of deg2rad for the same value will be the same, so i’ma call it $x

$dist = sin($x)^2 +  cos($x)^2

My geometry lessons tell me that sin(x)^2+cos(x)^2 = 1.

acos(1) = 0.

so $dist should = 0.

It was especially interesting because it would return the same incorrect response every time it occurred (5.xxxxxxxxxxxxxx) not sure of the decimals, but it was long and truncated as well.