Чому закон косинусів є більш кращим, ніж гаверсин при обчисленні відстані між двома точками широти-довготи?


41

Насправді, коли Сіннотт опублікував формулу Гаверсина, точність обчислення була обмежена. На сьогоднішній день 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
Як закон косинусів "кращий"? На це ми можемо відповісти двома способами: для комп’ютера та програміста. Для комп'ютера формула Гаверсина використовує менше функцій триггеру, але потребує двох квадратних коренів. Щодо обчислювальної ефективності, то це підкидання. Для програміста формула гаверсину трохи довша. Однак формула закону косинусів вимагає здійснення ACos, що розглядається дещо рідше, ніж реалізація ATan. Крім того, щоб написати куленепробивний код, ви повинні перевірити, що ACos не вийде з ладу. Тільки з цієї причини нам слід віддавати перевагу гаверину.
whuber

2
Я щойно реалізував гаверсин і косинус в Python. На цьому комп’ютері хаверсин займає 3,3 мкс, а косинус займає 2,2 мкс, що досить важливо, якщо вам потрібно зробити багато з них
гніблер

1
Дякую всім за хороші спостереження та інформацію. Я оновив текст, цитований у питанні, щоб бути, сподіваюся, досить об'єктивнішим та кориснішим.
ChrisV

@ChrisV, дякую за оновлення! Я перемістив це до коментаря, оскільки це не є безпосередньо відповіддю на питання, дякую за ваш чудовий сайт.
scw

Відповіді:


48

Проблему вказує слово "добре кондиціонований". Це питання комп’ютерної арифметики, а не математики.

Ось основні факти, які слід врахувати:

  1. Один радіан на землі охоплює майже 10 ^ 7 метрів.

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

  3. Плаваюча точка з подвійною точністю містить близько 15 десяткових цифр точності.

З точок (2) і (3) випливає, що коли х становить близько одного метра, або 10 ^ -7 радіанів (точка 1), втрачається майже вся точність: 1 - (10 ^ -7) ^ 2 = 1 - 10 ^ - 14 - це обчислення, в якому перші 14 з 15 значущих цифр усі скасовують, залишаючи лише одну цифру для відображення результату. Перевернути це навколо (що і робить зворотний косинус, "acos") означає, що обчислення acos для кутів, що відповідають відстаням довжини метра, не може бути виконано з якоюсь значущою точністю. (У певних поганих випадках втрата точності дає значення, коли acos навіть не визначено, тому код вийде з ладу і не дасть відповіді, дурницької відповіді або зламає машину.) Подібні міркування пропонують вам уникати використання зворотного косинуса якщо задіяно відстань менше кількох сотень метрів, залежно від того, яку точність ви готові втратити.

Роль, яку відіграють аксоси у формулі наївного закону косинусів, - це перетворення кута на відстань. Цю роль відіграє atan2 у формулі гаверсину. Тангенс малого кута x приблизно дорівнює самому x . Отже, обернена дотична кількість числа, будучи приблизно таким числом, обчислюється по суті, не втрачаючи точності. Ось чому формула Гаверсина, хоча математично еквівалентна закону формули косинусів, набагато перевершує невеликі відстані (порядку 1 метр або менше).

Ось порівняння двох формул із використанням 100 випадкових пар точок на земній кулі (з використанням обчислень подвійної точності Mathematica).

alt текст

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

alt текст

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


Чи є якийсь дешевий тест - наприклад, delta latitude > .1 || delta longitude > .1для динамічного вибору косинусу (для великих) або гаверсину (для невеликих відстаней)? Для того, щоб отримати найкращі показники та гарну точність.
Аноні-Мус

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

Чи atan2пропонують чисельні переваги більше asin? Я побачив орієнтири, де atan2було в 2-3 рази повільніше asin, і нам теж потрібна секунда sqrt.
Еріх Шуберт

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

Це було б на дуже великих відстанях? Поєднувати це з пропозицією @ Аноні-Мусса вище здається тоді цікаво.
Еріх Шуберт

6

Історична виноска:

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

1 - cos(x)

коли х малий. З точки зору гаверсину у нас є

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

і 2 * sin (x / 2) ^ 2 можна обчислити точно, навіть коли х малий.

За старих часів формула гаверсину мала додаткову перевагу - уникати додавання (що тягнуло за собою пошук антилога, додавання та пошук журналу). Тригонометрична формула, яка тягнула за собою лише множення, як вважалося, має "логарифмічну форму".

На сьогодні використання формул Гаверсина є трохи анахронічним. Можливо, кут x виражається в термінах sin(x)і cos(x)(а x може бути невідомо відомим). У цьому випадку обчислення 1 - cos(x)за формулою Гаверсина тягне за собою арктангент (отримати кут 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

Формула Гаверсина займає кілька рядків:

  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.