g​o​l​f​ ​a​t​a​n​2

18

Sometimes it really is a struggle to convert Cartesian coordinates (x,y) to Polar coordinates (r,phi). While you can calculate r = sqrt(x^2+y^2) quite easily, you often need some distinction of cases when calculating the angle phi because arcsin,arccos and arctan and all other trigonometric functions have a co-domain that each only spans half the circle.

In many languages there are built-ins for converting rectangular to polar coordinates, or at least have an atan2 function, which - given (x,y) - calculate the angle phi.

Task

Your task is to write a program/function that takes two (floating point, not both zero) Cartesian coordinates (x,y), and outputs the corresponding polar angle phi, where phi has to be in degrees, radians or grades (with grades I mean gradians which are 1/400 of the full circle), whichever is more convenient for you.

The angle is measured in positive orientation, and we have the zero angle for (1,0).

Details

You may not use built-ins that calculate the angle phi given two coordinates, including atan2,rect2polar,argOfComplexNumber and similar functions. However you can use the usual trigonometric functions and their reverses, that only take one argument. Any unit symbols are optional.

The radius r must be non-negative, and phi must be in the range [-360°, 360°] (it does not matter whether you output 270° or -90°).

Examples

Input       Output
(1,1)       45°
(0,3)       90°
(-1,1)      135°
(-5,0)      180°
(-2,-2)     225°
(0,-1.5)    270°
(4,-5)      308.66°

flawr

Posted 2016-06-18T15:36:49.993

Reputation: 40 560

Required precision in rads/degrees? – Luis Mendo – 2016-06-18T15:44:28.453

I'd say accurate to about machine precision, depending on what implementation you use (float/double/whatever) – flawr – 2016-06-18T15:45:42.957

May we take input as a single complex number? – Adám – 2018-12-03T14:40:26.940

Answers

9

MATL, 12 bytes

yYy/X;0G0<?_

The result is in radians.

Try it online! Or verify all test cases.

Explanation

MATL doesn't have an atan function (it has atan2, but it can't be used for this challenge). So I resorted to acos.

y     % Take x, y implicitly. Duplicate x onto the top of the stack
Yy    % Compute hypothenuse from x, y
/     % Divide x by hypothenuse
X;    % Arccosine (inverse of cosine function)
0G    % Push y again
0<    % Is it negative?
?_    % If so, change sign. Implicitly end conditional branch. Implicitly display

Luis Mendo

Posted 2016-06-18T15:36:49.993

Reputation: 87 464

Does matl really have no absolute value builtin? If it does, you could probably use it to replace 0<?_, shaving off a few bytes – Zwei – 2016-06-18T16:32:56.013

2

@Zwei It has (|). But here I'm changing sign of the result based on the sign of the second input, y. Besides, y can be 0, so I can't multiply by y/abs(y))

– Luis Mendo – 2016-06-18T16:38:42.823

5

JavaScript (ES6), 50 40 bytes

(x,y)=>(Math.atan(y/x)||0)+Math.PI*(x<0)

The result is in radians. Edit: Saved 10 bytes when I noticed that it's allowed for the result to be between -90° and 270°. Previous version with -Math.PI<=result<Math.PI:

(x,y)=>(Math.atan(y/x)||0)+Math.PI*(x<0)*(y>0||-1)

Neil

Posted 2016-06-18T15:36:49.993

Reputation: 95 035

What units? Please put them into your answer. – Solomon Ucko – 2016-06-19T16:20:46.530

What's the ||0 for? – l4m2 – 2018-12-03T07:49:17.500

@l4m2 For the x=y=0 case. – Neil – 2018-12-03T08:55:50.397

4

MATLAB / Octave, 24 bytes

@(x,y)atan(y/x)+pi*(x<0)

This defines an anonymous function that produces the result in radians.

Try it on ideone.

Luis Mendo

Posted 2016-06-18T15:36:49.993

Reputation: 87 464

