yosmo78
yosmo78

Reputation: 619

Convert from atan2 to atan

So I saw the post asking how to convert from atan to atan2. But I haven't seen the reverse. So how would one convert from atan2 to atan? Any help is much appreciated!

I am actually extremely surprised that I could not find this question anywhere on stack overflow (my searching skills may be limited lol). I want to go this route since atan2 seems more numerically stable than atan (but I may be wrong).

Upvotes: 0

Views: 437

Answers (2)

chux
chux

Reputation: 154572

Use the sign of x to determine how to call atan2(). @Eric Postpischil

It is more accurate than subtracting pi when atan2(y, x) is near pi.

Use of signbit() helps preserve sign edge cases versus 0 <= x.

#include <math.h>

double atan_alt(double y, double x) {
  return signbit(x) ? atan2(-y, -x) : atan2(y, x);
}

To demo differences:

int main(void) {
  const double d[] = {-INFINITY, -DBL_MAX, -1.0, -DBL_MIN, -DBL_TRUE_MIN, -0.0, //
      +0.0, + DBL_TRUE_MIN, +DBL_MIN, +1.0, +DBL_MAX, +INFINITY};

  int n = sizeof d / sizeof d[0];
  puts("Sign differences");
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      double y0 = myatan(d[j], d[i]);
      double y1 = atan_alt(d[j], d[i]);
      if (signbit(y0) != signbit(y1)) {
        printf("%14g %14g %22g %22g\n", d[i], d[j], y0, y1);
      }
    }
  }
  puts("Value differences");
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      double y0 = myatan(d[j], d[i]);
      double y1 = atan_alt(d[j], d[i]);
      if (signbit(y0) != signbit(y1)) {
        ;
      } else if (memcmp(&y0, &y1, sizeof y0)) {
        printf("%14g %14g %22a %22a %26La\n", d[i], d[j], y0,
            y1, atanl(d[j] / d[i]));
      }
    }
  }

  return 0;
}

Ouptut

Sign differences
          -inf             -0               -6.28319                      0
          -inf              0                      0                     -0
          -inf   4.94066e-324                      0                     -0
          -inf   2.22507e-308                      0                     -0
          -inf              1                      0                     -0
          -inf   1.79769e+308                      0                     -0
 -1.79769e+308             -0               -6.28319                      0
 -1.79769e+308              0                      0                     -0
 -1.79769e+308   4.94066e-324                      0                     -0
 -1.79769e+308   2.22507e-308                      0                     -0
 -1.79769e+308              1                      0          -5.56268e-309
            -1             -0               -6.28319                      0
            -1              0                      0                     -0
            -1   4.94066e-324                      0          -4.94066e-324
            -1   2.22507e-308                      0          -2.22507e-308
 -2.22507e-308             -0               -6.28319                      0
 -2.22507e-308              0                      0                     -0
 -2.22507e-308   4.94066e-324                      0           -2.22045e-16
 -4.94066e-324             -0               -6.28319                      0
 -4.94066e-324              0                      0                     -0
            -0           -inf                -1.5708                 1.5708
            -0  -1.79769e+308                -1.5708                 1.5708
            -0             -1                -1.5708                 1.5708
            -0  -2.22507e-308                -1.5708                 1.5708
            -0  -4.94066e-324                -1.5708                 1.5708
            -0             -0               -3.14159                      0
            -0              0                3.14159                     -0
            -0   4.94066e-324                 1.5708                -1.5708
            -0   2.22507e-308                 1.5708                -1.5708
            -0              1                 1.5708                -1.5708
            -0   1.79769e+308                 1.5708                -1.5708
            -0            inf                 1.5708                -1.5708
Value differences
 -1.79769e+308             -1                 0x0p+0              0x1p-1024                  0x1p-1024
            -1  -1.79769e+308   0x1.921fb54442d17p+0   0x1.921fb54442d18p+0    0x1.921fb54442d1846ap+0
            -1  -2.22507e-308                 0x0p+0              0x1p-1022                  0x1p-1022
            -1  -4.94066e-324                 0x0p+0              0x1p-1074                  0x1p-1074
            -1   1.79769e+308  -0x1.921fb54442d17p+0  -0x1.921fb54442d18p+0   -0x1.921fb54442d1846ap+0
 -2.22507e-308  -1.79769e+308   0x1.921fb54442d17p+0   0x1.921fb54442d18p+0    0x1.921fb54442d1846ap+0
 -2.22507e-308             -1   0x1.921fb54442d17p+0   0x1.921fb54442d18p+0    0x1.921fb54442d1846ap+0
 -2.22507e-308  -4.94066e-324                 0x0p+0                0x1p-52                    0x1p-52
 -2.22507e-308              1  -0x1.921fb54442d17p+0  -0x1.921fb54442d18p+0   -0x1.921fb54442d1846ap+0
 -2.22507e-308   1.79769e+308  -0x1.921fb54442d17p+0  -0x1.921fb54442d18p+0   -0x1.921fb54442d1846ap+0
 -4.94066e-324  -1.79769e+308   0x1.921fb54442d17p+0   0x1.921fb54442d18p+0    0x1.921fb54442d1846ap+0
 -4.94066e-324             -1   0x1.921fb54442d17p+0   0x1.921fb54442d18p+0    0x1.921fb54442d1846ap+0
 -4.94066e-324  -2.22507e-308   0x1.921fb54442d16p+0   0x1.921fb54442d17p+0    0x1.921fb54442d1746ap+0
 -4.94066e-324   2.22507e-308  -0x1.921fb54442d16p+0  -0x1.921fb54442d17p+0   -0x1.921fb54442d1746ap+0
 -4.94066e-324              1  -0x1.921fb54442d17p+0  -0x1.921fb54442d18p+0   -0x1.921fb54442d1846ap+0
 -4.94066e-324   1.79769e+308  -0x1.921fb54442d17p+0  -0x1.921fb54442d18p+0   -0x1.921fb54442d1846ap+0

Simplistically we could use atan(y/x). atan2(y,x) does have advantages with x or y as infinity or some zero.

We do get slightly better numeric answers with atan2(y,x), instead of atan(y/x), yet atan(y/x) remains an attractive simplification.

Upvotes: 4

AbdelAziz AbdelLatef
AbdelAziz AbdelLatef

Reputation: 3744

You can do the opposite from what was done in this question.

double myatan(double y, double x)
{
    double pi = 3.14159265358979323846;
    if (x >= 0)
        return atan2(y, x);
    else if (y >= 0)
        return atan2(y, x) - pi;
    else
        return atan2(y, x) + pi;
}

Upvotes: 0

Related Questions