Distância entre dois pontos na Lua

11

Dada a latitude / longitude de dois pontos na Lua (lat1, lon1)e (lat2, lon2), calcule a distância entre os dois pontos em quilômetros, usando qualquer fórmula que dê o mesmo resultado que a fórmula de haversine.

Entrada

  • Quatro valores inteiros lat1, lon1, lat2, lon2em graus (ângulo) ou
  • quatro valores decimais ϕ1, λ1, ϕ2, λ2em radianos.

Resultado

Distância em quilômetros entre os dois pontos (decimal com precisão ou número inteiro arredondado).

Fórmula de 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)

Onde

  • r é o raio da esfera (suponha que o raio da Lua seja 1737 km),
  • ϕ1 latitude do ponto 1 em radianos
  • ϕ2 latitude do ponto 2 em radianos
  • λ1 longitude do ponto 1 em radianos
  • λ2 longitude do ponto 2 em radianos
  • d é a distância circular entre os dois pontos

(fonte: https://en.wikipedia.org/wiki/Haversine_formula )

Outras fórmulas possíveis

  • d = r * acos(sin ϕ1 sin ϕ2 + cos ϕ1 cos ϕ2 cos(λ2 - λ1)) @miles 'formula .
  • d = r * acos(cos(ϕ1 - ϕ2) + cos ϕ1 cos ϕ2 (cos(λ2 - λ1) - 1)) A fórmula de @Neil .

Exemplo onde entradas são graus e saída como número inteiro arredondado

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

Regras

  • A entrada e saída podem ser fornecidas em qualquer formato conveniente .
  • Especifique na resposta se as entradas estão em graus ou radianos .
  • Não há necessidade de lidar com valores inválidos de latitude / longitude
  • Um programa completo ou uma função são aceitáveis. Se uma função, você pode retornar a saída em vez de imprimi-la.
  • Se possível, inclua um link para um ambiente de teste on-line para que outras pessoas possam experimentar seu código!
  • As brechas padrão são proibidas.
  • Isso é portanto todas as regras usuais de golfe se aplicam e o código mais curto (em bytes) vence.
mdahmoune
fonte
7
Usar essa fórmula específica é um requisito não observável. Não é o suficiente para dar o mesmo resultado que essa fórmula poderia dar?
Adám
1
Podemos pegar a entrada em radianos?
Adám
1
@mdahmoune OK, então você listou em graus para facilitar a escrita, mas pode exigimos entrada para estar em radianos? Caso contrário, esse desafio se tornará uma combinação (ruim) de conversão de ângulo e do desafio principal.
Adám 10/04/19
5
Eu diminuí a votação desta pergunta porque parece mais 'Quem é o idioma que mais usa essa fórmula', o que, na minha opinião, não é particularmente interessante.
você precisa saber é o seguinte
2
Uma fórmula mais curta para a maioria das línguas seria d = r * acos( sin ϕ1 sin ϕ2 + cos ϕ1 cos ϕ2 cos(λ2 - λ1) )onder = 1737
milhas

Respostas:

6

Geosfera R + , 54 47 bytes

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

Experimente online!

Recebe entrada como vetores de 2 elementos longitude,latitudeem graus. O TIO não possui o geospherepacote, mas tenha certeza de que ele retorna resultados idênticos à função abaixo.

Agradecimentos a Jonathan Allan por remover 7 bytes.

R , 64 bytes

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

Experimente online!

Toma 4 entradas como nos casos de teste, mas em radianos, em vez de graus.

Giuseppe
fonte
São e3e são /1000realmente necessários?
Jonathan Allan
1
@ JonathanAllan não, eles não são. Isso é muito burro de mim, mas o argumento padrão para o raio é a terra de em metros por isso era lógico no momento, lol
Giuseppe
Observe que a lei esférica dos cossenos não é numericamente estável, principalmente para pequenas distâncias. Isso provavelmente está correto no Mathematica , mas no R e na maioria dos outros idiomas é discutível se o critério "qualquer fórmula que produz o mesmo resultado que a fórmula de Haversine" é cumprido.
deixou de girar contra-relógiowis
@ceasedtoturncounterclockwis Eu o incluí principalmente para mantê-lo na base R. Suponho que o uso de uma biblioteca de ponto flutuante de precisão arbitrária atenuaria o efeito.
21718 Giuseppe
Sim, ou usando uma fórmula estável como, por exemplo, a fórmula haversine ...
deixou de girar no sentido contrário
5

JavaScript (Node.js) , 65 bytes

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

Experimente online!

Baseado na resposta de Kevin Cruijssen, nos comentários de Miles e Neil e mediante solicitação de Arnauld.

Olivier Grégoire
fonte
5

JavaScript (ES7), 90 bytes

Nota: veja a publicação de @ OlivierGrégoire para uma solução muito mais curta

Uma porta direta da resposta do TFeld . Recebe entrada em radianos.

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

Experimente online!

Usando os infames with()85 bytes

Obrigado a @ l4m2 por salvar 6 bytes

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

Experimente online!

Arnauld
fonte
2
Você pode fazerwith(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 bytes usando o algoritmo mais curto do @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))
Kevin Cruijssen 11/04/19
1
74 bytes utilizando @Neil é mais curto algoritmo :(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 bytes, otimizando a resposta de todos:(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 Muito bom. Você provavelmente deve publicá-lo como uma nova resposta.
Arnauld
5

APL (Dyalog Unicode) , 40 35 bytes SBCS

Função tácita anônima. Aceita {ϕ₁, λ₁} como argumento à esquerda e {ϕ₂, λ₂} como argumento à direita.

Usa a fórmula 2 r √ (sin² ( (ϕ₁-ϕ₂)2 ) + cos ϕ₁ cos ϕ₂ sin² ( (λ₁ - λ₂)2 ))

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

Experimente online! (a rfunção converte graus em radianos)


 concatenar elementos correspondentes; {{ϕ₁, ϕ₂}, {λ₁, λ₂}}

 escolha o primeiro; {ϕ₁, ϕ₂}

 então

2×.○ produto de seus cossenos; cos ϕ₁ cos ϕ₂
aceso. ponto "produto", mas com seletor de função trigonométrica (2 é cosseno) em vez de multiplicação e tempos em vez de mais

1, acrescente 1 a isso; {1, cos ϕ₁ cos ϕ₂}

( Multiplique isso pelo resultado da aplicação da seguinte função em {ϕ₁, λ₁} e {ϕ₂, λ₂}:

- suas diferenças; {ϕ₁ - ϕ₂, λ₁ - λ₂}

2÷⍨ divida isso por 2; { (ϕ₁ - ϕ₂)2 , (λ₁ - λ₂)2 }

1○ seno disso; {sin ( (ϕ₁ - ϕ₂)2 ), sin ( (λ₁ - λ₂)2 )}

×⍨ quadrado que (lit. se multiplica); {sin² ( (ϕ₁ - ϕ₂)2 ), sin² ( (λ₁-λ₂)2 )}

Agora temos {sin² ( (ϕ₁ - ϕ₂)2 ), cos ϕ₁ cos ϕ₂ sin² ( (λ₁ - λ₂)2 )}

1⊥ soma isso (lit. avaliar na base-1); sin² ( (ϕ₁-ϕ₂)2 ) + cos ϕ₁ cos ϕ₂ sin² ( (λ₁ - λ₂)2 )

.5*⍨ raiz quadrada disso (lit. elevar isso ao poder da metade)

¯1○ arco disso

3474× multiplicar isso por este


A função para permitir entrada em graus é:

○÷∘180

÷180 argumento dividido por 180

 multiplicar por π

Adão
fonte
4

Python 2 , 95 bytes

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*

Experimente online!

Recebe entrada em radianos.


Versão antiga, antes da liberação da E / S: recebe entrada como graus inteiros e retorna dist arredondado

Python 2 , 135 bytes

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

Experimente online!

TFeld
fonte
você pode soltar inte roundporque decimais são permitidos como saída, você também pode evitar a conversão para radianos porque insumos como radianos também são permitidos
mdahmoune
@mdahmoune, Obrigado, atualizado
TFeld
3

Java 8, 113 92 88 82 bytes

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

As entradas a,b,c,destão ϕ1,λ1,ϕ2,λ2em radianos.

-21 bytes usando a fórmula mais curta de @miles .
-4 bytes graças a @ OlivierGrégore porque eu ainda usei {Math m=null;return ...;}com every Math.as m., em vez de largar o returne usar Mathdiretamente.
-6 bytes usando a fórmula mais curta de @Neil .

Experimente online.

Explicação:

(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
fonte
1
"Otimização prematura é a raiz de todo o mal"! 88 bytes:(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
" Otimização prematura é a raiz de todo mal " Eu acho que você está realmente certo .. Obrigado!
Kevin Cruijssen
1
Eu encontrei uma formulação mais curta:(a,b,c,d)->1737*Math.acos(Math.cos(a-c)+Math.cos(a)*Math.cos(c)*(Math.cos(d-b)-1))
Neil
(Essa formulação não é mais curto no original Wolfram Idioma embora.)
Neil
3

Japt , 55 50 bytes

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

Não necessariamente tão preciso quanto as outras respostas, mas garoto, eu me diverti com essa. Permita-me elaborar.
Enquanto na maioria dos idiomas, esse desafio é bastante direto, Japt tem a propriedade lamentável de que não há embutido nem arcsine nem arccosine. Claro, você pode incorporar Javascript no Japt, mas isso seria o que sempre é o oposto do Feng Shui.

Tudo o que temos a fazer para superar esse pequeno incômodo é a arccosina aproximada e estamos prontos!

A primeira parte é tudo o que é introduzido na arccosina.

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.

O resultado é armazenado implicitamente Upara ser usado posteriormente.

Depois disso, precisamos encontrar uma boa aproximação para a arccosina. Desde que eu sou preguiçoso e não tão bom com matemática, obviamente vamos forçá-lo à força bruta.

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.

Poderíamos ter usado qualquer número grande para a resolução do gerador, o teste manual mostrou que 7!é suficientemente grande e, ao mesmo tempo, razoavelmente rápido.

Recebe a entrada como radianos, gera números não arredondados.

Raspou cinco bytes graças a Oliver .

Experimente online!

Nit
fonte
Você pode remover o (no Mc(X-V. Como o código de char para 1737não é ISO-8859-1, ele muda para UTF-8, que custa mais. Você pode usar o código de char para 173+ 7. ethproductions.github.io/japt/?v=1.4.5&code=I603&input=
Oliver
Você também pode remover o ,seguinte ToMP:-)
Oliver
@ Oliver Muito obrigado, os parênteses eram necessários na minha versão original, mas tornaram-se obsoletos ao jogar um pouco de golfe, embora eu tenha perdido completamente. Além disso, não sabia sobre a coisa da codificação, muito obrigado por isso também.
Nit
1
Se você deseja seguir a rota do JavaScript, lembre-se de que pode executar tudo através do shoco.
Oliver
2

Geléia ,  23 22  18 bytes

-4 bytes graças a milhas (use {e }ao usar sua fórmula .

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

Função diádica que aceita [ϕ1, ϕ2,]à esquerda e [λ1, λ2]à direita em radianos que retorna o resultado (como ponto flutuante).

Experimente online!


Meu ... (também salvou um byte aqui usando a {)

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

Experimente online

Jonathan Allan
fonte
Ah, interessante, atualizei a página novamente e ela mostrou sua edição. Basta clicar em nova resposta para mostrar que a alteração não é atualizada para mostrar suas edições. a alternativa de 18 bytes foi;I}ÆẠP+ÆSP${ÆA×⁽£ġ
miles
Nunca entendi como usar {e }eles nunca fazem o que eu esperava. Isso não significa que eu posso fazer o contrário em 17 ?!
Jonathan Allan
Talvez. {e }apenas crie uma díade a partir de uma mônada. Uma visão semelhante pode ser P{ -> ḷP¥. Pode ser bom adicionar uma composição (de J) rapidamente para fazer algo como o x (P+$) y -> (P x) + (P y)que pode salvar um ou dois bytes em situações semelhantes.
miles
2

MATLAB com caixa de ferramentas de mapeamento, 26 bytes

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

Função anônima que aceita as quatro entradas como uma matriz de células, na mesma ordem descrita no desafio.

Observe que isso fornece resultados exatos (supondo que o raio da Lua seja 1737 km), porque 1737/180é igual 9.65.

Exemplo de execução no Matlab R2017b:

insira a descrição da imagem aqui

Luis Mendo
fonte
1

Python 3, 79 bytes

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

O TIO não tem geopy.py

RootTwo
fonte
2
@Nit, meu entendimento é que é justo usar uma biblioteca disponível ao público que anteceda a questão. Eu acho que é como usar as ferramentas de mapeamento do MATLAB ou outras línguas usando uma biblioteca de matemática.
precisa saber é o seguinte
1

APL (Dyalog Unicode) , SBCS de 29 bytes

Programa completo. Solicita stdin para {ϕ₁, ϕ₂} e, em seguida, para {λ₁, λ₂}. Imprime em stdout.

Usa a fórmula r acos (sin ϕ₁ sin ϕ₂ + cos (λ₂ - λ₁) cos ϕ₁ cos ϕ₂)

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

Experimente online! (a rfunção converte graus em radianos)


 prompt para {ϕ₁, ϕ₂}

1 2∘.○ Aplicação de função trigonométrica cartesiana; {{sin ϕ₁, sin ϕ₂}, {cos ϕ₁, cos ϕ₂}}

×/ produtos em linha; {sin ϕ₁ sin ϕ₂, cos ϕ₁ cos ϕ₂}

()×@2 No segundo elemento, multiplique o seguinte por isso:

 prompt para {λ₁, λ₂}

-/ diferença entre aqueles; λ₁ - λ₂

2○ cosseno disso; cos (λ₁ - λ₂)

Agora temos {sin ϕ₁ sin ϕ₂, cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂}

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

¯2○ cosseno disso; cos (sin ϕ₁ sin ϕ₂ + cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂)

1737× multiplique r por isso; 1737 cos (sin ϕ₁ sin ϕ₂ + cos (λ₁ - λ₂) cos ϕ₁ cos ϕ₂)


A função para permitir entrada em graus é:

○÷∘180

÷180 argumento dividido por 180

 multiplicar por π

Adão
fonte
1

C (gcc) , 100 88 65 64 bytes

88 → 65 usando a fórmula de @miles
65 → 64 usando a fórmula de @ Neil

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

Experimente online!

jxh
fonte
Eu acredito que você precisa adicionar dois bytes para o -lmsinalizador do compilador.
OOBalance
@OOBalance: nem sempre é necessária a presença da bandeira. Depende de como o compilador foi instalado no sistema.
Jxh # 11/18
Bem. Acho que isso significa que posso subtrair dois bytes nesta resposta minha: codegolf.stackexchange.com/a/161452/79343 Obrigado.
OOBalance
@OOBalance: Votou na resposta. Eu também enviei minha própria solução.
Jxh #
Agradável. Votou no seu também.
OOBalance
1

Excel, 53 bytes

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

Usando a fórmula de @ Neil. Entrada em radianos.

Wernisch
fonte
1

Lagosta , 66 bytes

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

Usa a fórmula de milhas, mas a entrada é em graus. Isso adiciona uma etapa extra da conversão em radianos antes da multiplicação por raio.

Panda0nEarth
fonte
1

PHP , 88 bytes

Resposta de Port of Oliver

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

Experimente online!

Luis felipe De jesus Munoz
fonte
1

SmileBASIC, 60 bytes

INPUT X,Y,S,T?1737*ACOS(COS(X-S)+COS(X)*COS(S)*(COS(T-Y)-1))
12Me21
fonte