Расстояние между двумя точками на Луне

11

Учитывая широту / долготу двух точек на Луне (lat1, lon1)и (lat2, lon2)вычислите расстояние между двумя точками в километрах, используя любую формулу, которая дает тот же результат, что и формула haversine.

вход

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

Выход

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

Формула 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)

где

  • 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

правила

  • Вход и выход могут быть предоставлены в любом удобном формате .
  • Укажите в ответе, являются ли входные данные в градусах или радианах .
  • Нет необходимости обрабатывать неверные значения широты / долготы
  • Либо полная программа или функция приемлемы. Если функция, вы можете вернуть вывод, а не распечатать его.
  • Если возможно, укажите ссылку на среду онлайн-тестирования, чтобы другие люди могли опробовать ваш код!
  • Стандартные лазейки запрещены.
  • Это поэтому применяются все обычные правила игры в гольф, и выигрывает самый короткий код (в байтах).
mdahmoune
источник
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)

Попробуйте онлайн!

Вводит как 2-элементные векторы 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 входа, как в тестовых случаях, но в радианах, а не в градусах.

Giuseppe
источник
e3И /1000действительно ли это необходимо?
Джонатан Аллан
1
@JonathanAllan нет, нет. Это довольно глупо с моей стороны, но аргумент по умолчанию для радиуса - это земля в метрах, поэтому в то время это было логично, лол
Джузеппе
Обратите внимание, что сферический закон косинусов не является численно устойчивым, особенно для малых расстояний. Это, наверное , хорошо в Mathematica , но в R и в большинстве других языков это спорно ли критерий выполнила «любая формула , которая дает тот же результат, что и формуле гаверсинуса».
перестал поворачивать против часовой стрелки
@ceasedtoturncounterclockwis Я в основном включил его ради того, чтобы иметь его в базе R. Я полагаю, использование библиотеки с плавающей запятой произвольной точности уменьшит эффект.
Джузеппе
Да, или используя стабильную формулу, как, скажем, формула haversine ...
перестал вращаться против часовой стрелки
5

JavaScript (ES7), 90 байт

Примечание: см. Сообщение @ OlivierGrégoire для более короткого решения

Прямой порт ответа Тфельда . Вводит в радианах.

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

Попробуйте онлайн!

Arnauld
источник
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)
l4m2
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))
Кевин Круйссен,
1
74 байта, используя более короткий алгоритм(a,b,c,d,M=Math)=>1737*M.acos(M.cos(a-c)+M.cos(a)*M.cos(c)*(M.cos(d-b)-1))
@Neil
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○ синус этого; {грех ( (ϕ₁ - ϕ₂)2 ), грех ( (λ₁ - λ₂)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*

Попробуйте онлайн!

Вводит в радианах.


Старая версия, до того как ввод / вывод был ослаблен: принимает ввод как целые градусы и возвращает округленное расстояние

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

Попробуйте онлайн!

TFeld
источник
вы можете отбросить, 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.as 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))
Нил
(Эта формулировка не короче в оригинальном языке Wolfram Language.)
Нил
3

Japt , 55 50 байт

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

Не обязательно так же точно, как другие ответы, но парень, я развлекался с этим. Позвольте мне уточнить.
В то время как в большинстве языков эта задача довольно проста, у Japt есть прискорбное свойство - нет ни встроенного арксинуса, ни арккозина. Конечно, вы можете встраивать 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. Поскольку код символа 1737не соответствует ISO-8859-1, он переключается на UTF-8, который стоит дороже. Вместо этого вы можете использовать код 173+ для + 7. ethproductions.github.io/japt/?v=1.4.5&code=I603&input=
Оливер
Вы также можете удалить ,после ToMP:-)
Оливер
@Oliver Большое спасибо, скобки были необходимы в моей оригинальной версии, но они устарели, когда немного поиграли в гольф, хотя я полностью пропустил это. Кроме того, не знал о кодировке, большое спасибо за это тоже.
Нить
1
Если вы хотите пойти по пути JavaScript, имейте в виду, что вы можете запустить все через Shoco.
Оливер
2

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

-4 байта благодаря милям (использование {и }при использовании их формулы .

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

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

Попробуйте онлайн!


Мой ... (также сохранил байт здесь, используя {)

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

Попробуйте онлайн

Джонатан Аллан
источник
О, интересно, я снова обновил страницу, и она показала ваши изменения, просто щелкнув новый ответ, чтобы показать, что изменение не обновляется, чтобы показать ваши изменения. 18-байтовая альтернатива была;I}ÆẠP+ÆSP${ÆA×⁽£ġ
миль
Никогда не понимал, как использовать, {и }они никогда не делают то, что я ожидал. Разве это не значит, что я могу поступить иначе в 17 лет ?!
Джонатан Аллан
Может быть. {и }просто создать диаду из монады. Аналогичная точка зрения может быть P{ -> ḷP¥. Возможно, было бы неплохо добавить композицию (из J), чтобы быстро сделать что-то подобное, x (P+$) y -> (P x) + (P y)что может сохранить один или два байта в похожих ситуациях.
миль
2

MATLAB с Mapping Toolbox, 26 байтов

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

Анонимная функция, которая принимает четыре входа в виде массива ячеек в том же порядке, как описано в задании.

Обратите внимание, что это дает точные результаты (при условии, что радиус Луны составляет 1737 км), потому что 1737/180равен 9.65.

Пример запуска в Matlab R2017b:

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

Луис Мендо
источник
1

Python 3, 79 байт

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

TIO не имеет geopy.py

RootTwo
источник
2
@ Нет, я понимаю, что было бы справедливо использовать общедоступную библиотеку, которая предшествует вопросу. Я думаю, что это похоже на использование картографических инструментов MATLAB или на другие языки с использованием математической библиотеки.
RootTwo
1

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

Полная программа. Запрашивает стандартный ввод для {ϕ₁, ϕ₂}, а затем для {λ₁, λ₂}. Печать на стандартный вывод.

Используется формула 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 с использованием формулы @ Neil

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

Попробуйте онлайн!

jxh
источник
Я считаю, что вам нужно добавить два байта для -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))

Используя формулу @ Neil. Ввод в радианах.

Wernisch
источник
1

Омар , 66 байт

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

Использует формулу миль, но ввод в градусах. Это добавляет дополнительный шаг преобразования в радианы перед умножением на радиус.

Panda0nEarth
источник
1

SmileBASIC, 60 байтов

INPUT X,Y,S,T?1737*ACOS(COS(X-S)+COS(X)*COS(S)*(COS(T-Y)-1))
12Me21
источник