Help me I'm lost in the ocean!

11

1

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.

Mario

Posted 2016-11-24T10:20:17.470

Reputation: 3 043

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). – Osable – 2016-11-24T11:08:03.830

@Osable first 2 decimals are ok if you output in meters – Mario – 2016-11-24T11:21:47.123

What is the range of input? – Osable – 2016-11-24T11:27:32.983

@Osable you can consider the input to be from 0 to 100 (even too much than necessary/possible in this case). – Mario – 2016-11-24T11:36:59.573

Ok maybe h² is not that negligible within a centimeter if it goes up to 100 meters. – Osable – 2016-11-24T12:29:41.300

1You should have tried the Coast Guard Stack Exchange - code golferse can't help you get out of the ocean, man! – corsiKa – 2016-11-24T16:12:37.763

>

  • How are you measuring the "distance from my friend's position"? Euclidean distance to his feet? Great circle distance to his feet, assuming a spherical Earth? Euclidean distance to the torch? 2. What is the range of possible input? 3. What accuracy is required in the output?
  • < – Peter Taylor – 2016-11-25T08:47:45.377

    @PeterTaylor please see this Meta post

    – Mario – 2016-11-25T08:52:21.250

    I've seen that meta post. I'm still waiting for an answer to my questions. – Peter Taylor – 2016-11-26T11:07:25.960

    @PeterTaylor I edited the question adding explicitly all the specifications. – Mario – 2016-11-27T16:58:11.730

    Answers

    4

    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!

    Osable

    Posted 2016-11-24T10:20:17.470

    Reputation: 1 321

    112742000 can be written as •1#oC• – Emigna – 2016-11-24T13:21:47.447

    For reference, it would have been 9 bytes: •1#oC•+*t in 2sable – Emigna – 2016-11-24T13:23:38.590

    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. – Osable – 2016-11-24T13:26:39.957

    Correct. It is a base 10 number encoded in base 214. – Emigna – 2016-11-24T13:35:38.533

    The result can be achieved also by trigonometry but is probably longer. – Mario – 2016-11-24T14:09:10.803

    I meant that there is no trigonometric function in the current version of 05AB1E. However I found a Taylor series of acos(1/(1+x)) when x is close to 0, which is the case since x=h/R. It turns out that it's close to sqrt(2*h*R) as I mentionned earlier on another answer. This formula is then doable, but its accuracy is larger than one centimeter for the given input range. – Osable – 2016-11-24T14:17:58.713

    4

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

    R. Kap

    Posted 2016-11-24T10:20:17.470

    Reputation: 4 730

    lambda i:(i*(i+12742))**.5 would be even shorter. – Osable – 2016-11-24T11:13:53.800

    @Osable Nice! I was just about to do that. :) – R. Kap – 2016-11-24T11:18:29.080

    If there is mathematical tolerance, given the discrepancy between i and 12742, the expression can be shortened so: (i*12742)**.5 – Osable – 2016-11-24T11:21:38.263

    Results are wrong. 11.5m -> ~380km instead of ~12km – G B – 2016-11-25T12:23:52.057

    @GB The program reads its input as kilometers. – Osable – 2016-11-25T12:40:37.143

    Oops, you are right, sorry. – G B – 2016-11-25T12:47:35.060

    4

    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

    Titus

    Posted 2016-11-24T10:20:17.470

    Reputation: 13 814

    4

    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
    

    R. Kap

    Posted 2016-11-24T10:20:17.470

    Reputation: 4 730

    4

    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

    manatwork

    Posted 2016-11-24T10:20:17.470

    Reputation: 17 865

    4

    Haskell, 22 bytes

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

    Usage:

    Prelude> d 11.5
    12105.087040166212
    

    Pointfree: (23 bytes)

    sqrt.((*)=<<(+12742e3))
    

    Laikoni

    Posted 2016-11-24T10:20:17.470

    Reputation: 23 676

    3

    R, 29 bytes

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

    Takes input from stdin

    Billywob

    Posted 2016-11-24T10:20:17.470

    Reputation: 3 363

    A couple of bytes shorter is (h=scan())*(1+12742e3/h)^.5. – Flounderer – 2017-04-10T04:22:54.057

    2

    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)
    

    Martin Ender

    Posted 2016-11-24T10:20:17.470

    Reputation: 184 808

    2

    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.

    user62131

    Posted 2016-11-24T10:20:17.470

    Reputation:

    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. – Osable – 2016-11-25T11:28:24.347

    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. – None – 2016-11-25T11:33:22.130

    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. – Peter Taylor – 2016-11-25T11:54:30.080

    1The 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! – None – 2016-11-25T12:12:57.183

    1Requested 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. – Osable – 2016-11-25T12:32:42.870

    2

    Ruby, 23

    23 bytes, in Km

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

    25 bytes, in m

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

    G B

    Posted 2016-11-24T10:20:17.470

    Reputation: 11 099

    1

    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.

    R. Kap

    Posted 2016-11-24T10:20:17.470

    Reputation: 4 730

    there is an *s* missing on get*s* – sergiol – 2018-12-13T18:53:03.120

    1

    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.

    user62131

    Posted 2016-11-24T10:20:17.470

    Reputation:

    1

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

    user41805

    Posted 2016-11-24T10:20:17.470

    Reputation: 16 320

    1

    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
    

    user41805

    Posted 2016-11-24T10:20:17.470

    Reputation: 16 320