iOS и Android: та же функция, один и тот же вход, другой десятичный вывод - PullRequest
0 голосов
/ 07 января 2019

мы используем одну и ту же функцию в 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 }
}

А вот и ява:

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

Выход:

Android

{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}

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Когда вы конвертируете функцию из одного языка в другой, вы должны попытаться использовать те же имена переменных. В этом случае в Java вы также можете статически импортировать все математические функции , чтобы у вас не было функции, которая фактически заканчивала бы невозможным сравнение.

Это быстрая функция:

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 имеет круглые скобки сразу после греха, тогда как формула 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;
    }
}
0 голосов
/ 07 января 2019

Эта проблема возникает только при значениях Double. «Поплавки» должны быть защищены от этого. Это как-то связано с арифметикой с плавающей точкой IEEE 754.

Если вам интересно, это ссылка: https://www.appinf.com/download/FPIssues.pdf

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...