Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 更正我计算两点之间大圆距离的算法_Java_Algorithm - Fatal编程技术网

Java 更正我计算两点之间大圆距离的算法

Java 更正我计算两点之间大圆距离的算法,java,algorithm,Java,Algorithm,我使用下面的算法来计算两点之间的距离,但它产生了不合理的结果。我错在哪里 private static double distFrom(double latA, double lngA, double latB, double lngB) { double pk = 180/3.14169; double a1 = latA / pk; double a2 = lngA / pk; double b1 = latB / pk; double b2 = l

我使用下面的算法来计算两点之间的距离,但它产生了不合理的结果。我错在哪里

private static double distFrom(double latA, double lngA, double latB, double lngB) {
    double pk = 180/3.14169;

    double a1 = latA / pk;
    double a2 = lngA / pk;
    double b1 = latB / pk;
    double b2 = lngB / pk;

    double t1 = Math.cos(a1)*Math.cos(a2)*Math.cos(b1)*Math.cos(b2);
    double t2 = Math.cos(a1)*Math.sin(a2)*Math.cos(b1)*Math.sin(b2);
    double t3 = Math.sin(a1)*Math.sin(b1);
    double tt = Math.acos(t1 + t2 + t3);

    return 3959*tt;
}

将3.14169替换为Math.PI将略有改进,因为PI的第一位数字是3.14159


此外,还有很多算法。试着用英里、公里和令人作呕的英里来回答问题。

最好用标准字母——L代表经度,B代表纬度。你使用的方法的公式很奇怪。根据维基的说法,这将是:

    double B1 = latA / pk;
    double B2 = latB / pk;
    double dL = (lngA-lngB) / pk;

    double t1 = Math.cos(B1)*Math.cos(B2)*Math.cos(dL);
    double t2 = Math.sin(B1)*Math.sin(B2);

    double tt = Math.acos(t1 + t2);
更少的计算->更少的舍入误差


但是请注意,这个基于acos的公式仅在数学上是正确的,而在计算上是错误的——它在短距离内具有较低的浮点精度!在上述基础上,有更好的基于asin的短距离计算公式和基于atan的通用公式。从中选择一个。

这里是来自(“Vincenty公式的特例”)的atan版本的一个实现,它“适用于所有距离”:

/**
*WGS84中定义的平均地球半径,单位为公里(KM)
*/
公共静态最终双地球半径=6371.0087714;
/**
*以美国英里为单位的平均地球半径,以公里为单位换算
*/
公共静态最终双地球半径=0.621371192;
/**
*以海里为单位的平均地球半径,以公里为单位换算
*/
公共静态最终双地球半径=0.539956803;
/**
*使用“特殊”计算球体上两点之间的距离
*Vincenty公式的案例“用于精确性。这使用了更多的三角函数
*调用,但对于所有距离都更精确。
*

* *有关更多详细信息,请参阅。 * *@param-startat *起点纬度 *@param starton *起点经度 *@param endLat *终点的纬度 *@param endLon *终点的经度 *@param半径 *要使用的球形地球的半径 * *@返回给定半径的点之间的距离 */ 公共静态双大环距离(双止点、双止点、双止点、双止点、双半径) { //换算成弧度 双lonDelta=数学托拉迪安(starton-endLon); 双拉特1=数学托拉迪安(startLat); 双拉特2=数学环面(endLat); //计算重复使用的值 双cos1=数学cos(lat1); 双sin1=数学sin(lat1); double cos2=数学cos(lat2); 双sin2=数学sin(lat2); double cosDelta=数学cos(lonDelta); double top1=cos2*Math.sin(lonDelta); top1*=top1;//平方 双top2=(cos1*sin2)-(sin1*cos2*cosDelta); top2*=top2;//平方 双头=数学sqrt(top1+top2); 双底=(sin1*sin2)+(cos1*cos2*cosDelta); 双弧度=数学坐标(上/下); 返回半径*rad; }


为地球半径选择不同的值可设置所需的单位。这适用于任何半径的球体,因此,只要您知道起点和终点的纬度/经度,就可以使用3389.5公里的半径计算火星上的距离。

您能更详细地解释一下您的输出是什么、您期望的输出是什么以及您已经尝试解决的问题吗,这是哈弗森公式,你可以使用这样一个实现:如果你告诉我们你给这个方法“赋予”了哪些值,得到了哪些结果,期望得到哪些结果,那就太好了。@gilleain的答案是有效的。谢谢。@EpicPandaForce事实上我更喜欢使用公里,但在我的国家,仍然使用英制。如果至少有一个数字是双精度的,那么整个结果就是双精度的,所以不,整数除法是不正确的。返回值也是一样。。成功:返回3959.0*tt@WvdL-不需要,变量tt是双精度的,因此计算和结果是双精度的!最后一行中的系数有4个数字,因此,使用5个以上的PI数字不会得到任何结果!当然,Pi中有一个误差,但它小于最后一行中的舍入误差。在我的公司,需要坚持Java编码规则,计算的距离不必100%准确。我的算法有问题,因为结果比预期的要大10倍。我们不担心小于一英里的错误。距离肯定是不正确的,因为我们还覆盖了大圆算法无法处理的山区。@sandahung如果使用浮点精度差的算法,用4个有意义的数字计数,结果中很容易得到零意义的数字。i、 这将是完全错误的。如果您不能将精度与结果一起计算,并且显然无法计算,请仅使用良好/定义良好/具有高浮点精度的公式。@Sandahung您能给出一些结果比预期结果大10倍的测试用例吗?仅尝试几点,您的方法似乎给出了相当合理的结果(最多可能有1-2%的错误)。@SamYonnou如果常数有4位数字,1%的错误已经是可接受的100倍。因此,代码必须更改-Sandah Aung在代码中是绝对正确的。@Sandahung 1。使用浮点数永远无法获得精确的结果。但你必须设定可接受的错误——绝对或相对形式。2.Java编码规则与任何一组公认的术语都没有矛盾。例如,没有人使用人造卫星,而是使用人造卫星。另一个问题是,如果您的团队不知道标准大地测量术语。是的,使用你所理解的。对不起,我会用标准的方法。3.一英里的距离是多少?4.山区和大圈之间有什么联系?你不能和大地水准面一起工作。
/**
 * Mean earth radius in Kilometers (KM) as defined in WGS84
 */
public static final double EARTH_RADIUS_KM = 6371.0087714;

/**
 * Mean earth radius in US Miles, converted from Kilometers
 */
public static final double EARTH_RADIUS_MI = EARTH_RADIUS_KM * 0.621371192;

/**
 * Mean earth radius in Nautical Miles, converted from Kilometers
 */
public static final double EARTH_RADIUS_NM = EARTH_RADIUS_KM * 0.539956803;

/**
 * Calculates the distance between two points on a sphere using a "special
 * case of the Vincenty formula" for accuracy. This uses more trigonometric
 * calls than other formulas, but is more accurate for all distances.
 * <p/>
 * 
 * For more details, see <a href=
 * "https://en.wikipedia.org/wiki/Great-circle_distance">https://en.wikipedia.org/wiki/Great-circle_distance</a>.
 * 
 * @param startLat
 *          The starting point's latitude
 * @param startLon
 *          The starting point's longitude
 * @param endLat
 *          The ending point's latitude
 * @param endLon
 *          The ending point's longitude
 * @param radius
 *          The radius of the spherical earth to be used
 * 
 * @return The distance between the points for the given radius
 */
public static double greatCircleDistance( double startLat, double startLon, double endLat, double endLon, double radius )
{
    // convert to radians
    double lonDelta = Math.toRadians( startLon - endLon );
    double lat1 = Math.toRadians( startLat );
    double lat2 = Math.toRadians( endLat );

    // compute repeatedly used values
    double cos1 = Math.cos( lat1 );
    double sin1 = Math.sin( lat1 );
    double cos2 = Math.cos( lat2 );
    double sin2 = Math.sin( lat2 );
    double cosDelta = Math.cos( lonDelta );

    double top1 = cos2 * Math.sin( lonDelta );
    top1 *= top1; // squared

    double top2 = (cos1 * sin2) - (sin1 * cos2 * cosDelta);
    top2 *= top2; // squared

    double top = Math.sqrt( top1 + top2 );
    double bottom = (sin1 * sin2) + (cos1 * cos2 * cosDelta);

    double rad = Math.atan( top / bottom );

    return radius * rad;
}