2

This question is related to another stackoverflow discussion distance between long&lat points

Here is the code from the top voted answer:

/*
 * Calculate distance between two points in latitude and longitude taking
 * into account height difference. If you are not interested in height
 * difference pass 0.0. Uses Haversine method as its base.
 * 
 * lat1, lon1 Start point lat2, lon2 End point el1 Start altitude in meters
 * el2 End altitude in meters
 */
private double distance(double lat1, double lat2, double lon1, double lon2,
        double el1, double el2) {

    final int R = 6371; // Radius of the earth

    Double latDistance = deg2rad(lat2 - lat1);
    Double lonDistance = deg2rad(lon2 - lon1);
    Double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
            + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2))
            * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
    Double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double distance = R * c * 1000; // convert to meters

    double height = el1 - el2;
    distance = Math.pow(distance, 2) + Math.pow(height, 2);
    return Math.sqrt(distance);
}

private double deg2rad(double deg) {
    return (deg * Math.PI / 180.0);
}

The top voted answer has the following comment:

"Why not Math.toRadians() instead of deg2rad()? It would be really self-containing."

I looked up the Math.toRadians() method in the documentation and noticed this:

"Converts an angle measured in degrees to an approximately equivalent angle measured in radians. The conversion from degrees to radians is generally inexact."

  1. Is the top voted answer's deg2rad method more or less exact than the Math.toRadians() method?
  2. Using the deg2rad method performs two arithmetic operations and one Math.Pi look up, its not clear how Math.toRadians() performs the convention. Assuming that this distance calculation may be performed frequently and quick response to user input is desired, which conversion method would scale more efficiently?

If the answer to question 1 is that the two methods have roughly the same inexactness/accuracy, I think that I would use Math.toRadians. Using Math.ToRadians makes the code more readable, and I assume that it would scale more efficiently as well.

Community
  • 1
  • 1
gnate
  • 68
  • 1
  • 9
  • If you are going to be running this calculation very often (using `deg2rad()`), it might be worth storing pi / 180 in a constant, so you don't have to recalculate it every time. – DennisW Feb 13 '15 at 22:58
  • The root issue here is that doubles have limited precision and there's no way in any language, really, to have exact reversible conversions like this. I believe `Math.toRadians` is accurate to the greatest possible precision, however. – Louis Wasserman Feb 13 '15 at 23:02
  • You really should not confuse the difference between `Double` and `double`. `double` is a primitive type while `Double` is a wrapper type that adds a lot of overhead. – Clashsoft Feb 14 '15 at 00:16
  • Also `distance * distance` is faster than `Math.pow(distance, 2)` – Clashsoft Feb 14 '15 at 00:18
  • This code comes from the original post. In my adaptation I've changed all Doubles to doubles for that exact reason (as well as changed to ignore elevation changes). I'm not sure why the original author mixed the two, since they did not use any of the wrapper class functionality. I will take the Math.pow advice, I did forget about that part! – gnate Feb 14 '15 at 00:56
  • is "el1" and "el2" are elevations of the points referenced by latitude and longitude ? – Manoj Kumawat Dec 02 '17 at 13:10

2 Answers2

6

Math.toRadians is implemented like this:

public static double toRadians(double angdeg) {
    return angdeg / 180.0 * PI;
}

1) If there is a difference, it's negligible. Math.toRadians does the division first, while that answer does the multiplication first.

2) The only way to find out for sure is to test it, but I would expect that neither is faster since they both do the same thing.

user253751
  • 57,427
  • 7
  • 48
  • 90
  • 5
    If there was a more accurate conversion that `Math.toRadians`, then surely *someone* would have reported this to Sun / Oracle, sometime in the last 20 years or so ... – Stephen C Feb 13 '15 at 23:15
  • 2
    @StephenC funny you mentioned this back in 2013....https://bugs.openjdk.java.net/browse/JDK-8051808 – Jeryl Cook Apr 20 '21 at 13:51
1

In Java 9, the implementations of toRadians and toDegrees were changed to this:

public static double toRadians(double angdeg) {
    return angdeg * DEGREES_TO_RADIANS;
}

public static double toDegrees(double angrad) {
    return angrad * RADIANS_TO_DEGREES;
}

where DEGREES_TO_RADIANS and RADIANS_TO_DEGREES are literal constants. According to the following sources, this gives a 3-fold performance increase in a JMH micro-benchmark.

(We can also infer that the JIT compiler is not performing an optimization that is equivalent to the above. I presume that is because such an optimization could alter the computation's results. That would make it incorrect in general. The JIT compiler probably cannot make the judgement which way gives more accurate results, and it certainly cannot judge if accuracy ... or reproducibility ... is the most important criterion.)

The JDK bug database entries that relate to this are:


In summary, the answer for Java 9 and later is that the standard Math functions are faster than the alternative version. (Whether this was true in Java 8 and earlier is still untested ...)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216