Vincenty vs Haversine Distance Calculations [test] (v2)

Revision 2 of this benchmark created on


Description

[test]

code from: http://jsperf.com/vincenty-vs-haversine-distance-calculations

Setup

/** Converts numeric degrees to radians */
    if (typeof(Number.prototype.toRad) === "undefined") {
        Number.prototype.toRad = function() {
            return this * Math.PI / 180;
        };
    }
    
    function haversine(lat1, lon1, lat2, lon2) {
        var R = 6371;
        var dLat = (lat2 - lat1).toRad();
        var dLong = (lon2 - lon1).toRad();
    
        var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * Math.sin(dLong / 2) * Math.sin(dLong / 2);
        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        var d = R * c;
        d = d.toFixed(3);
        //return Math.round(d);
        return d;
    }
    
    function spherical(lat1, lon1, lat2, lon2) {
        var R = 6371; // km
        var d = Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1)) * R;
        return d.toFixed(3);
    }
    
    function lawofcosines(lat1, lon1, lat2, lon2) {
        var ct = Math.PI/180;
        //var ct = 111.08956;
        var R = 6371;
        // Law of Cosines
        var a = Math.sin(lat1 * ct) * Math.sin(lat2 * ct);
        var b = Math.cos(lat1 * ct) * Math.cos(lat2 * ct) * Math.cos((lon2 - lon1) * ct);
        c = Math.acos(a + b);
        d = R * c;
        return d.toFixed(3);
    }
    
    function distVincenty(lat1, lon1, lat2, lon2) {
        var a = 6378137,
            b = 6356752.314245,
            f = 1 / 298.257223563; // WGS-84 ellipsoid params
        var L = (lon2 - lon1).toRad();
        var U1 = Math.atan((1 - f) * Math.tan(lat1.toRad()));
        var U2 = Math.atan((1 - f) * Math.tan(lat2.toRad()));
        var sinU1 = Math.sin(U1),
            cosU1 = Math.cos(U1);
        var sinU2 = Math.sin(U2),
            cosU2 = Math.cos(U2);
    
        var lambda = L,
            lambdaP, iterLimit = 100;
        do {
            var sinLambda = Math.sin(lambda),
                cosLambda = Math.cos(lambda);
            var sinSigma = Math.sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
            if (sinSigma == 0) return 0; // co-incident points
            var cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
            var sigma = Math.atan2(sinSigma, cosSigma);
            var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
            var cosSqAlpha = 1 - sinAlpha * sinAlpha;
            var cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
            if (isNaN(cos2SigmaM)) cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (ᅡᄃ6)
            var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
            lambdaP = lambda;
            lambda = L + (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
        } while (Math.abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0);
    
        if (iterLimit == 0) return NaN // formula failed to converge
        var uSq = cosSqAlpha * (a * a - b * b) / (b * b);
        var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
        var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
        var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
        var s = b * A * (sigma - deltaSigma);
        s = s / 1000; // convert to km.
        s = s.toFixed(3); // round to 1mm precision
        return s;
    }

Test runner

Ready to run.

Testing in
TestOps/sec
Vincenty formula
distVincenty(-31.965379, 115.822077, -33.85789, 151.214806);
ready
Haversine formula
haversine(-31.965379, 115.822077, -33.85789, 151.214806);
ready
Law of cosines formula
lawofcosines(-31.965379, 115.822077, -33.85789, 151.214806);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.