3

Javascript ES6, 54 bytes

(x,y,m=Math)=>x<0&!y?m.PI:m.atan(y/(m.hypot(x,y)+x))*2

Uses radians.

Mama Fun Roll

Posted 2016-06-18T15:36:49.993

Reputation: 7 234

2

APL (Dyalog Unicode), 12 10 bytesSBCS

-2 thanks to ngn.

Anonymous tacit infix function. Uses alephalpha's formula. Takes x as right argument and y as left argument. Result is in radians.

11○∘⍟0J1⊥,

Try it online!

, concatenate the y and x

0J1⊥ Evaluate as base i digits (i.e. yi¹+xi⁰)

 natural logarithm of that

 then

11○ imaginary part of that

Adám

Posted 2016-06-18T15:36:49.993

Reputation: 37 779

1tip – ngn – 2018-12-03T10:23:42.757

@ngn Thank you. – Adám – 2018-12-03T13:27:39.240

11○∘⍟ -> 12○ – ngn – 2018-12-03T14:33:59.367

@ngn You may not use … argOfComplexNumber – Adám – 2018-12-03T14:39:38.613

oh... i see, sorry – ngn – 2018-12-03T14:41:18.337

2

Python 3, 75 67 bytes

8 bytes thanks to Dennis.

from math import*
lambda x,y:pi*(x<0==y)or atan(y/(hypot(x,y)+x))*2

Ideone it!

Leaky Nun

Posted 2016-06-18T15:36:49.993

Reputation: 45 011

Do you have to write out and and or? – flawr – 2016-06-18T16:18:33.620

What else can I do? – Leaky Nun – 2016-06-18T16:22:03.757

Perhaps use && and || or something similar? – flawr – 2016-06-18T18:09:26.217

1@flawr Python only has and and or. – Dennis – 2016-06-18T18:33:58.343

2pi*(x<0==y)or atan(y/(hypot(x,y)+x))*2 saves a few bytes. – Dennis – 2016-06-18T18:34:03.810

How is then & different from and here? – flawr – 2016-06-18T18:47:43.823

4@flawr: & is a bitwise operator. – vaultah – 2016-06-18T19:04:24.893

2

Jelly, 11 bytes (non-competing)

<0×ØP+÷@ÆṬ¥

Output is in radians. Unfortunately, Jelly had a sign bug in its division atoms, making this answer non-competing due to the required bug fix.

Try it online! or verify all test cases (converted to degrees).

How it works

<0×ØP+÷@ÆṬ¥  Main link. Left argument x. Right argument: y

<0           Compare x with 0.
  ×ØP        Multiply the resulting Boolean by Pi.
          ¥  Combine the two links to the left into a dyadic chain.
      ÷@     Divide y by x.
        ÆṬ   Apply arctan to the result.
     +       Add the results to both sides.

Dennis

Posted 2016-06-18T15:36:49.993

Reputation: 196 637

Does bugfixing count as making an answer non-competing? That seems odd. If the correct behavior was already specced, the bugfix should be unrelated. (After all, who knows how many other answers you made noncompeting by fixing an unnoticed edge-case?) – Mario Carneiro – 2016-06-19T17:13:01.610

@MarioCarneiro On PPCG, the interpreter defines the language. This is mainly because it's difficult to judge intentions (and most esolangs don't really have a concise spec), while you can't argue with an implementation. Note that altering the interpreter doesn't affect the validity of older answers. They only have to work in some published version of the interpreter.

– Dennis – 2016-06-19T17:15:48.157

I mean that you may have changed the behavior of older answers on some input which was not attempted at the time. How does PPCG handle bad test cases discovered after the fact? – Mario Carneiro – 2016-06-19T17:21:50.293

If test cases prove to be insufficient, more test cases are added. Solutions are expected for all valid inputs, not just the test cases in the question. Re: bug fix. My interpreter only produced the wrong sign for division by 0 (-1÷0 gave inf instead of -inf), so it's unlikely to affect most challenges. – Dennis – 2016-06-19T17:45:41.580

