Java Math.toRadians(角度) vs 硬计算

Java Math.toRadians(angle) vs hard-calculated

这个问题与另一个 Whosebug 讨论有关distance between long&lat points

这是得票最多的答案中的代码:

/*
 * 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);
}

投票最高的答案有以下评论:

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

我在 documentation 中查找了 Math.toRadians() 方法并注意到了这一点:

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

  1. 票数最高的答案的 deg2rad 方法是否比 Math.toRadians() 方法更精确?
  2. 使用 deg2rad 方法执行两次算术运算和一次 Math.Pi 查找,不清楚 Math.toRadians() 如何执行约定。假设这种距离计算可能会频繁执行,并且需要对用户输入做出快速响应,那么哪种转换方法的缩放效率更高?

如果问题1的答案是两种方法大致相同inexactness/accuracy,我想我会用Math.toRadians。使用 Math.ToRadians 使代码更具可读性,我认为它也会更有效地扩展。

Math.toRadians是这样实现的:

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

1) 如果有差异,可以忽略不计。 Math.toRadians 先做除法,而那个答案先做乘法。

2) 确定答案的唯一方法是对其进行测试,但我希望两者都不会更快,因为它们都做同样的事情。

在Java 9中,toRadianstoDegrees的实现改为:

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

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

其中 DEGREES_TO_RADIANSRADIANS_TO_DEGREES 是文字常量。根据以下来源,这使 JMH 微基准测试的性能提高了 3 倍。

(我们还可以推断 JIT 编译器没有执行与上述等效的优化。我认为这是因为这样的优化可能会改变计算结果。这会使它不正确 一般来说。JIT 编译器可能无法判断哪种方式给出的结果更准确,而且它当然无法判断准确性...或可重复性...是否是最重要的标准。)

与此相关的 JDK 个错误数据库条目是:


总而言之,Java 9 及更高版本的答案是标准 Math 函数比替代版本更快。 (这在 Java 8 和更早版本中是否正确尚未测试...)