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

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.

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°

• Required precision in rads/degrees? – Luis Mendo Jun 18 '16 at 15:44
• I'd say accurate to about machine precision, depending on what implementation you use (float/double/whatever) – flawr Jun 18 '16 at 15:45
• May we take input as a single complex number? – Adám Dec 3 '18 at 14:40

MATL, 12 bytes

yYy/X;0G0<?_


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


• 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 Jun 18 '16 at 16:32
• @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 Jun 18 '16 at 16:38

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)

• What units? Please put them into your answer. – Solomon Ucko Jun 19 '16 at 16:20
• What's the ||0 for? – l4m2 Dec 3 '18 at 7:49
• @l4m2 For the x=y=0 case. – Neil Dec 3 '18 at 8:55

MATLAB / Octave, 24 bytes

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


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

Javascript ES6, 54 bytes

(x,y,m=Math)=>x<0&!y?m.PI:m.atan(y/(m.hypot(x,y)+x))*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.

• 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 Jun 19 '16 at 17:13
• @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 Jun 19 '16 at 17:15
• 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 Jun 19 '16 at 17:21
• 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 Jun 19 '16 at 17:45

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!

• Do you have to write out and and or? – flawr Jun 18 '16 at 16:18
• What else can I do? – Leaky Nun Jun 18 '16 at 16:22
• @flawr Python only has and and or. – Dennis Jun 18 '16 at 18:33
• pi*(x<0==y)or atan(y/(hypot(x,y)+x))*2 saves a few bytes. – Dennis Jun 18 '16 at 18:34
• @flawr: & is a bitwise operator. – vaultah Jun 18 '16 at 19:04

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

• tip – ngn Dec 3 '18 at 10:23
• @ngn Thank you. – Adám Dec 3 '18 at 13:27
• 11○∘⍟ -> 12○ – ngn Dec 3 '18 at 14:33
• @ngn You may not use … argOfComplexNumber – Adám Dec 3 '18 at 14:39
• oh... i see, sorry – ngn Dec 3 '18 at 14:41

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

• That is a clever idea! Could you add an example how to call this function? – flawr May 25 '17 at 12:50

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


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

Pyth, 26 bytes

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


theta in radians.

Test suite.

𝔼𝕊𝕄𝕚𝕟, 13 chars / 17 bytes

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


Try it here (ES6 browsers only).

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

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.

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


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)