Відстань між двома точками на Місяці


11

Враховуючи широту / довготу двох точок на Місяці (lat1, lon1)і (lat2, lon2)обчисліть відстань між двома точками в кілометрах, використовуючи будь-яку формулу, яка дає такий же результат, як і формула Гаверсина.

Вхідні дані

  • Чотири цілих значення lat1, lon1, lat2, lon2в градусі (куті) або
  • чотири десяткових значення ϕ1, λ1, ϕ2, λ2в радіанах.

Вихідні дані

Відстань у кілометрах між двома точками (десятковий з будь-якою точністю або округлим цілим числом).

Формула Гаверсина

d = 2 r \ arcsin \ зліва (\ sqrt {\ sin ^ 2 \ зліва (\ frac {\ phi_2 - \ phi_1} {2} \ праворуч) + \ cos (\ phi_1) \ cos (\ phi_2) \ sin ^ 2 \ ліворуч (\ frac {\ lambda_2 - \ lambda_1} {2} \ праворуч)} \ праворуч)

де

  • r - радіус сфери (припустимо, радіус Місяця - 1737 км),
  • ϕ1 широта точки 1 в радіанах
  • ϕ2 широта точки 2 в радіанах
  • λ1 довгота точки 1 в радіанах
  • λ2 довгота точки 2 в радіанах
  • d - кругова відстань між двома точками

