【问题标题】:iOS and Android: Same function, same input, different decimal outputiOS和Android:相同的功能,相同的输入,不同的十进制输出
【发布时间】:2019-01-07 15:58:51
【问题描述】:

我们在iOS和Android中使用相同的函数,相同的输入数据,输出的第二个/第三个十进制数不同。

我可以理解原因,我们确实需要完全相同的输出。

跟随iOS功能:

func angleBoundSetFromPosition(userPosition: CLLocationCoordinate2D, distance: Double, bearing: Double) -> (CLLocationCoordinate2D) {
    let dist = Float(distance) / Float(6371)
    let brg = Float(bearing.degreesToRadians)
    let lat1 = Float(userPosition.latitude).degreesToRadians
    let lon1 = Float(userPosition.longitude).degreesToRadians
    let lat2 = asin(sin(lat1) * cos(dist) + cos(lat1) * sin(dist) * cos(brg))
    let lon2 = lon1 + atan2(sin(brg) * sin(dist) * cos(lat1), cos(dist) - sin(lat1) * sin(lat2))
    print("for: \(bearing), dist: \(dist), bearing: \(brg),  lat1: \(lat1), lon1: \(lon1), lat2: \(lat2), lon2: \(lon2)")
    return CLLocationCoordinate2D(latitude: Double(lat2.radiansToDegrees), longitude: Double(lon2.radiansToDegrees))
}

iOS 扩展:

extension FloatingPoint {
    var degreesToRadians: Self { return self / 180 * .pi}
    var radiansToDegrees: Self { return self * 180 / .pi }
}

这里是java:

public static LatLng getDestinationPoint(LatLng source, double brng, double dist) {
            dist = dist / 6371;
            brng = Math.toRadians(brng);

            double lat1 = Math.toRadians(source.latitude), lon1 = Math.toRadians(source.longitude);
            double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) +
                    Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
            double lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *
                            Math.cos(lat1),
                    Math.cos(dist) - Math.sin(lat1) *
                            Math.sin(lat2));
            if (Double.isNaN(lat2) || Double.isNaN(lon2)) {
                return null;
            }
            return new LatLng(Math.toDegrees(lat2), Math.toDegrees(lon2));
    }

输入:

UserPosition(45.6091463, 8.8496677)
distance = 10
called once with bearing = -45, and once with bearing 135

输出:

安卓

{latitude 45.621861885764005, longitude 8.83148183051733}
{latitude 45.596425230386295, longitude 8.867843324603944}

iOS

{latitude 45.67270183849526, longitude 8.758660791031469}
{latitude 45.54551866514264, longitude 8.940468486905017}

【问题讨论】:

  • 编辑您的问题并添加您测试的输入数据以及 Java 和 iOS/Swift 结果。
  • degreesToRadiansradiansToDegrees 是如何实现的?
  • 更新了更多信息

标签: java android ios swift


【解决方案1】:

当您将函数从一种语言转换为另一种语言时,您应该尝试使用相同的变量名。在这种情况下,对于 Java,您可能还想statically import all Math functions,这样您就没有最终无法进行比较的函数。

这是快速函数:

let lat2 = asin(sin(lat1)) * cos(newDistance) + cos(lat1) * sin(newDistance) * cos(newBearing)
                         ^

这是美化的 Java 函数:

double lat2 = asin(sin(lat1) * cos(newDistance) + cos(lat1) * sin(newDistance) * cos(newBearing));
                                                                                                ^

您的 Swift 函数在 sin 后面有一个括号,而 Java 公式在末尾有一个括号。

因此,分歧源于这两个方程都不匹配,而不是任何形式的双重数学问题。

双精度漂移通常只发生在小范围内。如果您的测试数据显示的值大不相同,则更有可能实现不正确,而不是解释

这是装箱的测试代码。

public static void main(String[] args) {
    System.out.println(getDestinationPoint(new LatLng(45.6091463, 8.8496677), -45, 10));
    System.out.println(getDestinationPoint(new LatLng(45.6091463, 8.8496677), 135, 10));
}

public static LatLng getDestinationPoint(LatLng source, double bearing, double distance) {
    double newDistance = distance / 6371;
    double newBearing = toRadians(bearing);
    double lat1 = toRadians(source.latitude);
    double lon1 = toRadians(source.longitude);
    double lat2 = asin(sin(lat1) * cos(newDistance) + cos(lat1) * sin(newDistance) * cos(newBearing));
    double lon2 = lon1 + atan2(sin(newBearing) * sin(newDistance) * cos(lat1), cos(newDistance) - sin(lat1) * sin(lat2));
    if (Double.isNaN(lat2) || Double.isNaN(lon2)) {
        return null;
    }
    return new LatLng(toDegrees(lat2), toDegrees(lon2));
}

static class LatLng {
    double latitude;
    double longitude;

    public LatLng(double lat, double lon) {
        latitude = lat;
        longitude = lon;
    }

    public String toString() {
        return latitude + ", " + longitude;
    }
}

【讨论】:

  • 你对括号的看法是对的,但现在不同之处在于更多证据,我将用一些数据更新问题
  • @Miotz 我在纯 Java 中的结果是 45.672701838495264, 8.758660791031469 | 45.545518665142644, 8.940468486905017,与您的 iOS/Swift 结果匹配,无法重现。我直接从问题中使用您的代码,以及存储值的虚拟类 LatLng。
  • @Miotz 已附加。
  • toRadians() 是从 swift 转换而来的 java 转换?因为我们仍然有不同的输出,唯一的区别是数学库的使用
  • @Miotz toRadians 是内置的 Math.toRadians
【解决方案2】:

这个问题应该只发生在“双”值上。 “浮动”应该不受此影响。 它与“IEEE 754”浮点算法有关。

如果您有兴趣,这是一个链接:https://www.appinf.com/download/FPIssues.pdf

【讨论】:

  • 这只改变了最后几个十进制数字,比如从第 9 位开始等等
猜你喜欢
  • 2013-07-16
  • 2021-09-09
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
相关资源
最近更新 更多