summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Cournapeau <cournape@gmail.com>2009-07-21 01:58:47 +0000
committerDavid Cournapeau <cournape@gmail.com>2009-07-21 01:58:47 +0000
commit6c8e325c7210cc03caf5c8f9f34e6ce0dd06dc79 (patch)
tree9253608e273280747e2977f505b835bfcc9a52f1
parent2024e81b568be2836bec88ab23615cef3659b3d0 (diff)
downloadnumpy-6c8e325c7210cc03caf5c8f9f34e6ce0dd06dc79.tar.gz
Add our own atan2 function, as a replacement for buggy implementations (like the MS C runtime).
-rw-r--r--numpy/core/src/npymath/npy_math.c.src89
1 files changed, 89 insertions, 0 deletions
diff --git a/numpy/core/src/npymath/npy_math.c.src b/numpy/core/src/npymath/npy_math.c.src
index e6eba425f..fb06cbdd8 100644
--- a/numpy/core/src/npymath/npy_math.c.src
+++ b/numpy/core/src/npymath/npy_math.c.src
@@ -60,6 +60,8 @@
#include "config.h"
#include "numpy/npy_math.h"
+#include "npy_math_private.h"
+
/*
*****************************************************************************
** BASIC MATH FUNCTIONS **
@@ -93,6 +95,93 @@ double npy_log1p(double x)
}
#endif
+/* Taken from FreeBSD mlib, adapted for numpy
+ *
+ * XXX: we could be a bit faster by reusing high/low words for inf/nan
+ * classification instead of calling npy_isinf/npy_isnan: we should have some
+ * macros for this, though, instead of doing it manually
+ */
+#ifndef HAVE_ATAN2
+/* XXX: we should have this in npy_math.h */
+#define NPY_DBL_EPSILON 1.2246467991473531772E-16
+double npy_atan2(double y, double x)
+{
+ npy_int32 k, m, iy, ix, hx, hy;
+ npy_uint32 lx,ly;
+ double z;
+
+ EXTRACT_WORDS(hx, lx, x);
+ ix = hx & 0x7fffffff;
+ EXTRACT_WORDS(hy, ly, y);
+ iy = hy & 0x7fffffff;
+
+ /* if x or y is nan, return nan */
+ if (npy_isnan(x * y)) {
+ return x + y;
+ }
+
+ if (x == 1.0) {
+ return npy_atan(y);
+ }
+
+ m = 2 * npy_signbit(x) + npy_signbit(y);
+ if (y == 0.0) {
+ switch(m) {
+ case 0:
+ case 1: return y; /* atan(+-0,+anything)=+-0 */
+ case 2: return NPY_PI;/* atan(+0,-anything) = pi */
+ case 3: return -NPY_PI;/* atan(-0,-anything) =-pi */
+ }
+ }
+
+ if (x == 0.0) {
+ return y > 0 ? NPY_PI_2 : -NPY_PI_2;
+ }
+
+ if (npy_isinf(x)) {
+ if (npy_isinf(y)) {
+ switch(m) {
+ case 0: return NPY_PI_4;/* atan(+INF,+INF) */
+ case 1: return -NPY_PI_4;/* atan(-INF,+INF) */
+ case 2: return 3.0*NPY_PI_4;/*atan(+INF,-INF)*/
+ case 3: return -3.0*NPY_PI_4;/*atan(-INF,-INF)*/
+ }
+ } else {
+ switch(m) {
+ case 0: return NPY_PZERO; /* atan(+...,+INF) */
+ case 1: return NPY_NZERO; /* atan(-...,+INF) */
+ case 2: return NPY_PI; /* atan(+...,-INF) */
+ case 3: return -NPY_PI; /* atan(-...,-INF) */
+ }
+ }
+ }
+
+ if (npy_isinf(y)) {
+ return y > 0 ? NPY_PI_2 : -NPY_PI_2;
+ }
+
+ /* compute y/x */
+ k = (iy - ix)>>20;
+ if(k > 60) { /* |y/x| > 2**60 */
+ z = NPY_PI_2 + 0.5 * NPY_DBL_EPSILON;
+ m &= 1;
+ } else if(hx < 0 && k < -60) {
+ z = 0.0; /* 0 > |y|/x > -2**-60 */
+ } else {
+ z = npy_atan(npy_fabs(y/x)); /* safe to do y/x */
+ }
+
+ switch (m) {
+ case 0: return z ; /* atan(+,+) */
+ case 1: return -z ; /* atan(-,+) */
+ case 2: return NPY_PI - (z - NPY_DBL_EPSILON);/* atan(+,-) */
+ default: /* case 3 */
+ return (z - NPY_DBL_EPSILON) - NPY_PI;/* atan(-,-) */
+ }
+}
+
+#endif
+
#ifndef HAVE_HYPOT
double npy_hypot(double x, double y)
{