(джерело: https://en.wikipedia.org/wiki/Haversine_formula )

Інші можливі формули

Приклад, коли вхідні дані є градусами, а виведення у вигляді округлого цілого числа

42, 9, 50, 2  --> 284
50, 2, 42, 9  --> 284
4, -2, -2, 1  --> 203
77, 8, 77, 8  --> 0
10, 2, 88, 9  --> 2365

Правила

  • Введення та вихід можуть бути задані у будь-якому зручному форматі .
  • Укажіть у відповіді, чи вхідні дані в градусах чи радіанах .
  • Не потрібно обробляти недійсні значення широти / довготи
  • Прийнятна або повна програма, або функція. Якщо функція, ви можете повернути вихід, а не надрукувати його.
  • Якщо можливо, додайте посилання на онлайн-тестувальне середовище, щоб інші люди могли спробувати ваш код!
  • Стандартні лазівки заборонені.
  • Це тому застосовуються всі звичайні правила гольфу, і найкоротший код (у байтах) виграє.

7
Використання цієї конкретної формули є непомітною вимогою. Хіба мало , щоб дати той же результат, що формула буде давати?
Адам

1
Чи можемо ми взяти вхід в радіанах?
Адам

1
@mdahmoune Гаразд, тож ви вказали в градусах для зручності написання, але може нам зажадати введення в радіанах? Інакше це завдання стає комбінованим (що погано) перетворенням кута і є головним завданням.
Адам

5
Я спростував це питання, тому що, здається, більше йдеться про те, "хто мовою може найбільше займатися цією формулою", що, на мою думку, не особливо цікаво.
caird coinheringaahing

2
Скороченою формулою для більшості мов буде d = r * acos( sin ϕ1 sin ϕ2 + cos ϕ1 cos ϕ2 cos(λ2 - λ1) )деr = 1737
милі

Відповіді:



6

R + геосфера , 54 47 байт

function(p,q)geosphere::distHaversine(p,q,1737)

Спробуйте в Інтернеті!

Приймає введення як двоелементні вектори longitude,latitudeв градусах. У TIO немає geosphereпакета, але будьте впевнені, що він повертає однакові результати до наведеної нижче функції.

Дякую Джонатану Аллану за гоління 7 байт.

R , 64 байти

function(p,l,q,k)1737*acos(sin(p)*sin(q)+cos(p)*cos(q)*cos(k-l))

Спробуйте в Інтернеті!

Бере 4 входи, як у тестових випадках, але в радіанах, а не в градусах.


Це e3і /1000справді потрібно?
Джонатан Аллан

1
@JonathanAllan ні вони не є. Це досить глупо з мене, але аргументом за замовчуванням для радіусу є земля в метрах, тому це було логічно в той час, хаха
Джузеппе

Зауважимо, що сферичний закон косинусів не є чисельно стійким, зокрема на малих відстанях. Це, мабуть, нормально в Mathematica , але в R та більшості інших мов дискусійно, чи виконується критерій "будь-яка формула, яка дає такий же результат, як і формула Гаверсина".
перестала повертати проти годинника,

@ceasedtoturncounter clockwis я здебільшого включив його задля того, щоб мати його в базі R. Я вважаю, що використання бібліотеки довільної точності з плаваючою точкою зменшить ефект.
Джузеппе

Так, або використовуючи стійку формулу, як, скажімо, формула Гаверсина ...
перестала повертати проти годинника,


5

JavaScript (ES7), 90 байт

Примітка. Дивіться публікацію @ OlivierGrégoire для набагато коротшого рішення

Прямий порт відповіді TFeld . Приймає введення в радіанах.

(a,b,c,d,M=Math)=>3474*M.asin((M.sin((c-a)/2)**2+M.cos(c)*M.cos(a)*M.sin((d-b)/2)**2)**.5)

Спробуйте в Інтернеті!

Використовуючи сумнозвісний with()85 байт

Завдяки @ l4m2 за економію 6 байт

with(Math)f=(a,b,c,d)=>3474*asin((sin((c-a)/2)**2+cos(c)*cos(a)*sin((d-b)/2)**2)**.5)

Спробуйте в Інтернеті!


2
Можна зробитиwith(Math)f=(a,b,c,d)=>3474*asin((sin((c-a)/2)**2+cos(c)*cos(a)*sin((d-b)/2)**2)**.5)
l4м2

77 байт , використовуючи @miles короткий алгоритм " :(a,b,c,d,M=Math)=>1737*M.acos(M.sin(a)*M.sin(c)+M.cos(a)*M.cos(c)*M.cos(d-b))
Кевін Cruijssen

1
74 байт з використанням @Neil «S короткий алгоритм :(a,b,c,d,M=Math)=>1737*M.acos(M.cos(a-c)+M.cos(a)*M.cos(c)*(M.cos(d-b)-1))
Kevin Cruijssen

3
65 байт, що оптимізують відповідь усіх:(a,b,c,d,C=Math.cos)=>1737*Math.acos(C(a-c)+C(a)*C(c)*(C(d-b)-1))
Олів'є Грегоар

@ OlivierGrégoire Дуже приємно. Напевно, ви повинні опублікувати це як нову відповідь.
Арнольд

5

APL (Dyalog Unicode) , 40 35 байт SBCS

Анонімна негласна функція. Приймає {ϕ₁, λ₁} як лівий аргумент і {ϕ₂, λ₂} як правий аргумент.

Використовує формулу 2 r √ (sin² ( (ϕ₁-ϕ₂)2 ) + cos ϕ₁ cos ϕ₂ sin² ( (λ₁ - λ₂)2 ))

3474ׯ1○.5*⍨1⊥(×⍨12÷⍨-)×1,2×.○∘⊃,¨

Спробуйте в Інтернеті! ( rфункція перетворює градуси в радіани)


 з'єднати відповідні елементи; {{ϕ₁, ϕ₂}, {λ₁, λ₂}}

 виберіть перше; {ϕ₁, ϕ₂}

 потім

2×.○ добуток їх косинусів; cos ϕ₁ cos ϕ₂
літ. крапка "продукт", але із селектором триггерної функції (2 - косинус) замість множення та разів замість плюс

1, додайте 1 до цього; {1, cos ϕ₁ cos ϕ₂}

( Помножте це на результат застосування наступної функції до {ϕ₁, λ₁} і {ϕ₂, λ₂}:

- їх відмінності; {ϕ₁ - ϕ₂, λ₁ - λ₂}

2÷⍨ розділити це на 2; { (ϕ₁ - ϕ₂)2 , (λ₁ - λ₂)2 }

1○ синус того; {sin ( (ϕ₁ - ϕ₂)2 ), sin ( (λ₁ - λ₂)2 )}

×⍨ квадрат, що (літ. саморозмножуватися); {sin² ( (ϕ₁ - ϕ₂)2 ), sin² ( (λ₁-λ₂)2 )}

Тепер у нас {sin² ( (ϕ₁ - ϕ₂)2 ), cos ϕ₁ cos ϕ₂ sin² ( (λ₁ - λ₂)2 )}

1⊥ сума, що (літ. оцінка в базі-1); sin² ( (ϕ₁-ϕ₂)2 ) + cos ϕ₁ cos ϕ₂ sin² ( (λ₁ - λ₂)2 )

.5*⍨ квадратний корінь цього (освітлене підняти це до сили половини)

¯1○ дуги того

3474× помножте це на це


Функція дозволу введення в градусах:

○÷∘180

÷180 аргумент розділений на 180

 помножити на π


4

Python 2 , 95 байт

lambda a,b,c,d:3474*asin((sin((c-a)/2)**2+cos(c)*cos(a)*sin((d-b)/2)**2)**.5)
from math import*

Спробуйте в Інтернеті!

Приймає введення в радіанах.


Стара версія, до введення / вимикання: приймає введення як цілі ступені, а повертає округлене dist

Python 2 , 135 байт

lambda a,b,c,d:int(round(3474*asin((sin((r(c)-r(a))/2)**2+cos(r(c))*cos(r(a))*sin((r(d)-r(b))/2)**2)**.5)))
from math import*
r=radians

Спробуйте в Інтернеті!


ви можете кинути, intі roundтому що децималі дозволені як вихід, ви також можете уникнути перетворення на радіани, оскільки вхідні дані як радіани також дозволені
mdahmoune

@mdahmoune, спасибі, оновлено
TFeld

3

Java 8, 113 92 88 82 байт

(a,b,c,d)->1737*Math.acos(Math.cos(a-c)+Math.cos(a)*Math.cos(c)*(Math.cos(d-b)-1))

Входи a,b,c,dзнаходяться ϕ1,λ1,ϕ2,λ2в радіанах.

-21 байт за допомогою коротшої формули @miles .
-4 байт завдяки @ OlivierGrégore , тому що я до сих пір використовується {Math m=null;return ...;}з кожним , Math.як m., замість того , опускаючи returnі використовувати Mathбезпосередньо.
-6 байт за допомогою коротшої формули @Neil .

Спробуйте в Інтернеті.

Пояснення:

(a,b,c,d)->                  // Method with four double parameters and double return-type
  1737*Math.acos(            //  Return 1737 multiplied with the acos of:
   Math.cos(a-c)             //   the cos of `a` minus `c`,
   +Math.cos(a)*Math.cos(c)  //   plus the cos of `a` multiplied with the cos of `c`
   *(Math.cos(d-b)-1))       //   multiplied with the cos of `d` minus `b` minus 1

1
"Передчасна оптимізація - корінь усього зла"! 88 байт:(a,b,c,d)->1737*Math.acos(Math.sin(a)*Math.sin(c)+Math.cos(a)*Math.cos(c)*Math.cos(d-b))
Олів’є Грегуар

" Передчасна оптимізація - корінь усякого зла ", мабуть, ви справді праві. Дякую!
Кевін Круїссен

1
Я знайшов більш коротку формулювання:(a,b,c,d)->1737*Math.acos(Math.cos(a-c)+Math.cos(a)*Math.cos(c)*(Math.cos(d-b)-1))
Ніл

(Ця форма не є коротшою в оригінальній мові Вольфрама.)
Ніл,

3

Japt , 55 50 байт

MsU *MsW +McU *McW *McX-V
ToMP1/7l¹ñ@McX aUÃv *#­7

Не обов'язково досить точний, як інші відповіді, але хлопчик, мені це було весело. Дозвольте мені розробити.
Незважаючи на те, що в більшості мов цей виклик є досить простим, у Джапта є нещаслива властивість, що не існує вбудованого ні для дуги, ні для дуги. Звичайно, ви можете вбудовувати Javascript у Japt, але це було б протилежним фен-шуй.

Все, що нам потрібно зробити, щоб подолати цю незначну неприємність - це приблизний аркокозин, і ми готові йти!

Перша частина - це все, що потрапляє в аркозин.

MsU *MsW +McU *McW *McX-V
MsU                        // Take the sine of the first input and
    *MsW...                // multiply by the cos of the second one etc.

Результат неявно зберігається, Uщоб використовуватись згодом.

Слідом за цим нам потрібно знайти гарне наближення до аркозину. Оскільки я лінивий і не дуже хороший з математикою, ми, очевидно, просто збираємося це зробити грубо.

ToMP1/7l¹ñ@McX aUÃv *#­7
T                       // Take 0
 o                      // and create a range from it
  MP                    // to π
    1/7l¹               // with resolution 1/7!.
         ñ@             // Sort this range so that
           McX          // the cosine of a given value
               aU       // is closest to U, e.g. the whole trig lot
                        // we want to take arccosine of.
                 Ã      // When that's done,
                  v     // get the first element
                    *#­7 // and multiply it by 1737, returning implicitly.

Ми могли використати будь-яку велику кількість для роздільної здатності генератора, ручне тестування показало 7!достатньо велику кількість, при цьому досить швидко.

Приймає введення як радіани, виводить необмежені числа.

Поголив п’ять байтів завдяки Оліверу .

Спробуйте в Інтернеті!


Ви можете видалити (ін Mc(X-V. Оскільки char-код 1737не ISO-8859-1, він переходить на UTF-8, що коштує дорожче. Ви можете замість цього використовувати char-код для 173+ 7. ethproductions.github.io/japt/?v=1.4.5&code=I603&input=
Олівер

Ви також можете видалити ,після ToMP:-)
Олівер

@Oliver Спасибі велике, дужки були потрібні в моїй оригінальній версії, але вони застаріли, коли трохи грали в гольф, я повністю пропустив це. Крім того, не знав про кодування річ, велике спасибі також за це.
Ніт

1
Якщо ви хочете пройти маршрут JavaScript, майте на увазі, що ви можете запустити все через шоко.
Олівер



2

Желе ,  23 22  18 байт

-4 байти завдяки милям (використання {та }при використанні їх формули .

;I}ÆẠP+ÆSP${ÆA×⁽£ġ

Діадична функція, що приймає [ϕ1, ϕ2,]зліва і [λ1, λ2]справа в радіанах, що повертає результат (як плаваюча точка).

Спробуйте в Інтернеті!


Шахта ... (також тут збережено байт за допомогою a {)

,IÆẠCH;ÆẠ{Ḣ+PƊ½ÆṢ×⁽µṣ

Спробуйте в Інтернеті


Що цікаво, я знову оновив сторінку, і вона показала вашу редагування, просто натиснувши нову відповідь, щоб показати, що зміна не оновлюється, щоб показати ваші зміни. альтернативою 18 байт було;I}ÆẠP+ÆSP${ÆA×⁽£ġ
миль

Ніколи не розумів, як користуватися, {і }вони ніколи не роблять того, чого я очікував. Чи це не означає, що я можу зробити інакше в 17 ?!
Джонатан Аллан

Можливо. {і }просто створити діаду з монади. Схожий погляд може бути P{ -> ḷP¥. Можливо, добре додати композицію (від J), щоб зробити щось подібне, x (P+$) y -> (P x) + (P y)що може зберегти байт або два в подібних ситуаціях.
милі

2

MATLAB з картографічним набором інструментів, 26 байт

@(x)distance(x{:})*9.65*pi

Анонімна функція, яка приймає чотири входи як масив комірок у тому ж порядку, як описано в виклику.

Зауважимо, що це дає точні результати (якщо припустити, що радіус Місяця - 1737 км), оскільки 1737/180дорівнює 9.65.

Приклад запуску в Matlab R2017b:

введіть тут опис зображення


1

Пітон 3, 79 байт

from geopy import*
lambda a,b:distance.great_circle(a,b,radius=1737).kilometers

TIO не має geopy.py


2
@Nit, я розумію, що справедливо гра використовувати публічно доступну бібліотеку, яка передує цьому питанню. Я думаю, що це як використання інструментів картографування MATLAB або інших мов за допомогою математичної бібліотеки.
RootTwo

1

APL (Dyalog Unicode) , 29 байт SBCS

Повна програма. Підказує stdin для {ϕ₁, ϕ₂}, а потім для {λ₁, λ₂}. Друкується до stdout.

Використовує формулу r acos (sin ϕ₁ sin ϕ₂ + cos (λ₂ - λ₁) cos ϕ₁ cos ϕ₂)

1737ׯ2○+/(2○-/⎕)×@2×/1 2∘.○⎕

Спробуйте в Інтернеті! ( rфункція перетворює градуси в радіани)


 запит на {ϕ₁, ϕ₂}

1 2∘.○ Декартові триг-функції; {{sin ϕ₁, sin ϕ₂}, {cos ϕ₁, cos ϕ₂}}

×/ рядові вироби; {sin ϕ₁ sin ϕ₂, cos ϕ₁ cos ϕ₂}

()×@2 На другому елементі помножте наступне на це:

 підказка для {λ₁, λ₂}

-/ різниця між тими; λ₁ - λ₂

2○ косинус того; cos (λ₁ - λ₂)

Тепер у нас є {sin ϕ₁ sin ϕ₂, cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂}

+/ сума; sin ϕ₁ sin ϕ₂ + cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂

¯2○ косинус того; cos (sin ϕ₁ sin ϕ₂ + cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂)

1737× помножити r на це; 1737 cos (sin ϕ₁ sin ϕ₂ + cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂)


Функція дозволу введення в градусах:

○÷∘180

÷180 аргумент розділений на 180

 помножити на π


1

C (gcc) , 100 88 65 64 байт

88 → 65, використовуючи формулу @miles
65 → 64, використовуючи формулу @ Ніла

#define d(w,x,y,z)1737*acos(cos(w-y)+cos(w)*cos(y)*(cos(z-x)-1))

Спробуйте в Інтернеті!


Я вважаю, що вам потрібно додати два байти для -lmпрапора компілятора.
OOBalance

@OOBalance: Наявність прапора не завжди потрібно. Це залежить від того, як був встановлений компілятор в системі.
jxh

Добре. Здогадайтесь, це означає, що я можу відняти два байти у цій моїй відповіді: codegolf.stackexchange.com/a/161452/79343 Дякую.
OOBalance

@OOBalance: відповідь запрошена. Я також подав власне рішення.
jxh

Приємно. Оголосив і ваш.
OOBalance

1

Excel, 53 байти

=1737*ACOS(COS(A1-C1)+COS(A1)*COS(C1)*(COS(D1-B1)-1))

Використовуючи формулу @ Ніла. Введення в Радіан.


1

Омари , 66 байт

def h(a,c,b,d):1737*radians arccos a.sin*b.sin+a.cos*b.cos*cos d-c

Використовує формулу миль, але введення в градусах. Це додає додатковий крок перетворення на радіани перед множенням на радіус.




1

SmileBASIC, 60 байт

INPUT X,Y,S,T?1737*ACOS(COS(X-S)+COS(X)*COS(S)*(COS(T-Y)-1))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.