月球两点之间的距离


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

其他可能的公式

  • d = r * acos(sin ϕ1 sin ϕ2 + cos ϕ1 cos ϕ2 cos(λ2 - λ1)) @miles的公式
  • d = r * acos(cos(ϕ1 - ϕ2) + cos ϕ1 cos ϕ2 (cos(λ2 - λ1) - 1)) @Neil的公式

输入为度并输出为四舍五入整数的示例

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 '18

2
对于大多数语言来说d = r * acos( sin ϕ1 sin ϕ2 + cos ϕ1 cos ϕ2 cos(λ2 - λ1) ),较短的公式是r = 1737
英里

Answers:



6

R + 地球圈54 47字节

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

在线尝试!

将输入作为longitude,latitude度数的2元素向量。TIO没有geosphere软件包,但是请放心,它会向下面的函数返回相同的结果。

感谢Jonathan Allan精简了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不,他们不是。这对我来说真是愚蠢,但是半径的默认参数是地球的米数,因此在当时是合乎逻辑的,大声笑
Giuseppe

请注意,余弦的球形定律在数值上不稳定,尤其是对于小距离。在Mathematica中这可能是可以的,但是在R和其他大多数语言中,是否满足“具有与hasrsine公式相同的结果的任何公式”的准则,这值得商bat。
停止了逆时针转动

@ceasedtoturncounterclockwis我主要是为了将它包含在基本R中而包含它。我想使用任意精度的浮点库将减轻这种影响。
朱塞佩

是的,或者使用诸如haversine公式之类的稳定公式...
停止了逆时针旋转


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

使用@miles的较短算法的77个字节(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
使用@Neil的较短算法的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))
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égoire18年

@OlivierGrégoire非常好。您可能应该将其发布为新答案。
Arnauld

5

APL(Dyalog Unicode)40 35 字节SBCS

匿名默认功能。以{ϕ₁,λ₁}为左自变量,以{ϕ_2,λ_2}为右自变量。

使用公式2 r√(sin²((ϕ₁-ϕ²)2)+ cos ϕ₁ cos ϕ²sin²((λ₁–λ²)2))

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

在线尝试!(该r功能将度数转换为弧度)


 连接相应的元素;{{ϕ₁,ϕ_2},{λ₁,λ_2}}

 选择第一个;{ϕ₁,ϕ²}

 然后

2×.○ 余弦的乘积;cos cos
点亮。点“乘积”,但带有触发函数选择器(2是余弦)而不是乘法,而时间不是加号

1, 在此之前添加1;{1,cosϕ₁coss_2}

( 乘以将以下函数应用于{,λ₁}和{,2,λ2}的结果:

- 他们的差异;{ϕ₁-ϕ 2,λ₁-λ2}

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 ϕssin²((λ₁-λ²)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*

在线尝试!

以弧度为单位输入。


在I / O松弛之前的旧版本:将输入作为整数度,并返回四舍五入的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由于允许使用小数作为输出,因此也可以避免转换为弧度,因为也允许使用输入作为弧度
mdahmoune18,2018年

@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的较短公式
感谢@OlivierGrégore-4个字节,因为我仍然将as {Math m=null;return ...;}与每个Math.as一起使用m.,而不是直接删除returnand使用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))
Neil

(尽管最初的Wolfram语言中的提法并不短。)
Neil

3

Japt55 50字节

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

不一定与其他答案一样精确,但是男孩确实让我很开心。请允许我详细说明。
虽然在大多数语言中,这一挑战非常简单,但是Japt的不幸之处在于,既没有反正弦也没有反余弦的内置函数。当然,您可以在Japt中嵌入Javascript,但这与风水正好相反。

为了克服这些小麻烦,我们要做的就是近似反余弦,我们很高兴!

第一部分是进入反余弦的所有内容。

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!足够大,而且速度相当快。

将输入作为弧度,输出未四舍五入的数字。

多亏了Oliver才减少了5个字节。

在线尝试!


您可以删除(中的Mc(X-V。由于的字符代码1737不是ISO-8859-1,因此它将切换到UTF-8,这会花费更多。您可以改为使用173+ 的字符代码7ethproductions.github.io/japt/?v=1.4.5&code=I603&input=
Oliver

您也可以删除,ToMP:-)
奥利弗

@Oliver非常感谢,括号在我的原始版本中是必需的,但是在打高尔夫球时有点过时了,但是我完全错过了它。另外,我也不了解编码,也非常感谢。
Nit

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岁时做其他事情吗?
乔纳森·艾伦,

也许。{}从一个monad创建一个dyad。类似的观点可能是P{ -> ḷP¥。快速添加一个compose(来自J)可能会很好,例如x (P+$) y -> (P x) + (P y)在类似情况下可以节省一两个字节。
英里

2

带映射工具箱的MATLAB,26个字节

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

将四个输入作为单元格数组的匿名函数,其顺序与挑战中所述的顺序相同。

请注意,由于1737/180等于,因此得出的结果准确(假设月球半径为1737公里)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


2
@Nit,我的理解是,使用在问题之前存在的公共图书馆是公平的游戏。我认为这就像使用MATLAB的映射工具,或使用数学库的其他语言一样。
RootTwo '18

1

APL(Dyalog Unicode),29 字节SBCS

完成程序。提示stdin为{ϕ₁,ϕ_2},然后为{λ₁,λ_2}。打印到标准输出。

使用公式r acos(sin ϕ₁ sin ϕ 2 + cos(λ2 –λ₁)cos ϕ₁ cos ϕ2)

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

在线尝试!(该r功能将度数转换为弧度)


 提示输入{ϕ₁,ϕ²}

1 2∘.○ 笛卡尔三角函数应用;{{sin ϕ₁,sin ϕ_2},{cos ϕ₁,cos ϕ_2}}

×/ 逐行产品;{sin ϕ₁ sin ϕ 2,cos ϕ₁ cos ϕ 2}

()×@2 在第二个元素上,将以下内容乘以:

 提示输入{λ₁,λ_2}

-/ 两者之间的差异;λ₁–λ2

2○ 余弦 cos(λ₁–λ2)

现在我们有了{sin ϕ₁ sin ϕ 2,cos(λ₁–λ2)cos ϕ₁ cos ϕ2}

+/ 和; sin ϕ₁ sin ϕ 2 + cos(λ₁–λ2)cos ϕ₁ cos ϕ 2

¯2○ 余弦 cos(sin ϕ₁ sin ϕ 2 + cos(λ₁–λ2)cos ϕ₁ cos ϕ2)

1737× 将r乘以;1737 cos(sin ϕ₁ sin ϕ 2 + cos(λ₁–λ2)cos ϕ₁ cos ϕ2)


允许输入度数的函数是:

○÷∘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))

在线尝试!


我相信您需要为-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的公式。输入弧度。


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))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.