Почему закон косинусов более предпочтителен, чем косинус, при расчете расстояния между двумя точками широты и долготы?


41

Фактически, когда Синнотт опубликовал формулу haversine, точность вычислений была ограничена. В настоящее время JavaScript (и большинство современных компьютеров и языков) используют 64-разрядные числа IEEE 754 с плавающей запятой, что обеспечивает 15 значительных показателей точности. С этой точностью простой сферический закон формулы косинусов ( cos c = cos a cos b + sin a sin b cos C) дает хорошо обусловленные результаты на расстояниях до 1 метра. Ввиду этого, вероятно, в большинстве ситуаций стоит использовать либо более простой закон косинусов, либо более точную эллипсоидальную формулу Винсенти в предпочтении хаверсину! (принимая во внимание примечания ниже об ограничениях в точности сферической модели).
Источник: http://www.movable-type.co.uk/scripts/latlong.html

В чем причина того, что закон косинусов более предпочтителен?

Примечание: цитируемый текст был обновлен его автором, как указано ниже .


10
Как закон косинусов "предпочтителен"? Мы можем ответить на это двумя способами: для компьютера и программиста. Для компьютера формула haversine использует меньше тригонометрических функций, но требует двух квадратных корней. Для вычислительной эффективности, это бросок. Для программиста формула haversine немного длиннее. Однако формула закона косинусов требует наличия реализации ACos, что наблюдается немного реже, чем реализация ATan. Кроме того, чтобы написать пуленепробиваемый код, вы должны убедиться, что ACos не выйдет из строя. Только по этой причине мы должны предпочесть haversine.
whuber

2
Я только что реализовал haversine и cosine в Python. На этом компьютере haversine длится 3,3 мкс, а косинус - 2,2 мкс, что весьма важно, если вам нужно сделать много из них
gnibbler

1
Спасибо всем за хорошие наблюдения и информацию. Я обновил текст, указанный в вопросе, чтобы, я надеюсь, был более объективным и полезным.
ChrisV

@ChrisV, спасибо за обновление! Я переместил это в комментарий, так как он не является прямым ответом на вопрос, спасибо за ваш замечательный сайт.
Scw

Ответы:


49

Проблема обозначена словом «хорошо обусловлено». Это вопрос компьютерной арифметики, а не математики.

Вот основные факты для рассмотрения:

  1. Один радиан на земле охватывает почти 10 ^ 7 метров.

  2. Функция косинуса для аргументов x около 0 приблизительно равна 1 - x ^ 2/2.

  3. Плавающая точка двойной точности имеет около 15 десятичных знаков точности.

Точки (2) и (3) подразумевают, что когда x составляет около одного метра или 10 ^ -7 радиан (точка 1), почти вся точность теряется: 1 - (10 ^ -7) ^ 2 = 1 - 10 ^ - 14 - это расчет, в котором все первые 14 из 15 значащих цифр отменяются, оставляя только одну цифру для представления результата. Отражение вокруг этого (что делает обратный косинус, «acos») означает, что вычисление acos для углов, которые соответствуют расстояниям в метр, не может быть выполнено с какой-либо значимой точностью. (В некоторых плохих случаях потеря точности дает значение, при котором acos даже не определен, поэтому код сломается и не даст ответа, бессмысленного ответа или вылетит из строя.) Аналогичные соображения показывают, что вам следует избегать использования обратного косинуса если задействованы расстояния менее нескольких сотен метров, в зависимости от того, какую точность вы готовы потерять.

Роль acos в наивной формуле закона косинусов заключается в преобразовании угла в расстояние. Эту роль играет atan2 в формуле haversine. Тангенс малого угла x приблизительно равен самому x . Следовательно, обратный тангенс числа, приблизительно равный этому числу, вычисляется по существу без потери точности. Вот почему формула haversine, хотя математически эквивалентна формуле закона косинусов, намного лучше для небольших расстояний (порядка 1 метра или меньше).

Вот сравнение двух формул с использованием 100 случайных пар точек на земном шаре (с использованием вычислений Mathematica с двойной точностью).

альтернативный текст

Вы можете видеть, что для расстояний менее примерно 0,5 метра две формулы расходятся. Выше 0,5 метра они склонны соглашаться. Чтобы показать, насколько они согласны, на следующем графике показаны соотношения закона косинусов: результаты haversine для еще 100 пар случайных точек, их широта и долгота случайным образом различаются на величину до 5 метров.

альтернативный текст

