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

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.


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


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 π


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!


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

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!


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


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


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


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 π


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!


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.


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ń.




1

SmileBASIC, 60 bajtów

INPUT X,Y,S,T?1737*ACOS(COS(X-S)+COS(X)*COS(S)*(COS(T-Y)-1))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.