1

x86 machine language (32 bit Linux), 25 13 bytes (noncompeting)

0:       55                      push   %ebp
1:       89 e5                   mov    %esp,%ebp
3:       dd 45 08                fldl   0x8(%ebp)
6:       dd 45 10                fldl   0x10(%ebp)
9:       d9 f3                   fpatan  
b:       c9                      leave
c:       c3                      ret

To try it online, compile the following C program (don't forget -m32 flag on x86_64)

#include<stdio.h>
#include<math.h>
const char j[]="U\x89\xe5\335E\b\335E\20\xd9\xf3\xc9\xc3";
int main(){
  for(double f=-1;f<1;f+=.1){
    for(double g=-1;g<1;g+=.1){
      printf("%.2f %.2f %f %f\n",f,g,atan2(f,g),((double(*)(double,double))j)(f,g));
    }
  }
}

ceilingcat

Posted 2016-06-18T15:36:49.993

Reputation: 5 503

1

Mathematica, 16 bytes

I am not sure whether Log is considered as a built-in that calculates the angle given two coordinates.

N@Im@Log[#+I#2]&

Example:

In[1]:= N@Im@Log[#+I#2]&[1,1]

Out[1]= 0.785398

In[2]:= N@Im@Log[#+I#2]&[4,-5]

Out[2]= -0.896055

alephalpha

Posted 2016-06-18T15:36:49.993

Reputation: 23 988

That is a clever idea! Could you add an example how to call this function? – flawr – 2017-05-25T12:50:53.753

1

J, 10 bytes

Anonymous tacit infix function. Uses alephalpha's formula. Takes x as left argument and y as right argument. Result is in radians.

11 o.^.@j.

Try it online!

j. calculate x + y×i

@ then

^. natural logarithm of that

11 o. imaginary part of that

Adám

Posted 2016-06-18T15:36:49.993

Reputation: 37 779

0

Axiom, 58 bytes

f(a,b)==(a=0 and b=0=>%i;sign(b)*acos(a*1./sqrt(a^2+b^2)))

test (i use only acos() it returns radiants )

(40) -> [[a,b,f(a,b)*180/%pi] for a in [1,0,-1,-5,-2,0,4] for b in [1,3,1,0,-2,-1.5,-5] ]
   (40)
   [[1.0,1.0,45.0], [0.0,3.0,90.0], [- 1.0,1.0,135.0], [- 5.0,0.0,180.0],
    [- 2.0,- 2.0,- 135.0], [0.0,- 1.5,- 90.0],
    [4.0,- 5.0,- 51.3401917459 09909396]]
                                            Type: List List Complex Float

RosLuP

Posted 2016-06-18T15:36:49.993

Reputation: 3 036

0

Python 2, 59 bytes

lambda x,y:acos(x/hypot(x,y))/(-1,1)[y>0]
from math import*

Try it online!

Outputs in radians in range [-pi,pi)

Vedant Kandoi

Posted 2016-06-18T15:36:49.993

Reputation: 1 955

0

Pyth, 26 bytes

AQ?|>G0Hy.tcH+@s^R2Q2G5.n0

theta in radians.

Test suite.

Leaky Nun

Posted 2016-06-18T15:36:49.993

Reputation: 45 011

0

, 13 chars / 17 bytes

î<0)*π+МǍ í/î

Try it here (ES6 browsers only).

Uses (x<0)*pi+tan(y/x).

Mama Fun Roll

Posted 2016-06-18T15:36:49.993

Reputation: 7 234

0

Python 3, 65 bytes

from math import*
f=lambda x,y:atan(y/x if x else y*inf)+pi*(x<0)

This outputs radians in the range [-π/2, 3π/2), equivalent to [-90, 270) degrees.

Random832

Posted 2016-06-18T15:36:49.993

Reputation: 796