17
\$\begingroup\$

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°
\$\endgroup\$
3
  • \$\begingroup\$ Required precision in rads/degrees? \$\endgroup\$
    – Luis Mendo
    Jun 18, 2016 at 15:44
  • \$\begingroup\$ I'd say accurate to about machine precision, depending on what implementation you use (float/double/whatever) \$\endgroup\$
    – flawr
    Jun 18, 2016 at 15:45
  • \$\begingroup\$ May we take input as a single complex number? \$\endgroup\$
    – Adám
    Dec 3, 2018 at 14:40

15 Answers 15

9
\$\begingroup\$

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
      
\$\endgroup\$
2
  • \$\begingroup\$ Does matl really have no absolute value builtin? If it does, you could probably use it to replace 0<?_, shaving off a few bytes \$\endgroup\$
    – Zwei
    Jun 18, 2016 at 16:32
  • 2
    \$\begingroup\$ @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)) \$\endgroup\$
    – Luis Mendo
    Jun 18, 2016 at 16:38
5
\$\begingroup\$

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)
\$\endgroup\$
3
  • \$\begingroup\$ What units? Please put them into your answer. \$\endgroup\$ Jun 19, 2016 at 16:20
  • \$\begingroup\$ What's the ||0 for? \$\endgroup\$
    – l4m2
    Dec 3, 2018 at 7:49
  • \$\begingroup\$ @l4m2 For the x=y=0 case. \$\endgroup\$
    – Neil
    Dec 3, 2018 at 8:55
4
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

Javascript ES6, 54 bytes

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

Uses radians.

\$\endgroup\$
0
2
\$\begingroup\$

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!

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

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

\$\endgroup\$
4
  • 1
    \$\begingroup\$ tip \$\endgroup\$
    – ngn
    Dec 3, 2018 at 10:23
  • \$\begingroup\$ 11○∘⍟ -> 12○ \$\endgroup\$
    – ngn
    Dec 3, 2018 at 14:33
  • \$\begingroup\$ @ngn You may not use … argOfComplexNumber \$\endgroup\$
    – Adám
    Dec 3, 2018 at 14:39
  • \$\begingroup\$ oh... i see, sorry \$\endgroup\$
    – ngn
    Dec 3, 2018 at 14:41
2
\$\begingroup\$

Jelly, 11 bytes

<0×ØP+÷@ÆṬ¥

Output is in radians. Jelly had a sign bug in its division atoms which was fixed.

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.
\$\endgroup\$
4
  • \$\begingroup\$ 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?) \$\endgroup\$ Jun 19, 2016 at 17:13
  • \$\begingroup\$ @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. \$\endgroup\$
    – Dennis
    Jun 19, 2016 at 17:15
  • \$\begingroup\$ 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? \$\endgroup\$ Jun 19, 2016 at 17:21
  • \$\begingroup\$ 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. \$\endgroup\$
    – Dennis
    Jun 19, 2016 at 17:45
1
\$\begingroup\$

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
\$\endgroup\$
1
  • \$\begingroup\$ That is a clever idea! Could you add an example how to call this function? \$\endgroup\$
    – flawr
    May 25, 2017 at 12:50
1
\$\begingroup\$

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));
    }
  }
}
\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
0
\$\begingroup\$

Pyth, 26 bytes

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

theta in radians.

Test suite.

\$\endgroup\$
0
0
\$\begingroup\$

𝔼𝕊𝕄𝕚𝕟, 13 chars / 17 bytes

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

Try it here (ES6 browsers only).

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

\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
0
\$\begingroup\$

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)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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