Odległość między dwoma punktami na Księżycu

11

Biorąc pod uwagę szerokość / długość geograficzną dwóch punktów na Księżycu (lat1, lon1)i (lat2, lon2)oblicz odległość między dwoma punktami w kilometrach, używając dowolnej formuły, która daje taki sam wynik jak formuła haverine.

Wejście

  • Cztery wartości całkowite lat1, lon1, lat2, lon2w stopniach (kąt) lub
  • cztery wartości dziesiętne ϕ1, λ1, ϕ2, λ2w radianach.

Wynik

Odległość w kilometrach między dwoma punktami (dziesiętna z dowolną precyzją lub zaokrąglona liczba całkowita).

Formuła Haversine

d = 2 r \ arcsin \ left (\ sqrt {\ sin ^ 2 \ left (\ frac {\ phi_2 - \ phi_1} {2} \ right) + \ cos (\ phi_1) \ cos (\ phi_2) \ sin ^ 2 \ left (\ frac {\ lambda_2 - \ lambda_1} {2} \ right)} \ right)

gdzie

  • r jest promieniem kuli (załóżmy, że promień Księżyca wynosi 1737 km),
  • ϕ1 szerokość geograficzna punktu 1 w radianach
  • ϕ2 szerokość geograficzna punktu 2 w radianach
  • λ1 długość punktu 1 w radianach
  • λ2 długość punktu 2 w radianach
  • d jest kołową odległością między dwoma punktami

