11
\$\begingroup\$

Introduction

Today I went fishing alone with my canoe, unfortunately I fell asleep and the stream brought me away, I lost my oars, now it's night and I am lost in the ocean! I can't see the coast so I must be far away!

I have my cell phone but is malfunctional because it got wet by the salty water, I can't talk or hear anything because the mic and phone speaker are broken, but I can send SMS to my friend who is on the coast's beach!

My friend has a very powerful torch and he raised it on top of bamboo's canes to show me the right direction, but I can’t row because I have no oars, so I must tell him how far I am so he can send someone to catch me!

My friend told me that he is keeping the torch at 11.50 meters on the sea level, and I can see the light right over the horizon. Now I only remember from the school that the Earth radius should be 6371 Km at the sea level, and I’m sittin in my canoe so you can assume that my eyes are at sea level too.

Task

Since the currents are moving me moment by moment, my friend is raising the torch from time to time (now it’s at 12.30 meters), please write a full program or function that will help me to calculate the distance from my friend’s position!

Here is a diagram (not to scale):

enter image description here

The orange point labelled M is me, the red point labelled T is the torch. The green line is the linear distance between M and T

Input

Take from standard input the torch height h in meters at the sea level, which I see right on top of the horizon, in the form of a floating point number with two decimals precision (with the accuracy of 1 centimeter or 0.01 meters), in the range from 0 to 100 included.

Output

You should return the euclidean length of the green line with the accuracy of 1 cm. For example if you output in meters, should be with two decimals (at least). The output can be either meters or kilometers, but respecting the accuracy.

Test cases:

All values in meters.

11.5 > 12105.08
13.8 > 13260.45

Rules

Shortest code wins.

\$\endgroup\$
  • \$\begingroup\$ Does the result have to be mathematically correct or is it ok if the first 2 decimals are ok? I mean that hxh is small in comparison to 2xRxh and can be neglected for small distances. (R is the radius of Earth and h is the height of the torch). \$\endgroup\$ – Osable Nov 24 '16 at 11:08
  • \$\begingroup\$ @Osable first 2 decimals are ok if you output in meters \$\endgroup\$ – Mario Nov 24 '16 at 11:21
  • \$\begingroup\$ What is the range of input? \$\endgroup\$ – Osable Nov 24 '16 at 11:27
  • \$\begingroup\$ @Osable you can consider the input to be from 0 to 100 (even too much than necessary/possible in this case). \$\endgroup\$ – Mario Nov 24 '16 at 11:36
  • 1
    \$\begingroup\$ You should have tried the Coast Guard Stack Exchange - code golferse can't help you get out of the ocean, man! \$\endgroup\$ – corsiKa Nov 24 '16 at 16:12

14 Answers 14

4
\$\begingroup\$

05AB1E, 13 12 10 bytes

Saved 2 bytes thanks to Emigna.

Since there is no trigonometric functions to be called using OP's assumption that the earth is locally a plane, it becomes possible to make an 05AB1E solution.

•1#oC•+¹*t

           For understanding purposes input is referred to as 'h'
•1#oC•     Push 12742000 [ = 2*R, where R is the radius of earth]
      +    Compute 2*R+h
       ¹*  Multiply by h. Result is (2*R*+h)*h
         t Take the square root of it and implicitly display it

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ 12742000 can be written as •1#oC• \$\endgroup\$ – Emigna Nov 24 '16 at 13:21
  • \$\begingroup\$ For reference, it would have been 9 bytes: •1#oC•+*t in 2sable \$\endgroup\$ – Emigna Nov 24 '16 at 13:23
  • \$\begingroup\$ Does a string sourrounded with depict a... base 214 number? 05AB1E suffers a lack of documentation on such special functions sometimes. Nice 2sable answer also. I found out about it a few days ago but I didn't think about using it for this question. \$\endgroup\$ – Osable Nov 24 '16 at 13:26
  • \$\begingroup\$ Correct. It is a base 10 number encoded in base 214. \$\endgroup\$ – Emigna Nov 24 '16 at 13:35
  • \$\begingroup\$ The result can be achieved also by trigonometry but is probably longer. \$\endgroup\$ – Mario Nov 24 '16 at 14:09
4
\$\begingroup\$

Python, 34 26 bytes:

(-8 bytes thanks to Osable!)

lambda i:(i*(i+12742))**.5

An anonymous lambda function. Takes input in kilometers and outputs in kilometers. Invoke as print(<Function Name>(<Input>)).

\$\endgroup\$
  • \$\begingroup\$ lambda i:(i*(i+12742))**.5 would be even shorter. \$\endgroup\$ – Osable Nov 24 '16 at 11:13
  • \$\begingroup\$ @Osable Nice! I was just about to do that. :) \$\endgroup\$ – R. Kap Nov 24 '16 at 11:18
  • \$\begingroup\$ If there is mathematical tolerance, given the discrepancy between i and 12742, the expression can be shortened so: (i*12742)**.5 \$\endgroup\$ – Osable Nov 24 '16 at 11:21
  • \$\begingroup\$ Results are wrong. 11.5m -> ~380km instead of ~12km \$\endgroup\$ – G B Nov 25 '16 at 12:23
  • \$\begingroup\$ @GB The program reads its input as kilometers. \$\endgroup\$ – Osable Nov 25 '16 at 12:40