Это показывает, что закон формулы косинусов хорош до 3-4 десятичных знаков после того, как расстояние превышает 5-10 метров. Количество десятичных разрядов точности увеличивается квадратично; таким образом, на 50-100 м (один порядок) вы получаете точность 5-6 dp (два порядка); на 500-1000 м вы получаете 7-8 дп и т. д.


Есть ли какой-нибудь дешевый тест - например, delta latitude > .1 || delta longitude > .1чтобы динамически выбрать либо косинус (для больших), либо haversine (для небольших расстояний)? Для того, чтобы получить лучшую производительность и хорошую точность.
Anony-Mousse

@ Anony-Mousse Обе формулы могут быть отключены на несколько десятых процента для расстояний, равных одной четверти по всему миру, поэтому к тому времени мы не будем суетиться о точности! Поэтому любого теста, который может отличить близкие точки (несколько сотен метров) от почти диаметрально противоположных точек (около 20 миллионов метров) от всего, что между ними должно быть достаточно.
whuber

atan2Предлагает ли числовые преимущества сверх asin? Я видел тесты, где они atan2были в 2-3 раза медленнее asin, и нам sqrtтоже нужна секунда .
Эрих Шуберт

@Erich Я не изучал разницу, но обратите внимание, что asinэто по сути то же самое, что acosи, следовательно, страдает от той же потери точности для определенных значений - в данном случае для аргументов около 1 и -1. В принципе atan2такой проблемы нет.
whuber

Это было бы на очень больших расстояниях? Объединение этого с предложением @ Anony-Mousse выше кажется интересным.
Эрих Шуберт

7

Историческая сноска:

Гаверсин был способом избежать больших ошибок округления в вычислениях, таких как

1 - cos(x)

когда х мало. С точки зрения haversine мы имеем

1 - cos(x) = 2*sin(x/2)^2
           = 2*haversin(x)

и 2 * sin (x / 2) ^ 2 можно точно вычислить, даже если x мало.

В старые времена формула haversine имела дополнительное преимущество в том, что избегала добавления (что влекло за собой поиск по журналу, добавление и поиск по журналу). Считалось, что тригонометрическая формула, которая влечет только умножения, находится в «логарифмической форме».

В настоящее время использование формул haversine является слегка анахроничным. Может быть, что угол x выражен в терминах sin(x)и cos(x)(и x может быть не известен явно). В этом случае вычисление 1 - cos(x)по формуле haversine влечет за собой арктангенс (чтобы получить угол x), деление пополам (чтобы получить x/2), синус (чтобы получить sin(x/2)), квадрат (чтобы получить sin(x/2)^2) и окончательное удвоение. Вы гораздо лучше, используя оценку

1 - cos(x) = sin(x)^2/(1 + cos(x))

что не влечет за собой оценки тригонометрических функций. (Очевидно, используйте правую сторону, только если cos(x) > 0; в противном случае, можно использовать 1 - cos(x)напрямую.)


1

Формула косинуса может быть реализована в одну строку:

  Distance = acos(SIN(lat1)*SIN(lat2)+COS(lat1)*COS(lat2)*COS(lon2-lon1))*6371

Формула haversine занимает несколько строк:

  dLat = (lat2-lat1)
  dLon = (lon2-lon1)
  a = sin(dLat/2) * sin(dLat/2) + cos(lat1) * cos(lat2) * sin(dLon/2) * sin(dLon/2)
  distance = 6371 * 2 * atan2(sqrt(a), sqrt(1-a))

Математически они идентичны, поэтому единственное отличие состоит в практичности.


Хотя оригинальный Haversine не использует atan2формулу, связанную с компьютером , ничто не мешает переписать 4 строки выше в одну формулу.
Арьян

@ Арьян, правда, но это было бы неэффективно , потому что нужно было бы вычислить дважды. Крайне важно, чтобы формула включала в себя как Sqrt (a), так и Sqrt (1-a), потому что, хотя один из них будет численно нестабильным на очень малых или очень больших расстояниях, другой не будет: именно это делает этот подход эффективным.
whuber

Правда, @whuber, но все же я сомневаюсь, что количество строк когда-нибудь заставит меня выбрать одну из других. (И, как вы уже объяснили в своем ответе, есть более важные причины, чтобы отдать предпочтение одному из них.)
Арджан,

3
@ Arjan Я согласен. Первым приоритетом должна быть адекватность кода для задачи программирования. После этого я хотел бы внести ясность: читабельность, удобство обслуживания и грамотная документация. В отсутствие такого контекста подсчет количества строк кода не имеет смысла.
whuber

1
atan2(sqrt(a), sqrt(1-a))так же, какasin(sqrt(a))
user102008
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.