(źródło: https://en.wikipedia.org/wiki/Haversine_formula )

Inne możliwe formuły

  • d = r * acos(sin ϕ1 sin ϕ2 + cos ϕ1 cos ϕ2 cos(λ2 - λ1)) @miles wzór " .
  • d = r * acos(cos(ϕ1 - ϕ2) + cos ϕ1 cos ϕ2 (cos(λ2 - λ1) - 1)) @Neil wzór jest .

Przykład, w którym dane wejściowe to stopnie, a dane wyjściowe jako zaokrąglona liczba całkowita

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

Zasady

  • Dane wejściowe i wyjściowe można podawać w dowolnym dogodnym formacie .
  • W odpowiedzi określ, czy dane wejściowe są w stopniach, czy radianach .
  • Nie ma potrzeby obsługi niepoprawnych wartości szerokości i długości geograficznej
  • Dopuszczalny jest pełny program lub funkcja. Jeśli funkcja, możesz zwrócić dane wyjściowe zamiast je drukować.
  • Jeśli to możliwe, dołącz link do internetowego środowiska testowego, aby inni mogli wypróbować Twój kod!
  • Standardowe luki są zabronione.
  • To jest więc obowiązują wszystkie zwykłe zasady gry w golfa, a wygrywa najkrótszy kod (w bajtach).
mdahmoune
źródło
7
Stosowanie tej konkretnej formuły jest nie do zaobserwowania. Czy nie wystarczy dać taki sam wynik, jaki dałaby ta formuła ?
Adám
1
Czy możemy wprowadzić dane w radianach?
Adám
1
@mdahmoune OK, więc wymienione w stopniach na łatwość pisania, ale może to wymagać wkładu być w radianach? W przeciwnym razie wyzwanie to staje się kombinacją (co jest złe) konwersji kąta i głównego wyzwania.
Adám
5
Głosowałem za tym pytaniem, ponieważ wydaje się, że bardziej brzmi: „Kto potrafi grać w tę formułę najbardziej”, co moim zdaniem nie jest szczególnie interesujące.
caird coinheringaahing
2
Krótsza formuła dla większości języków byłaby d = r * acos( sin ϕ1 sin ϕ2 + cos ϕ1 cos ϕ2 cos(λ2 - λ1) )tamr = 1737
mile

Odpowiedzi:

6

R + geosfera , 54 47 bajtów

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

Wypróbuj online!

Pobiera dane wejściowe jako 2-elementowe wektory longitude,latitudew stopniach. TIO nie ma geospherepakietu, ale zapewniamy, że zwraca identyczne wyniki do funkcji poniżej.

Podziękowania dla Jonathana Allana za zgolenie 7 bajtów.

R , 64 bajty

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

Wypróbuj online!

Przyjmuje 4 dane wejściowe jak w przypadkach testowych, ale raczej w radianach niż stopniach.

Giuseppe
źródło
e3i /1000to naprawdę konieczne?
Jonathan Allan,
1
@JonathanAllan nie, nie są. To dość głupi o mnie, ale domyślnym argumentem dla promienia jest ziemia w metrach więc logiczne było w momencie, lol
Giuseppe
Należy zauważyć, że prawo sferyczne cosinusów nie jest stabilne numerycznie, szczególnie na małych odległościach. Prawdopodobnie jest to w porządku w Mathematica , ale w R i większości innych języków można dyskutować, czy spełnione jest kryterium „dowolnej formuły, która daje taki sam wynik jak formuła haverine”.
przestał obracać przeciwnie do zegara
@ceasedtoturncounterclockwis W większości zawarłem go ze względu na posiadanie go w bazie R. Przypuszczam, że użycie biblioteki zmiennoprzecinkowej o dowolnej precyzji złagodziłoby efekt.
Giuseppe,
Tak, lub stosując stabilną formułę, taką jak, powiedzmy, formuła haverine ...
przestała się obracać przeciwnie do zegara
5

JavaScript (Node.js) , 65 bajtów

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

Wypróbuj online!

Na podstawie odpowiedzi Kevina Cruijssena, komentarzy Milesa i Neila oraz na prośbę Arnaulda.

Olivier Grégoire
źródło
5

JavaScript (ES7), 90 bajtów

Uwaga: patrz post na @ OlivierGrégoire, aby uzyskać znacznie krótsze rozwiązanie

Bezpośredni port odpowiedzi TFeld . Pobiera dane w radianach.

(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)

Wypróbuj online!

Korzystanie z niesławnego with(), 85 bajtów

Dzięki @ l4m2 za oszczędność 6 bajtów

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

Wypróbuj online!

Arnauld
źródło
2
Możesz zrobićwith(Math)f=(a,b,c,d)=>3474*asin((sin((c-a)/2)**2+cos(c)*cos(a)*sin((d-b)/2)**2)**.5)
l4m2
77 bajtów wykorzystujące @miles krótszy algorytm ' :(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))
Kevin Cruijssen
1
74 bajtów za pomocą @Neil „S krótszy algorytm :(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 bajtów optymalizujących odpowiedź wszystkich:(a,b,c,d,C=Math.cos)=>1737*Math.acos(C(a-c)+C(a)*C(c)*(C(d-b)-1))
Olivier Grégoire,
@ OlivierGrégoire Bardzo miło. Prawdopodobnie powinieneś opublikować to jako nową odpowiedź.
Arnauld,
5

APL (Dyalog Unicode) , 40 35 bajtów SBCS

Anonimowa funkcja ukryta. Bierze {ϕ₁, λ₁} jako lewy argument i {ϕ₂, λ₂} jako prawy argument.

Używa wzoru 2 r √ (sin² ( (ϕ₁-ϕ₂)2 ) + cos ϕ₁ cos ϕ₂ sin² ( (λ₁ - λ₂)2 ))

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

Wypróbuj online! ( rfunkcja przekształca stopnie w radiany)


 łączyć odpowiednie elementy; {{ϕ₁, ϕ₂}, {λ₁, λ₂}}

 wybierz pierwszy; {ϕ₁, ϕ₂}

 następnie

2×.○ produkt ich cosinusów; cos ϕ₁ cos ϕ₂
świeci kropka „iloczyn”, ale z selektorem funkcji trig (2 to cosinus) zamiast mnożenia i czasów zamiast plus

1, dodaj 1 do tego; {1, cos ϕ₁ cos ϕ₂}

( Pomnóż to przez wynik zastosowania następującej funkcji do {ϕ₁, λ₁} i {ϕ₂, λ₂}:

- ich różnice; {ϕ₁ - ϕ₂, λ₁ - λ₂}

2÷⍨ podziel to przez 2; { (ϕ₁ - ϕ₂)2 , (λ₁ - λ₂)2 }

1○ sinus tego; {sin ( (ϕ₁ - ϕ₂)2 ), sin ( (λ₁ - λ₂)2 )}

×⍨ kwadrat, który (świeci samo-mnożenie); {sin² ( (ϕ₁ - ϕ₂)2 ), sin² ( (λ₁-λ₂)2 )}

Teraz mamy {sin² ( (ϕ₁ - ϕ₂)2 ), cos ϕ₁ cos ϕ₂ sin² ( (λ₁ - λ₂)2 )}

1⊥ suma, która (lit. ocena w podstawie 1); sin² ( (ϕ₁-ϕ₂)2 ) + cos ϕ₁ cos ϕ₂ sin² ( (λ₁ - λ₂)2 )

.5*⍨ pierwiastek kwadratowy z tego (lit. podnieść to do potęgi połowy)

¯1○ Arcsine tego

3474× pomnóż to przez to


Funkcja pozwalająca na wprowadzanie danych w stopniach to:

○÷∘180

÷180 argument podzielony przez 180

 pomnóż przez π

Adám
źródło
4

Python 2 , 95 bajtów

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*

Wypróbuj online!

Pobiera dane w radianach.


Stara wersja, przed zwolnieniem wejścia / wyjścia: Pobiera dane wejściowe jako liczby całkowite i zwraca zaokrągloną liczbę dist

Python 2 , 135 bajtów

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

Wypróbuj online!

TFeld
źródło
możesz upuścić, inta roundponieważ dziesiętne są dozwolone jako dane wyjściowe, możesz także uniknąć konwersji na radiany, ponieważ dozwolone są również dane wejściowe jako radiany
mdahmoune 10.04.2018
@mdahmoune, Dzięki, zaktualizowano
TFeld
3

Java 8, 113 92 88 82 bajtów

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

Dane wejściowe a,b,c,dϕ1,λ1,ϕ2,λ2w radianach.

-21 bajtów przy użyciu krótszej formuły @miles .
-4 bajty dzięki @ OlivierGrégore, ponieważ wciąż używałem {Math m=null;return ...;}z każdym Math.as m., zamiast upuszczać returni używać Mathbezpośrednio.
-6 bajtów przy użyciu krótszej formuły @Neil .

Wypróbuj online.

Wyjaśnienie:

(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
Kevin Cruijssen
źródło
1
„Przedwczesna optymalizacja jest źródłem wszelkiego zła”! 88 bajtów:(a,b,c,d)->1737*Math.acos(Math.sin(a)*Math.sin(c)+Math.cos(a)*Math.cos(c)*Math.cos(d-b))
Olivier Grégoire
Przedwczesna optymalizacja jest źródłem wszelkiego zła ” Chyba masz rację… Dzięki!
Kevin Cruijssen
1
Znalazłem krótsze sformułowanie:(a,b,c,d)->1737*Math.acos(Math.cos(a-c)+Math.cos(a)*Math.cos(c)*(Math.cos(d-b)-1))
Neil
(To sformułowanie nie jest jednak krótsze w oryginalnym języku Wolfram.)
Neil
3

Japt , 55 50 bajtów

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

Niekoniecznie tak precyzyjne jak inne odpowiedzi, ale chłopcze dobrze się z tym bawiłem. Pozwól mi rozwinąć.
Podczas gdy w większości języków to wyzwanie jest dość proste, Japt ma niefortunną właściwość, że nie ma wbudowanej ani dla arcsine, ani arccosine. Jasne, możesz osadzić Javascript w Japt, ale byłoby to przeciwieństwo Feng Shui.

Jedyne, co musimy zrobić, aby przezwyciężyć tę niewielką uciążliwość, to przybliżona arkozyna i jesteśmy gotowi!

Pierwsza część to wszystko, co dostaje się do arccosine.

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.

Wynik jest domyślnie przechowywany w Ucelu późniejszego wykorzystania.

Następnie musimy znaleźć dobre przybliżenie dla arccosine. Ponieważ jestem leniwy i nie jestem zbyt dobry w matematyce, najwyraźniej po prostu go wykorzystamy.

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.

Mogliśmy użyć dowolnej dużej liczby do rozdzielczości generatora, testy ręczne wykazały, że 7!jest wystarczająco duży, a jednocześnie dość szybki.

Pobiera dane wejściowe jako radiany, generuje liczby nie zaokrąglone.

Ogolił pięć bajtów dzięki Oliverowi .

Wypróbuj online!

Gnida
źródło
Możesz usunąć (w Mc(X-V. Ponieważ kod char 1737nie dla ISO-8859-1, przełącza się na UTF-8, co kosztuje więcej. Zamiast tego możesz użyć kodu char dla 173+ 7. ethproductions.github.io/japt/?v=1.4.5&code=I603&input=
Oliver
Możesz także usunąć ,po ToMP:-)
Oliver,
@Oliver Bardzo dziękuję, nawias był konieczny w mojej oryginalnej wersji, ale stał się przestarzały, kiedy grałem w golfa, ale całkowicie go przeoczyłem. Również nie wiedziałem o kodowaniu, wielkie dzięki za to.
Nit
1
Jeśli chcesz iść drogą JavaScript, pamiętaj, że możesz uruchomić wszystko przez shoco.
Oliver,
2

Galaretka ,  23 22  18 bajtów

-4 bajty dzięki milom (użycie {i }używanie ich formuły .

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

Funkcja dynamiczna akceptująca [ϕ1, ϕ2,]po lewej i [λ1, λ2]po prawej stronie w radianach, która zwraca wynik (jako zmiennoprzecinkowy).

Wypróbuj online!


Mój ... (tutaj również zapisałem bajt za pomocą a {)

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

Wypróbuj online

Jonathan Allan
źródło
Och, ciekawe, odświeżyłem stronę ponownie i pokazała ona twoją edycję, wystarczy kliknąć nową odpowiedź, aby pokazać, że zmiana nie aktualizuje się, aby pokazać twoje zmiany. 18 bajtową alternatywą było;I}ÆẠP+ÆSP${ÆA×⁽£ġ
mile
Nigdy nie rozumiałem, jak korzystać {i }nigdy nie robią tego, czego bym się spodziewał. Czy to nie znaczy, że mogę zrobić inaczej w 17 roku ?!
Jonathan Allan,
Może. {i }po prostu stwórz diadę z monady. Podobny pogląd może być P{ -> ḷP¥. Może warto dodać szybkie komponowanie (od J), aby zrobić coś takiego, x (P+$) y -> (P x) + (P y)co może zaoszczędzić bajt lub dwa w podobnych sytuacjach.
mile
2

MATLAB z Przybornikiem mapowania, 26 bajtów

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

Anonimowa funkcja, która przyjmuje cztery dane wejściowe jako macierz komórki, w takiej samej kolejności, jak opisano w wyzwaniu.

Zauważ, że daje to dokładne wyniki (zakładając, że promień Księżyca wynosi 1737 km), ponieważ 1737/180jest równe 9.65.

Przykład uruchomienia w Matlab R2017b:

wprowadź opis zdjęcia tutaj

Luis Mendo
źródło
1

Python 3, 79 bajtów

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

TIO nie ma geopy.py

RootTwo
źródło
2
@ Ale rozumiem, że uczciwą grą jest korzystanie z publicznie dostępnej biblioteki, która poprzedza pytanie. Myślę, że to tak, jakby używać narzędzi mapujących MATLAB lub innych języków korzystających z biblioteki matematycznej.
RootTwo
1

APL (Dyalog Unicode) , 29 bajtów SBCS

Kompletny program Monituje stdin dla {ϕ₁, ϕ₂}, a następnie dla {λ₁, λ₂}. Drukuje na standardowe wyjście.

Używa wzoru r acos (sin ϕ₁ sin ϕ₂ + cos (λ₂ - λ₁) cos ϕ₁ cos ϕ₂)

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

Wypróbuj online! ( rfunkcja przekształca stopnie w radiany)


 monit o {ϕ₁, ϕ₂}

1 2∘.○ Kartezjańska aplikacja z funkcją trig; {{sin ϕ₁, sin ϕ₂}, {cos ϕ₁, cos ϕ₂}}

×/ produkty rzędowe; {sin ϕ₁ sin ϕ₂, cos ϕ₁ cos ϕ₂}

()×@2 W drugim elemencie pomnóż przez to:

 monit o {λ₁, λ₂}

-/ różnica między nimi; λ₁ - λ₂

2○ cosinus tego; cos (λ₁ - λ₂)

Teraz mamy {sin ϕ₁ sin ϕ₂, cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂}

+/ suma; sin ϕ₁ sin ϕ₂ + cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂

¯2○ cosinus tego; cos (sin ϕ₁ sin ϕ₂ + cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂)

1737× pomnóż przez to; 1737 cos (sin ϕ₁ sin ϕ₂ + cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂)


Funkcja pozwalająca na wprowadzanie danych w stopniach to:

○÷∘180

÷180 argument podzielony przez 180

 pomnóż przez π

Adám
źródło
1

C (gcc) , 100 88 65 64 bajtów

88 → 65 za pomocą formuły @milesa
65 → 64 za pomocą formuły @ Neila

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

Wypróbuj online!

jxh
źródło
Uważam, że musisz dodać dwa bajty dla -lmflagi kompilatora.
OOBalance
@OOBalance: Obecność flagi nie zawsze jest wymagana. Zależy to od sposobu zainstalowania kompilatora w systemie.
jxh
W porządku. Zgaduję, że oznacza to, że mogę odjąć dwa bajty w tej mojej odpowiedzi: codegolf.stackexchange.com/a/161452/79343 Dzięki.
OOBalance
@OOBalance: Poparłem odpowiedź. Przedstawiłem także własne rozwiązanie.
jxh
Ładny. Poprosiłem również o twoje.
OOBalance
1

Excel, 53 bajty

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

Korzystanie ze wzoru @ Neila. Wejście w radianach.

Wernisch
źródło
1

Homar , 66 bajtów

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

Używa wzoru mil, ale dane wejściowe są w stopniach. Dodaje to dodatkowy krok konwersji na radiany przed pomnożeniem przez promień.

Panda0nEarth
źródło
1

PHP , 88 bajtów

Port Oliver odpowiedź

function f($a,$b,$c,$d,$e=cos){return 1737*acos($e($a-$c)+$e($a)*$e($c)*($e($d-$b)-1));}

Wypróbuj online!

Luis Felipe De Jesus Munoz
źródło
1

SmileBASIC, 60 bajtów

INPUT X,Y,S,T?1737*ACOS(COS(X-S)+COS(X)*COS(S)*(COS(T-Y)-1))
12Me21
źródło