4
\$\begingroup\$

PHP, 34 bytes

<?=sqrt((12742e3+$h=$argv[1])*$h);

breakdown

   r^2+x^2=(r+h)^2      # Pythagoras base
   r^2+x^2=r^2+2rh+h^2  # right term distributed
       x^2=    2rh+h^2  # -r^2
       x =sqrt(2rh+h^2) # sqrt

so far, this is identical to the old Mathematica answer

sqrt(2*6371e3*$h+$h*$h) # to PHP
sqrt(14742e3*$h+$h+$h)  # constants combined
sqrt((14742e3+$h)*$h)   # conjugation to save a byte
((14742e3+$h)*$h)**.5   # same size

now all that´s left to do is to add input =$argv[1] and output <?= - done

\$\endgroup\$
4
\$\begingroup\$

dc, 16 11 bytes:

?d12742+*vp

Prompts for input through command line in kilometers and then outputs distance in kilometers.

Explanation

?           # Prompt for input
 d          # Duplicate the top-of-stack value
  12742     # Push 12,742 onto the stack
       +    # Pop the top 2 values of the stack and push their sum
        *   # Pop top 2 values of the stack and push their product
         v  # Pop the remaining value and push the square root
          p # Output the result to STDOUT

This takes advantage of the following:

((6371+h)**2-6371**2)**.5 
=> ((6371**2+12742h+h**2)-6371**2)**0.5 
=> (h**2+12742h)**0.5 
=> (h*(h+12742))**0.5
\$\endgroup\$
4
\$\begingroup\$

jq, 18 characters

(12742e3+.)*.|sqrt

Yet another copy of the same formula.

Sample run:

bash-4.3$ jq '(12742e3+.)*.|sqrt' <<< 11.5
12105.087040166212

On-line test

\$\endgroup\$
4
\$\begingroup\$

Haskell, 22 bytes

d h=sqrt$h*(h+12742e3)

Usage:

Prelude> d 11.5
12105.087040166212

Pointfree: (23 bytes)

sqrt.((*)=<<(+12742e3))
\$\endgroup\$
3
\$\begingroup\$

R, 29 bytes

h=scan();sqrt(h^2+2*h*6371e3)

Takes input from stdin

\$\endgroup\$
  • \$\begingroup\$ A couple of bytes shorter is (h=scan())*(1+12742e3/h)^.5. \$\endgroup\$ – Flounderer Apr 10 '17 at 4:22
2
\$\begingroup\$

Mathematica, 16 bytes

Either of these works for both input and output in kilometres:

