Reputation: 619
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
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
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