(12742#+#*#)^.5&
((12742+#)#)^.5&

This is a simple application of Pythagoras to the problem:

   x*x + R*R = (R+h)*(R+h)
=> x*x = (R+h)*(R+h) - R*R
       = R*R + 2*R*h + h*h - R*R
       = 2*R*h + h*h
=>   x = √(2*R*h + h*h)
\$\endgroup\$
2
\$\begingroup\$

Jelly, 9 bytes in Jelly's code page

I decided to have a go at writing the program in a golfing language. I actually found a more efficient algorithm than the one other people are using (at least over short distances like the one in the question), but it requires literal floating-point numbers which Jelly doesn't seem to be able to compress, so Pythagoras it is.

+“Ȯịż’×µ½

Explanation:

 “Ȯịż’     12742000, compressed base-250
+          add to argument
      ×    multiply with original argument
       µ   separator to avoid what would otherwise be a parsing ambiguity
        ½  square root everything seen so far
           implicit output at EOF

The need for the µ separator irks me, but I think it's unavoidable; Jelly has already saved a byte over 05AB1E via being able to guess what arguments many of the commands need, but in this case it can't correctly guess to the end, so I needed to give it a hint.

Jelly, 7 bytes in Jelly's code page

דȮịż’½

As I explained in my other answer, the series approximation to the Pythagoras approximation actually produces better results over the lengths included in the question (at least, they're closer to the example outputs), and also has a shorter formula. While I was writing it, I realised that instead of calculating the square root of 12742000 in advance, I could multiply the number by 12742000 first, and then square root both at the same time. This is basically equivalent to the other formula without the addition, and as such, it can be produced from the previous program via removing the addition from it. This saves two bytes, as it now parses unambiguously and so we don't need a µ any more.

\$\endgroup\$
  • \$\begingroup\$ I decided not to use this optimization because it doesn't yield the same values if you look at the centimeters (cf. requested output) given the range of h. It would also save 2 bytes in 05AB1E. \$\endgroup\$ – Osable Nov 25 '16 at 11:28
  • \$\begingroup\$ With the optimization, I get outputs of 12105.081577585506 and 13260.452480967608; those are very close to the test case's output, and round to them. Without, I get 12105.087040166212 and 13260.459661716106, which are further away (and the latter is incorrect in the centimeters, rounding to 13260.46). As mentioned in the other answer, the optimization happens to be closer to the correct value than the optimized code because it contains two errors that largely cancel each other out, rather than just one which has nothing to cancel it. \$\endgroup\$ – user62131 Nov 25 '16 at 11:33
  • \$\begingroup\$ Since you just voted to "Leave open" in the review queue, I assume that you believe you know the answers to the questions for which I requested clarification in the comments. Please therefore edit the question so that it is unambiguous. \$\endgroup\$ – Peter Taylor Nov 25 '16 at 11:54
  • 1
    \$\begingroup\$ The question is unambiguous: the author needs to know the distance to his friend to help navigate. He can determine the position of the torch to an accuracy of 0.1 metres (we can determine this from the story that's told). This is inevitably going to give approximately 1 metre of uncertainty from the output at the current distance (note: the author is drifting around, thus is unlikely to move very far very quickly…), and therefore anything that's approximately that accurate is likely to be acceptable. Part of the problem is determining how accurate you'd need to be in this situation! \$\endgroup\$ – user62131 Nov 25 '16 at 12:12
  • 1
    \$\begingroup\$ Requested output shows 2 decimals in meters. So accuracy is expected to be 1 centimeter. In the comments to the question, OP said that h could go up to 100. With h=100 there is a discrepancy of 14 centimeters from the original algorithm. \$\endgroup\$ – Osable Nov 25 '16 at 12:32
2
\$\begingroup\$

Ruby, 23

23 bytes, in Km

->h{(h*h+h*12742)**0.5}

25 bytes, in m

->h{(h*h+h*12742e3)**0.5}
\$\endgroup\$
1
\$\begingroup\$

Tcl, 49 bytes:

set A [get stdin];puts [expr ($A*($A+12742))**.5]

Well, I am brand new to Tcl, so any tips for golfing this down is highly appreciated. Like my other answers, prompts for command line input in kilometers and outputs in kilometers. Essentially a Tcl adaptation of my existing dc and python answers.

\$\endgroup\$
  • \$\begingroup\$ there is an s missing on gets \$\endgroup\$ – sergiol Dec 13 '18 at 18:53
1
\$\begingroup\$

x86_64+SSE machine code, 16 bytes

The bytes of the program are on the left (in hexadecimal), there's a disassembly on the right to make it a bit easier to read. This is a function that follows the normal x86_64 convention for functions taking and returning a single-precision floating point number (it takes the argument in %xmm0 and returns its answer in the same register, and uses %xmm1 and %eax as temporaries; these are the same calling conventions a C program will use, and as such you can call the function directly from a C program, which is how I tested it).

b8 80 19 5f 45          mov    $0x455f1980,%eax
66 0f 6e c8             movd   %eax,%xmm1
0f 51 c0                sqrtps %xmm0,%xmm0
0f 59 c1                mulps  %xmm1,%xmm0
c3                      retq

Even with a disassembly, though, this still needs an explanation. First, it's worth discussing the formula. Most people are ignoring the curvature of the earth and using Pythagoras' formula to measure the distance. I'm doing it too, but I'm using a series expansion approximation; I'm only taking the term relating to the first power of the input, and ignoring the third, fifth, seventh, etc. powers, which all have only a very small influence at this short distance. (Besides, the Pythagoras approximation gives a low value, whereas the later terms in the series expansion serve to reduce the value; as such, by ignoring a minor factor that would serve to push the approximation in the wrong direction, I actually happen to get a more accurate result by using a less accurate formula.) The formula turns out to be √12742000×√h; as a single-precision floating-point number, √12742000 is 0x455f1980.

The next thing that might confuse people is why I'm using vector instructions for the square root and the multiply; %xmm0 and %xmm1 can hold four single-precision floating point numbers each, and I'm operating on all four. The reasoning here is really simple: their encoding is one byte shorter than that of the corresponding scalar instructions. So I can make the FPU do a bunch of extra work square-rooting and multiplying zeroes in order to save myself two bytes, in a method that's very reminsicent of the typical golfing language algorithm. (I called x86 assembler the golfing language of assemblers in chat a while back, and I still haven't changed my mind on that.)

From there, the algorithm's very simple: load %xmm1 with √12742000 via %eax (which is shorter in terms of bytes than loading it from memory would be), square-root the argument (and three zeroes), multiply corresponding elements of %xmm1 and %xmm0 (we only care about the first element), then return.

\$\endgroup\$
1
\$\begingroup\$

Minkolang v0.15, 22 bytes

ndd*$r'12742000'*+1MN.

Try it online!

n                               gets input in the form of a number
 dd                             duplicates it twice
   *                            multiplies 2 of the duplicates with each other
                                STACK: [h, h*h]
    $r                          swap top two stack values
                                STACK: [h*h, h]
      '12742000'*               push this number and multiply the original input by it
                                STACK: [h*h, h*12742000]
                 +1M            adds the two values and takes their square root
                                STACK: [sqrt(h*h+h*12742000)]
                    N.          output as a number and end program
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 31 25 bytes

Displays the value in metres

//the actual code 
f=h=>(h*h+12742e3*h)**0.5


console.log(f(11.5));
console.log(f(13.8));

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.