summaryrefslogtreecommitdiff
path: root/numpy/core/src/npymath
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core/src/npymath')
-rw-r--r--numpy/core/src/npymath/_signbit.c32
-rw-r--r--numpy/core/src/npymath/arm64_exports.c30
-rw-r--r--numpy/core/src/npymath/halffloat.c555
-rw-r--r--numpy/core/src/npymath/halffloat.cpp238
-rw-r--r--numpy/core/src/npymath/ieee754.c.src33
-rw-r--r--numpy/core/src/npymath/ieee754.cpp37
-rw-r--r--numpy/core/src/npymath/npy_math_complex.c.src532
-rw-r--r--numpy/core/src/npymath/npy_math_internal.h.src2
-rw-r--r--numpy/core/src/npymath/npy_math_private.h4
9 files changed, 757 insertions, 706 deletions
diff --git a/numpy/core/src/npymath/_signbit.c b/numpy/core/src/npymath/_signbit.c
deleted file mode 100644
index 12af55387..000000000
--- a/numpy/core/src/npymath/_signbit.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Adapted from cephes */
-
-int
-_npy_signbit_d(double x)
-{
- union
- {
- double d;
- short s[4];
- int i[2];
- } u;
-
- u.d = x;
-
-#if NPY_SIZEOF_INT == 4
-
-#ifdef WORDS_BIGENDIAN /* defined in pyconfig.h */
- return u.i[0] < 0;
-#else
- return u.i[1] < 0;
-#endif
-
-#else /* NPY_SIZEOF_INT != 4 */
-
-#ifdef WORDS_BIGENDIAN
- return u.s[0] < 0;
-#else
- return u.s[3] < 0;
-#endif
-
-#endif /* NPY_SIZEOF_INT */
-}
diff --git a/numpy/core/src/npymath/arm64_exports.c b/numpy/core/src/npymath/arm64_exports.c
new file mode 100644
index 000000000..dfa8054d7
--- /dev/null
+++ b/numpy/core/src/npymath/arm64_exports.c
@@ -0,0 +1,30 @@
+#if defined(__arm64__) && defined(__APPLE__)
+
+#include <math.h>
+/*
+ * Export these for scipy, since the SciPy build for macos arm64
+ * downloads the macos x86_64 NumPy, and does not error when the
+ * linker fails to use npymathlib.a. Importing numpy will expose
+ * these external functions
+ * See https://github.com/numpy/numpy/issues/22673#issuecomment-1327520055
+ *
+ * This file is actually compiled as part of the main module.
+ */
+
+double npy_asinh(double x) {
+ return asinh(x);
+}
+
+double npy_copysign(double y, double x) {
+ return copysign(y, x);
+}
+
+double npy_log1p(double x) {
+ return log1p(x);
+}
+
+double npy_nextafter(double x, double y) {
+ return nextafter(x, y);
+}
+
+#endif
diff --git a/numpy/core/src/npymath/halffloat.c b/numpy/core/src/npymath/halffloat.c
deleted file mode 100644
index 51948c736..000000000
--- a/numpy/core/src/npymath/halffloat.c
+++ /dev/null
@@ -1,555 +0,0 @@
-#define NPY_NO_DEPRECATED_API NPY_API_VERSION
-
-#include "numpy/halffloat.h"
-
-/*
- * This chooses between 'ties to even' and 'ties away from zero'.
- */
-#define NPY_HALF_ROUND_TIES_TO_EVEN 1
-/*
- * If these are 1, the conversions try to trigger underflow,
- * overflow, and invalid exceptions in the FP system when needed.
- */
-#define NPY_HALF_GENERATE_OVERFLOW 1
-#define NPY_HALF_GENERATE_UNDERFLOW 1
-#define NPY_HALF_GENERATE_INVALID 1
-
-/*
- ********************************************************************
- * HALF-PRECISION ROUTINES *
- ********************************************************************
- */
-
-float npy_half_to_float(npy_half h)
-{
- union { float ret; npy_uint32 retbits; } conv;
- conv.retbits = npy_halfbits_to_floatbits(h);
- return conv.ret;
-}
-
-double npy_half_to_double(npy_half h)
-{
- union { double ret; npy_uint64 retbits; } conv;
- conv.retbits = npy_halfbits_to_doublebits(h);
- return conv.ret;
-}
-
-npy_half npy_float_to_half(float f)
-{
- union { float f; npy_uint32 fbits; } conv;
- conv.f = f;
- return npy_floatbits_to_halfbits(conv.fbits);
-}
-
-npy_half npy_double_to_half(double d)
-{
- union { double d; npy_uint64 dbits; } conv;
- conv.d = d;
- return npy_doublebits_to_halfbits(conv.dbits);
-}
-
-int npy_half_iszero(npy_half h)
-{
- return (h&0x7fff) == 0;
-}
-
-int npy_half_isnan(npy_half h)
-{
- return ((h&0x7c00u) == 0x7c00u) && ((h&0x03ffu) != 0x0000u);
-}
-
-int npy_half_isinf(npy_half h)
-{
- return ((h&0x7fffu) == 0x7c00u);
-}
-
-int npy_half_isfinite(npy_half h)
-{
- return ((h&0x7c00u) != 0x7c00u);
-}
-
-int npy_half_signbit(npy_half h)
-{
- return (h&0x8000u) != 0;
-}
-
-npy_half npy_half_spacing(npy_half h)
-{
- npy_half ret;
- npy_uint16 h_exp = h&0x7c00u;
- npy_uint16 h_sig = h&0x03ffu;
- if (h_exp == 0x7c00u) {
-#if NPY_HALF_GENERATE_INVALID
- npy_set_floatstatus_invalid();
-#endif
- ret = NPY_HALF_NAN;
- } else if (h == 0x7bffu) {
-#if NPY_HALF_GENERATE_OVERFLOW
- npy_set_floatstatus_overflow();
-#endif
- ret = NPY_HALF_PINF;
- } else if ((h&0x8000u) && h_sig == 0) { /* Negative boundary case */
- if (h_exp > 0x2c00u) { /* If result is normalized */
- ret = h_exp - 0x2c00u;
- } else if(h_exp > 0x0400u) { /* The result is a subnormal, but not the smallest */
- ret = 1 << ((h_exp >> 10) - 2);
- } else {
- ret = 0x0001u; /* Smallest subnormal half */
- }
- } else if (h_exp > 0x2800u) { /* If result is still normalized */
- ret = h_exp - 0x2800u;
- } else if (h_exp > 0x0400u) { /* The result is a subnormal, but not the smallest */
- ret = 1 << ((h_exp >> 10) - 1);
- } else {
- ret = 0x0001u;
- }
-
- return ret;
-}
-
-npy_half npy_half_copysign(npy_half x, npy_half y)
-{
- return (x&0x7fffu) | (y&0x8000u);
-}
-
-npy_half npy_half_nextafter(npy_half x, npy_half y)
-{
- npy_half ret;
-
- if (npy_half_isnan(x) || npy_half_isnan(y)) {
- ret = NPY_HALF_NAN;
- } else if (npy_half_eq_nonan(x, y)) {
- ret = x;
- } else if (npy_half_iszero(x)) {
- ret = (y&0x8000u) + 1; /* Smallest subnormal half */
- } else if (!(x&0x8000u)) { /* x > 0 */
- if ((npy_int16)x > (npy_int16)y) { /* x > y */
- ret = x-1;
- } else {
- ret = x+1;
- }
- } else {
- if (!(y&0x8000u) || (x&0x7fffu) > (y&0x7fffu)) { /* x < y */
- ret = x-1;
- } else {
- ret = x+1;
- }
- }
-#if NPY_HALF_GENERATE_OVERFLOW
- if (npy_half_isinf(ret) && npy_half_isfinite(x)) {
- npy_set_floatstatus_overflow();
- }
-#endif
-
- return ret;
-}
-
-int npy_half_eq_nonan(npy_half h1, npy_half h2)
-{
- return (h1 == h2 || ((h1 | h2) & 0x7fff) == 0);
-}
-
-int npy_half_eq(npy_half h1, npy_half h2)
-{
- /*
- * The equality cases are as follows:
- * - If either value is NaN, never equal.
- * - If the values are equal, equal.
- * - If the values are both signed zeros, equal.
- */
- return (!npy_half_isnan(h1) && !npy_half_isnan(h2)) &&
- (h1 == h2 || ((h1 | h2) & 0x7fff) == 0);
-}
-
-int npy_half_ne(npy_half h1, npy_half h2)
-{
- return !npy_half_eq(h1, h2);
-}
-
-int npy_half_lt_nonan(npy_half h1, npy_half h2)
-{
- if (h1&0x8000u) {
- if (h2&0x8000u) {
- return (h1&0x7fffu) > (h2&0x7fffu);
- } else {
- /* Signed zeros are equal, have to check for it */
- return (h1 != 0x8000u) || (h2 != 0x0000u);
- }
- } else {
- if (h2&0x8000u) {
- return 0;
- } else {
- return (h1&0x7fffu) < (h2&0x7fffu);
- }
- }
-}
-
-int npy_half_lt(npy_half h1, npy_half h2)
-{
- return (!npy_half_isnan(h1) && !npy_half_isnan(h2)) && npy_half_lt_nonan(h1, h2);
-}
-
-int npy_half_gt(npy_half h1, npy_half h2)
-{
- return npy_half_lt(h2, h1);
-}
-
-int npy_half_le_nonan(npy_half h1, npy_half h2)
-{
- if (h1&0x8000u) {
- if (h2&0x8000u) {
- return (h1&0x7fffu) >= (h2&0x7fffu);
- } else {
- return 1;
- }
- } else {
- if (h2&0x8000u) {
- /* Signed zeros are equal, have to check for it */
- return (h1 == 0x0000u) && (h2 == 0x8000u);
- } else {
- return (h1&0x7fffu) <= (h2&0x7fffu);
- }
- }
-}
-
-int npy_half_le(npy_half h1, npy_half h2)
-{
- return (!npy_half_isnan(h1) && !npy_half_isnan(h2)) && npy_half_le_nonan(h1, h2);
-}
-
-int npy_half_ge(npy_half h1, npy_half h2)
-{
- return npy_half_le(h2, h1);
-}
-
-npy_half npy_half_divmod(npy_half h1, npy_half h2, npy_half *modulus)
-{
- float fh1 = npy_half_to_float(h1);
- float fh2 = npy_half_to_float(h2);
- float div, mod;
-
- div = npy_divmodf(fh1, fh2, &mod);
- *modulus = npy_float_to_half(mod);
- return npy_float_to_half(div);
-}
-
-
-
-/*
- ********************************************************************
- * BIT-LEVEL CONVERSIONS *
- ********************************************************************
- */
-
-npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f)
-{
- npy_uint32 f_exp, f_sig;
- npy_uint16 h_sgn, h_exp, h_sig;
-
- h_sgn = (npy_uint16) ((f&0x80000000u) >> 16);
- f_exp = (f&0x7f800000u);
-
- /* Exponent overflow/NaN converts to signed inf/NaN */
- if (f_exp >= 0x47800000u) {
- if (f_exp == 0x7f800000u) {
- /* Inf or NaN */
- f_sig = (f&0x007fffffu);
- if (f_sig != 0) {
- /* NaN - propagate the flag in the significand... */
- npy_uint16 ret = (npy_uint16) (0x7c00u + (f_sig >> 13));
- /* ...but make sure it stays a NaN */
- if (ret == 0x7c00u) {
- ret++;
- }
- return h_sgn + ret;
- } else {
- /* signed inf */
- return (npy_uint16) (h_sgn + 0x7c00u);
- }
- } else {
- /* overflow to signed inf */
-#if NPY_HALF_GENERATE_OVERFLOW
- npy_set_floatstatus_overflow();
-#endif
- return (npy_uint16) (h_sgn + 0x7c00u);
- }
- }
-
- /* Exponent underflow converts to a subnormal half or signed zero */
- if (f_exp <= 0x38000000u) {
- /*
- * Signed zeros, subnormal floats, and floats with small
- * exponents all convert to signed zero half-floats.
- */
- if (f_exp < 0x33000000u) {
-#if NPY_HALF_GENERATE_UNDERFLOW
- /* If f != 0, it underflowed to 0 */
- if ((f&0x7fffffff) != 0) {
- npy_set_floatstatus_underflow();
- }
-#endif
- return h_sgn;
- }
- /* Make the subnormal significand */
- f_exp >>= 23;
- f_sig = (0x00800000u + (f&0x007fffffu));
-#if NPY_HALF_GENERATE_UNDERFLOW
- /* If it's not exactly represented, it underflowed */
- if ((f_sig&(((npy_uint32)1 << (126 - f_exp)) - 1)) != 0) {
- npy_set_floatstatus_underflow();
- }
-#endif
- /*
- * Usually the significand is shifted by 13. For subnormals an
- * additional shift needs to occur. This shift is one for the largest
- * exponent giving a subnormal `f_exp = 0x38000000 >> 23 = 112`, which
- * offsets the new first bit. At most the shift can be 1+10 bits.
- */
- f_sig >>= (113 - f_exp);
- /* Handle rounding by adding 1 to the bit beyond half precision */
-#if NPY_HALF_ROUND_TIES_TO_EVEN
- /*
- * If the last bit in the half significand is 0 (already even), and
- * the remaining bit pattern is 1000...0, then we do not add one
- * to the bit after the half significand. However, the (113 - f_exp)
- * shift can lose up to 11 bits, so the || checks them in the original.
- * In all other cases, we can just add one.
- */
- if (((f_sig&0x00003fffu) != 0x00001000u) || (f&0x000007ffu)) {
- f_sig += 0x00001000u;
- }
-#else
- f_sig += 0x00001000u;
-#endif
- h_sig = (npy_uint16) (f_sig >> 13);
- /*
- * If the rounding causes a bit to spill into h_exp, it will
- * increment h_exp from zero to one and h_sig will be zero.
- * This is the correct result.
- */
- return (npy_uint16) (h_sgn + h_sig);
- }
-
- /* Regular case with no overflow or underflow */
- h_exp = (npy_uint16) ((f_exp - 0x38000000u) >> 13);
- /* Handle rounding by adding 1 to the bit beyond half precision */
- f_sig = (f&0x007fffffu);
-#if NPY_HALF_ROUND_TIES_TO_EVEN
- /*
- * If the last bit in the half significand is 0 (already even), and
- * the remaining bit pattern is 1000...0, then we do not add one
- * to the bit after the half significand. In all other cases, we do.
- */
- if ((f_sig&0x00003fffu) != 0x00001000u) {
- f_sig += 0x00001000u;
- }
-#else
- f_sig += 0x00001000u;
-#endif
- h_sig = (npy_uint16) (f_sig >> 13);
- /*
- * If the rounding causes a bit to spill into h_exp, it will
- * increment h_exp by one and h_sig will be zero. This is the
- * correct result. h_exp may increment to 15, at greatest, in
- * which case the result overflows to a signed inf.
- */
-#if NPY_HALF_GENERATE_OVERFLOW
- h_sig += h_exp;
- if (h_sig == 0x7c00u) {
- npy_set_floatstatus_overflow();
- }
- return h_sgn + h_sig;
-#else
- return h_sgn + h_exp + h_sig;
-#endif
-}
-
-npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d)
-{
- npy_uint64 d_exp, d_sig;
- npy_uint16 h_sgn, h_exp, h_sig;
-
- h_sgn = (d&0x8000000000000000ULL) >> 48;
- d_exp = (d&0x7ff0000000000000ULL);
-
- /* Exponent overflow/NaN converts to signed inf/NaN */
- if (d_exp >= 0x40f0000000000000ULL) {
- if (d_exp == 0x7ff0000000000000ULL) {
- /* Inf or NaN */
- d_sig = (d&0x000fffffffffffffULL);
- if (d_sig != 0) {
- /* NaN - propagate the flag in the significand... */
- npy_uint16 ret = (npy_uint16) (0x7c00u + (d_sig >> 42));
- /* ...but make sure it stays a NaN */
- if (ret == 0x7c00u) {
- ret++;
- }
- return h_sgn + ret;
- } else {
- /* signed inf */
- return h_sgn + 0x7c00u;
- }
- } else {
- /* overflow to signed inf */
-#if NPY_HALF_GENERATE_OVERFLOW
- npy_set_floatstatus_overflow();
-#endif
- return h_sgn + 0x7c00u;
- }
- }
-
- /* Exponent underflow converts to subnormal half or signed zero */
- if (d_exp <= 0x3f00000000000000ULL) {
- /*
- * Signed zeros, subnormal floats, and floats with small
- * exponents all convert to signed zero half-floats.
- */
- if (d_exp < 0x3e60000000000000ULL) {
-#if NPY_HALF_GENERATE_UNDERFLOW
- /* If d != 0, it underflowed to 0 */
- if ((d&0x7fffffffffffffffULL) != 0) {
- npy_set_floatstatus_underflow();
- }
-#endif
- return h_sgn;
- }
- /* Make the subnormal significand */
- d_exp >>= 52;
- d_sig = (0x0010000000000000ULL + (d&0x000fffffffffffffULL));
-#if NPY_HALF_GENERATE_UNDERFLOW
- /* If it's not exactly represented, it underflowed */
- if ((d_sig&(((npy_uint64)1 << (1051 - d_exp)) - 1)) != 0) {
- npy_set_floatstatus_underflow();
- }
-#endif
- /*
- * Unlike floats, doubles have enough room to shift left to align
- * the subnormal significand leading to no loss of the last bits.
- * The smallest possible exponent giving a subnormal is:
- * `d_exp = 0x3e60000000000000 >> 52 = 998`. All larger subnormals are
- * shifted with respect to it. This adds a shift of 10+1 bits the final
- * right shift when comparing it to the one in the normal branch.
- */
- assert(d_exp - 998 >= 0);
- d_sig <<= (d_exp - 998);
- /* Handle rounding by adding 1 to the bit beyond half precision */
-#if NPY_HALF_ROUND_TIES_TO_EVEN
- /*
- * If the last bit in the half significand is 0 (already even), and
- * the remaining bit pattern is 1000...0, then we do not add one
- * to the bit after the half significand. In all other cases, we do.
- */
- if ((d_sig&0x003fffffffffffffULL) != 0x0010000000000000ULL) {
- d_sig += 0x0010000000000000ULL;
- }
-#else
- d_sig += 0x0010000000000000ULL;
-#endif
- h_sig = (npy_uint16) (d_sig >> 53);
- /*
- * If the rounding causes a bit to spill into h_exp, it will
- * increment h_exp from zero to one and h_sig will be zero.
- * This is the correct result.
- */
- return h_sgn + h_sig;
- }
-
- /* Regular case with no overflow or underflow */
- h_exp = (npy_uint16) ((d_exp - 0x3f00000000000000ULL) >> 42);
- /* Handle rounding by adding 1 to the bit beyond half precision */
- d_sig = (d&0x000fffffffffffffULL);
-#if NPY_HALF_ROUND_TIES_TO_EVEN
- /*
- * If the last bit in the half significand is 0 (already even), and
- * the remaining bit pattern is 1000...0, then we do not add one
- * to the bit after the half significand. In all other cases, we do.
- */
- if ((d_sig&0x000007ffffffffffULL) != 0x0000020000000000ULL) {
- d_sig += 0x0000020000000000ULL;
- }
-#else
- d_sig += 0x0000020000000000ULL;
-#endif
- h_sig = (npy_uint16) (d_sig >> 42);
-
- /*
- * If the rounding causes a bit to spill into h_exp, it will
- * increment h_exp by one and h_sig will be zero. This is the
- * correct result. h_exp may increment to 15, at greatest, in
- * which case the result overflows to a signed inf.
- */
-#if NPY_HALF_GENERATE_OVERFLOW
- h_sig += h_exp;
- if (h_sig == 0x7c00u) {
- npy_set_floatstatus_overflow();
- }
- return h_sgn + h_sig;
-#else
- return h_sgn + h_exp + h_sig;
-#endif
-}
-
-npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h)
-{
- npy_uint16 h_exp, h_sig;
- npy_uint32 f_sgn, f_exp, f_sig;
-
- h_exp = (h&0x7c00u);
- f_sgn = ((npy_uint32)h&0x8000u) << 16;
- switch (h_exp) {
- case 0x0000u: /* 0 or subnormal */
- h_sig = (h&0x03ffu);
- /* Signed zero */
- if (h_sig == 0) {
- return f_sgn;
- }
- /* Subnormal */
- h_sig <<= 1;
- while ((h_sig&0x0400u) == 0) {
- h_sig <<= 1;
- h_exp++;
- }
- f_exp = ((npy_uint32)(127 - 15 - h_exp)) << 23;
- f_sig = ((npy_uint32)(h_sig&0x03ffu)) << 13;
- return f_sgn + f_exp + f_sig;
- case 0x7c00u: /* inf or NaN */
- /* All-ones exponent and a copy of the significand */
- return f_sgn + 0x7f800000u + (((npy_uint32)(h&0x03ffu)) << 13);
- default: /* normalized */
- /* Just need to adjust the exponent and shift */
- return f_sgn + (((npy_uint32)(h&0x7fffu) + 0x1c000u) << 13);
- }
-}
-
-npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h)
-{
- npy_uint16 h_exp, h_sig;
- npy_uint64 d_sgn, d_exp, d_sig;
-
- h_exp = (h&0x7c00u);
- d_sgn = ((npy_uint64)h&0x8000u) << 48;
- switch (h_exp) {
- case 0x0000u: /* 0 or subnormal */
- h_sig = (h&0x03ffu);
- /* Signed zero */
- if (h_sig == 0) {
- return d_sgn;
- }
- /* Subnormal */
- h_sig <<= 1;
- while ((h_sig&0x0400u) == 0) {
- h_sig <<= 1;
- h_exp++;
- }
- d_exp = ((npy_uint64)(1023 - 15 - h_exp)) << 52;
- d_sig = ((npy_uint64)(h_sig&0x03ffu)) << 42;
- return d_sgn + d_exp + d_sig;
- case 0x7c00u: /* inf or NaN */
- /* All-ones exponent and a copy of the significand */
- return d_sgn + 0x7ff0000000000000ULL +
- (((npy_uint64)(h&0x03ffu)) << 42);
- default: /* normalized */
- /* Just need to adjust the exponent and shift */
- return d_sgn + (((npy_uint64)(h&0x7fffu) + 0xfc000u) << 42);
- }
-}
diff --git a/numpy/core/src/npymath/halffloat.cpp b/numpy/core/src/npymath/halffloat.cpp
new file mode 100644
index 000000000..aa582c1b9
--- /dev/null
+++ b/numpy/core/src/npymath/halffloat.cpp
@@ -0,0 +1,238 @@
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+
+/*
+ * If these are 1, the conversions try to trigger underflow,
+ * overflow, and invalid exceptions in the FP system when needed.
+ */
+#define NPY_HALF_GENERATE_OVERFLOW 1
+#define NPY_HALF_GENERATE_INVALID 1
+
+#include "numpy/halffloat.h"
+
+#include "common.hpp"
+/*
+ ********************************************************************
+ * HALF-PRECISION ROUTINES *
+ ********************************************************************
+ */
+using namespace np;
+
+float npy_half_to_float(npy_half h)
+{
+ return static_cast<float>(Half::FromBits(h));
+}
+
+double npy_half_to_double(npy_half h)
+{
+ return static_cast<double>(Half::FromBits(h));
+}
+
+npy_half npy_float_to_half(float f)
+{
+ return Half(f).Bits();
+}
+
+npy_half npy_double_to_half(double d)
+{
+ return Half(d).Bits();
+}
+
+int npy_half_iszero(npy_half h)
+{
+ return (h&0x7fff) == 0;
+}
+
+int npy_half_isnan(npy_half h)
+{
+ return Half::FromBits(h).IsNaN();
+}
+
+int npy_half_isinf(npy_half h)
+{
+ return ((h&0x7fffu) == 0x7c00u);
+}
+
+int npy_half_isfinite(npy_half h)
+{
+ return ((h&0x7c00u) != 0x7c00u);
+}
+
+int npy_half_signbit(npy_half h)
+{
+ return (h&0x8000u) != 0;
+}
+
+npy_half npy_half_spacing(npy_half h)
+{
+ npy_half ret;
+ npy_uint16 h_exp = h&0x7c00u;
+ npy_uint16 h_sig = h&0x03ffu;
+ if (h_exp == 0x7c00u) {
+#if NPY_HALF_GENERATE_INVALID
+ npy_set_floatstatus_invalid();
+#endif
+ ret = NPY_HALF_NAN;
+ } else if (h == 0x7bffu) {
+#if NPY_HALF_GENERATE_OVERFLOW
+ npy_set_floatstatus_overflow();
+#endif
+ ret = NPY_HALF_PINF;
+ } else if ((h&0x8000u) && h_sig == 0) { /* Negative boundary case */
+ if (h_exp > 0x2c00u) { /* If result is normalized */
+ ret = h_exp - 0x2c00u;
+ } else if(h_exp > 0x0400u) { /* The result is a subnormal, but not the smallest */
+ ret = 1 << ((h_exp >> 10) - 2);
+ } else {
+ ret = 0x0001u; /* Smallest subnormal half */
+ }
+ } else if (h_exp > 0x2800u) { /* If result is still normalized */
+ ret = h_exp - 0x2800u;
+ } else if (h_exp > 0x0400u) { /* The result is a subnormal, but not the smallest */
+ ret = 1 << ((h_exp >> 10) - 1);
+ } else {
+ ret = 0x0001u;
+ }
+
+ return ret;
+}
+
+npy_half npy_half_copysign(npy_half x, npy_half y)
+{
+ return (x&0x7fffu) | (y&0x8000u);
+}
+
+npy_half npy_half_nextafter(npy_half x, npy_half y)
+{
+ npy_half ret;
+
+ if (npy_half_isnan(x) || npy_half_isnan(y)) {
+ ret = NPY_HALF_NAN;
+ } else if (npy_half_eq_nonan(x, y)) {
+ ret = x;
+ } else if (npy_half_iszero(x)) {
+ ret = (y&0x8000u) + 1; /* Smallest subnormal half */
+ } else if (!(x&0x8000u)) { /* x > 0 */
+ if ((npy_int16)x > (npy_int16)y) { /* x > y */
+ ret = x-1;
+ } else {
+ ret = x+1;
+ }
+ } else {
+ if (!(y&0x8000u) || (x&0x7fffu) > (y&0x7fffu)) { /* x < y */
+ ret = x-1;
+ } else {
+ ret = x+1;
+ }
+ }
+#if NPY_HALF_GENERATE_OVERFLOW
+ if (npy_half_isinf(ret) && npy_half_isfinite(x)) {
+ npy_set_floatstatus_overflow();
+ }
+#endif
+
+ return ret;
+}
+
+int npy_half_eq_nonan(npy_half h1, npy_half h2)
+{
+ return Half::FromBits(h1).Equal(Half::FromBits(h2));
+}
+
+int npy_half_eq(npy_half h1, npy_half h2)
+{
+ return Half::FromBits(h1) == Half::FromBits(h2);
+}
+
+int npy_half_ne(npy_half h1, npy_half h2)
+{
+ return Half::FromBits(h1) != Half::FromBits(h2);
+}
+
+int npy_half_lt_nonan(npy_half h1, npy_half h2)
+{
+ return Half::FromBits(h1).Less(Half::FromBits(h2));
+}
+
+int npy_half_lt(npy_half h1, npy_half h2)
+{
+ return Half::FromBits(h1) < Half::FromBits(h2);
+}
+
+int npy_half_gt(npy_half h1, npy_half h2)
+{
+ return npy_half_lt(h2, h1);
+}
+
+int npy_half_le_nonan(npy_half h1, npy_half h2)
+{
+ return Half::FromBits(h1).LessEqual(Half::FromBits(h2));
+}
+
+int npy_half_le(npy_half h1, npy_half h2)
+{
+ return Half::FromBits(h1) <= Half::FromBits(h2);
+}
+
+int npy_half_ge(npy_half h1, npy_half h2)
+{
+ return npy_half_le(h2, h1);
+}
+
+npy_half npy_half_divmod(npy_half h1, npy_half h2, npy_half *modulus)
+{
+ float fh1 = npy_half_to_float(h1);
+ float fh2 = npy_half_to_float(h2);
+ float div, mod;
+
+ div = npy_divmodf(fh1, fh2, &mod);
+ *modulus = npy_float_to_half(mod);
+ return npy_float_to_half(div);
+}
+
+
+/*
+ ********************************************************************
+ * BIT-LEVEL CONVERSIONS *
+ ********************************************************************
+ */
+
+npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f)
+{
+ if constexpr (Half::kNativeConversion<float>) {
+ return BitCast<uint16_t>(Half(BitCast<float>(f)));
+ }
+ else {
+ return half_private::FromFloatBits(f);
+ }
+}
+
+npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d)
+{
+ if constexpr (Half::kNativeConversion<double>) {
+ return BitCast<uint16_t>(Half(BitCast<double>(d)));
+ }
+ else {
+ return half_private::FromDoubleBits(d);
+ }
+}
+
+npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h)
+{
+ if constexpr (Half::kNativeConversion<float>) {
+ return BitCast<uint32_t>(static_cast<float>(Half::FromBits(h)));
+ }
+ else {
+ return half_private::ToFloatBits(h);
+ }
+}
+
+npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h)
+{
+ if constexpr (Half::kNativeConversion<double>) {
+ return BitCast<uint64_t>(static_cast<double>(Half::FromBits(h)));
+ }
+ else {
+ return half_private::ToDoubleBits(h);
+ }
+}
+
diff --git a/numpy/core/src/npymath/ieee754.c.src b/numpy/core/src/npymath/ieee754.c.src
index 5d8cb06a4..8fccc9a69 100644
--- a/numpy/core/src/npymath/ieee754.c.src
+++ b/numpy/core/src/npymath/ieee754.c.src
@@ -15,20 +15,6 @@
#define LDBL_TRUE_MIN __LDBL_DENORM_MIN__
#endif
-#if !defined(HAVE_DECL_SIGNBIT)
-#include "_signbit.c"
-
-int _npy_signbit_f(float x)
-{
- return _npy_signbit_d((double) x);
-}
-
-int _npy_signbit_ld(long double x)
-{
- return _npy_signbit_d((double) x);
-}
-#endif
-
/*
* FIXME: There is a lot of redundancy between _next* and npy_nextafter*.
* refactor this at some point
@@ -326,25 +312,6 @@ static npy_longdouble _nextl(npy_longdouble x, int p)
}
/**end repeat**/
-/*
- * Decorate all the math functions which are available on the current platform
- */
-
-float npy_nextafterf(float x, float y)
-{
- return nextafterf(x, y);
-}
-
-double npy_nextafter(double x, double y)
-{
- return nextafter(x, y);
-}
-
-npy_longdouble npy_nextafterl(npy_longdouble x, npy_longdouble y)
-{
- return nextafterl(x, y);
-}
-
int npy_clear_floatstatus() {
char x=0;
return npy_clear_floatstatus_barrier(&x);
diff --git a/numpy/core/src/npymath/ieee754.cpp b/numpy/core/src/npymath/ieee754.cpp
index ebc1dbeba..1c59bf300 100644
--- a/numpy/core/src/npymath/ieee754.cpp
+++ b/numpy/core/src/npymath/ieee754.cpp
@@ -17,21 +17,6 @@
#define LDBL_TRUE_MIN __LDBL_DENORM_MIN__
#endif
-#if !defined(HAVE_DECL_SIGNBIT)
-#include "_signbit.c"
-
-int
-_npy_signbit_f(float x)
-{
- return _npy_signbit_d((double)x);
-}
-
-int
-_npy_signbit_ld(long double x)
-{
- return _npy_signbit_d((double)x);
-}
-#endif
/*
* FIXME: There is a lot of redundancy between _next* and npy_nextafter*.
@@ -388,28 +373,6 @@ npy_spacingl(npy_longdouble x)
}
}
-/*
- * Decorate all the math functions which are available on the current platform
- */
-
-extern "C" float
-npy_nextafterf(float x, float y)
-{
- return nextafterf(x, y);
-}
-
-extern "C" double
-npy_nextafter(double x, double y)
-{
- return nextafter(x, y);
-}
-
-extern "C" npy_longdouble
-npy_nextafterl(npy_longdouble x, npy_longdouble y)
-{
- return nextafterl(x, y);
-}
-
extern "C" int
npy_clear_floatstatus()
{
diff --git a/numpy/core/src/npymath/npy_math_complex.c.src b/numpy/core/src/npymath/npy_math_complex.c.src
index 696495dab..eb9d810b7 100644
--- a/numpy/core/src/npymath/npy_math_complex.c.src
+++ b/numpy/core/src/npymath/npy_math_complex.c.src
@@ -72,7 +72,7 @@ static const @ctype@ c_1@c@ = {1.0@C@, 0.0};
* These are necessary because we do not count on using a
* C99 compiler.
*=========================================================*/
-static NPY_INLINE
+static inline
@ctype@
cmul@c@(@ctype@ a, @ctype@ b)
{
@@ -84,7 +84,7 @@ cmul@c@(@ctype@ a, @ctype@ b)
return npy_cpack@c@(ar*br - ai*bi, ar*bi + ai*br);
}
-static NPY_INLINE
+static inline
@ctype@
cdiv@c@(@ctype@ a, @ctype@ b)
{
@@ -443,29 +443,43 @@ npy_cpow@c@ (@ctype@ a, @ctype@ b)
@type@ bi = npy_cimag@c@(b);
@ctype@ r;
+ /*
+ * Checking if in a^b, if b is zero.
+ * If a is not zero then by definition of logarithm a^0 is 1.
+ * If a is also zero then 0^0 is best defined as 1.
+ */
if (br == 0. && bi == 0.) {
return npy_cpack@c@(1., 0.);
}
- if (ar == 0. && ai == 0.) {
- if (br > 0 && bi == 0) {
- return npy_cpack@c@(0., 0.);
- }
- else {
- volatile @type@ tmp = NPY_INFINITY@C@;
- /*
- * NB: there are four complex zeros; c0 = (+-0, +-0), so that
- * unlike for reals, c0**p, with `p` negative is in general
- * ill-defined.
- *
- * c0**z with z complex is also ill-defined.
- */
- r = npy_cpack@c@(NPY_NAN@C@, NPY_NAN@C@);
-
- /* Raise invalid */
- tmp -= NPY_INFINITY@C@;
- ar = tmp;
- return r;
- }
+ /* case 0^b
+ * If a is a complex zero (ai=ar=0), then the result depends
+ * upon values of br and bi. The result is either:
+ * 0 (in magnitude), undefined or 1.
+ * The later case is for br=bi=0 and independent of ar and ai
+ * but is handled above).
+ */
+ else if (ar == 0. && ai == 0.) {
+ /*
+ * If the real part of b is positive (br>0) then this is
+ * the zero complex with positive sign on both the
+ * real and imaginary part.
+ */
+ if (br > 0) {
+ return npy_cpack@c@(0., 0.);
+ }
+ /* else we are in the case where the
+ * real part of b is negative (br<0).
+ * Here we should return a complex nan
+ * and raise FloatingPointError: invalid value...
+ */
+
+ /* Raise invalid value by calling inf - inf*/
+ volatile @type@ tmp = NPY_INFINITY@C@;
+ tmp -= NPY_INFINITY@C@;
+ ar = tmp;
+
+ r = npy_cpack@c@(NPY_NAN@C@, NPY_NAN@C@);
+ return r;
}
if (bi == 0 && (n=(npy_intp)br) == br) {
if (n == 1) {
@@ -521,6 +535,443 @@ npy_cpow@c@ (@ctype@ a, @ctype@ b)
#endif
}
+
+#ifndef HAVE_CCOS@C@
+@ctype@
+npy_ccos@c@(@ctype@ z)
+{
+ /* ccos(z) = ccosh(I * z) */
+ return npy_ccosh@c@(npy_cpack@c@(-npy_cimag@c@(z), npy_creal@c@(z)));
+}
+#endif
+
+#ifndef HAVE_CSIN@C@
+@ctype@
+npy_csin@c@(@ctype@ z)
+{
+ /* csin(z) = -I * csinh(I * z) */
+ z = npy_csinh@c@(npy_cpack@c@(-npy_cimag@c@(z), npy_creal@c@(z)));
+ return npy_cpack@c@(npy_cimag@c@(z), -npy_creal@c@(z));
+}
+#endif
+
+#ifndef HAVE_CTAN@C@
+@ctype@
+npy_ctan@c@(@ctype@ z)
+{
+ /* ctan(z) = -I * ctanh(I * z) */
+ z = npy_ctanh@c@(npy_cpack@c@(-npy_cimag@c@(z), npy_creal@c@(z)));
+ return (npy_cpack@c@(npy_cimag@c@(z), -npy_creal@c@(z)));
+}
+#endif
+
+#ifndef HAVE_CCOSH@C@
+/*
+ * Taken from the msun library in FreeBSD, rev 226599.
+ *
+ * Hyperbolic cosine of a complex argument z = x + i y.
+ *
+ * cosh(z) = cosh(x+iy)
+ * = cosh(x) cos(y) + i sinh(x) sin(y).
+ *
+ * Exceptional values are noted in the comments within the source code.
+ * These values and the return value were taken from n1124.pdf.
+ *
+ * CCOSH_BIG is chosen such that
+ * spacing(0.5 * exp(CCOSH_BIG)) > 0.5*exp(-CCOSH_BIG)
+ * although the exact value assigned to CCOSH_BIG is not so important
+ */
+@ctype@
+npy_ccosh@c@(@ctype@ z)
+{
+#if @precision@ == 1
+ const npy_float CCOSH_BIG = 9.0f;
+ const npy_float CCOSH_HUGE = 1.70141183e+38f;
+#endif
+#if @precision@ == 2
+ const npy_double CCOSH_BIG = 22.0;
+ const npy_double CCOSH_HUGE = 8.9884656743115795e+307;
+#endif
+#if @precision@ >= 3
+#if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE
+ const npy_longdouble CCOSH_BIG = 22.0L;
+ const npy_longdouble CCOSH_HUGE = 8.9884656743115795e+307L;
+#else
+ const npy_longdouble CCOSH_BIG = 24.0L;
+ const npy_longdouble CCOSH_HUGE = 5.94865747678615882543e+4931L;
+#endif
+#endif
+
+ @type@ x, y, h, absx;
+ npy_int xfinite, yfinite;
+
+ x = npy_creal@c@(z);
+ y = npy_cimag@c@(z);
+
+ xfinite = npy_isfinite(x);
+ yfinite = npy_isfinite(y);
+
+ /* Handle the nearly-non-exceptional cases where x and y are finite. */
+ if (xfinite && yfinite) {
+ if (y == 0) {
+ return npy_cpack@c@(npy_cosh@c@(x), x * y);
+ }
+ absx = npy_fabs@c@(x);
+ if (absx < CCOSH_BIG) {
+ /* small x: normal case */
+ return npy_cpack@c@(npy_cosh@c@(x) * npy_cos@c@(y),
+ npy_sinh@c@(x) * npy_sin@c@(y));
+ }
+
+ /* |x| >= 22, so cosh(x) ~= exp(|x|) */
+ if (absx < SCALED_CEXP_LOWER@C@) {
+ /* x < 710: exp(|x|) won't overflow */
+ h = npy_exp@c@(absx) * 0.5@c@;
+ return npy_cpack@c@(h * npy_cos@c@(y),
+ npy_copysign@c@(h, x) * npy_sin@c@(y));
+ }
+ else if (absx < SCALED_CEXP_UPPER@C@) {
+ /* x < 1455: scale to avoid overflow */
+ z = _npy_scaled_cexp@c@(absx, y, -1);
+ return npy_cpack@c@(npy_creal@c@(z),
+ npy_cimag@c@(z) * npy_copysign@c@(1, x));
+ }
+ else {
+ /* x >= 1455: the result always overflows */
+ h = CCOSH_HUGE * x;
+ return npy_cpack@c@(h * h * npy_cos@c@(y), h * npy_sin@c@(y));
+ }
+ }
+
+ /*
+ * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0.
+ * The sign of 0 in the result is unspecified. Choice = normally
+ * the same as dNaN. Raise the invalid floating-point exception.
+ *
+ * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0.
+ * The sign of 0 in the result is unspecified. Choice = normally
+ * the same as d(NaN).
+ */
+ if (x == 0 && !yfinite) {
+ return npy_cpack@c@(y - y, npy_copysign@c@(0, x * (y - y)));
+ }
+
+ /*
+ * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0.
+ *
+ * cosh(NaN +- I 0) = d(NaN) + I sign(d(NaN, +-0))0.
+ * The sign of 0 in the result is unspecified.
+ */
+ if (y == 0 && !xfinite) {
+ return npy_cpack@c@(x * x, npy_copysign@c@(0, x) * y);
+ }
+
+ /*
+ * cosh(x +- I Inf) = dNaN + I dNaN.
+ * Raise the invalid floating-point exception for finite nonzero x.
+ *
+ * cosh(x + I NaN) = d(NaN) + I d(NaN).
+ * Optionally raises the invalid floating-point exception for finite
+ * nonzero x. Choice = don't raise (except for signaling NaNs).
+ */
+ if (xfinite && !yfinite) {
+ return npy_cpack@c@(y - y, x * (y - y));
+ }
+
+ /*
+ * cosh(+-Inf + I NaN) = +Inf + I d(NaN).
+ *
+ * cosh(+-Inf +- I Inf) = +Inf + I dNaN.
+ * The sign of Inf in the result is unspecified. Choice = always +.
+ * Raise the invalid floating-point exception.
+ *
+ * cosh(+-Inf + I y) = +Inf cos(y) +- I Inf sin(y)
+ */
+ if (npy_isinf(x)) {
+ if (!yfinite) {
+ return npy_cpack@c@(x * x, x * (y - y));
+ }
+ return npy_cpack@c@((x * x) * npy_cos@c@(y), x * npy_sin@c@(y));
+ }
+
+ /*
+ * cosh(NaN + I NaN) = d(NaN) + I d(NaN).
+ *
+ * cosh(NaN +- I Inf) = d(NaN) + I d(NaN).
+ * Optionally raises the invalid floating-point exception.
+ * Choice = raise.
+ *
+ * cosh(NaN + I y) = d(NaN) + I d(NaN).
+ * Optionally raises the invalid floating-point exception for finite
+ * nonzero y. Choice = don't raise (except for signaling NaNs).
+ */
+ return npy_cpack@c@((x * x) * (y - y), (x + x) * (y - y));
+}
+#undef CCOSH_BIG
+#undef CCOSH_HUGE
+#endif
+
+#ifndef HAVE_CSINH@C@
+/*
+ * Taken from the msun library in FreeBSD, rev 226599.
+ *
+ * Hyperbolic sine of a complex argument z = x + i y.
+ *
+ * sinh(z) = sinh(x+iy)
+ * = sinh(x) cos(y) + i cosh(x) sin(y).
+ *
+ * Exceptional values are noted in the comments within the source code.
+ * These values and the return value were taken from n1124.pdf.
+ */
+@ctype@
+npy_csinh@c@(@ctype@ z)
+{
+#if @precision@ == 1
+ const npy_float CSINH_BIG = 9.0f;
+ const npy_float CSINH_HUGE = 1.70141183e+38f;
+#endif
+#if @precision@ == 2
+ const npy_double CSINH_BIG = 22.0;
+ const npy_double CSINH_HUGE = 8.9884656743115795e+307;
+#endif
+#if @precision@ >= 3
+#if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE
+ const npy_longdouble CSINH_BIG = 22.0L;
+ const npy_longdouble CSINH_HUGE = 8.9884656743115795e+307L;
+#else
+ const npy_longdouble CSINH_BIG = 24.0L;
+ const npy_longdouble CSINH_HUGE = 5.94865747678615882543e+4931L;
+#endif
+#endif
+
+ @type@ x, y, h, absx;
+ npy_int xfinite, yfinite;
+
+ x = npy_creal@c@(z);
+ y = npy_cimag@c@(z);
+
+ xfinite = npy_isfinite(x);
+ yfinite = npy_isfinite(y);
+
+ /* Handle the nearly-non-exceptional cases where x and y are finite. */
+ if (xfinite && yfinite) {
+ if (y == 0) {
+ return npy_cpack@c@(npy_sinh@c@(x), y);
+ }
+ absx = npy_fabs@c@(x);
+ if (absx < CSINH_BIG) {
+ /* small x: normal case */
+ return npy_cpack@c@(npy_sinh@c@(x) * npy_cos@c@(y),
+ npy_cosh@c@(x) * npy_sin@c@(y));
+ }
+
+ /* |x| >= 22, so cosh(x) ~= exp(|x|) */
+ if (absx < SCALED_CEXP_LOWER@C@) {
+ /* x < 710: exp(|x|) won't overflow */
+ h = npy_exp@c@(npy_fabs@c@(x)) * 0.5@c@;
+ return npy_cpack@c@(npy_copysign@c@(h, x) * npy_cos@c@(y),
+ h * npy_sin@c@(y));
+ }
+ else if (x < SCALED_CEXP_UPPER@C@) {
+ /* x < 1455: scale to avoid overflow */
+ z = _npy_scaled_cexp@c@(absx, y, -1);
+ return npy_cpack@c@(npy_creal@c@(z) * npy_copysign@c@(1, x),
+ npy_cimag@c@(z));
+ }
+ else {
+ /* x >= 1455: the result always overflows */
+ h = CSINH_HUGE * x;
+ return npy_cpack@c@(h * npy_cos@c@(y), h * h * npy_sin@c@(y));
+ }
+ }
+
+ /*
+ * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN.
+ * The sign of 0 in the result is unspecified. Choice = normally
+ * the same as dNaN. Raise the invalid floating-point exception.
+ *
+ * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN).
+ * The sign of 0 in the result is unspecified. Choice = normally
+ * the same as d(NaN).
+ */
+ if (x == 0 && !yfinite) {
+ return npy_cpack@c@(npy_copysign@c@(0, x * (y - y)), y - y);
+ }
+
+ /*
+ * sinh(+-Inf +- I 0) = +-Inf + I +-0.
+ *
+ * sinh(NaN +- I 0) = d(NaN) + I +-0.
+ */
+ if (y == 0 && !xfinite) {
+ if (npy_isnan(x)) {
+ return z;
+ }
+ return npy_cpack@c@(x, npy_copysign@c@(0, y));
+ }
+
+ /*
+ * sinh(x +- I Inf) = dNaN + I dNaN.
+ * Raise the invalid floating-point exception for finite nonzero x.
+ *
+ * sinh(x + I NaN) = d(NaN) + I d(NaN).
+ * Optionally raises the invalid floating-point exception for finite
+ * nonzero x. Choice = don't raise (except for signaling NaNs).
+ */
+ if (xfinite && !yfinite) {
+ return npy_cpack@c@(y - y, x * (y - y));
+ }
+
+ /*
+ * sinh(+-Inf + I NaN) = +-Inf + I d(NaN).
+ * The sign of Inf in the result is unspecified. Choice = normally
+ * the same as d(NaN).
+ *
+ * sinh(+-Inf +- I Inf) = +Inf + I dNaN.
+ * The sign of Inf in the result is unspecified. Choice = always +.
+ * Raise the invalid floating-point exception.
+ *
+ * sinh(+-Inf + I y) = +-Inf cos(y) + I Inf sin(y)
+ */
+ if (!xfinite && !npy_isnan(x)) {
+ if (!yfinite) {
+ return npy_cpack@c@(x * x, x * (y - y));
+ }
+ return npy_cpack@c@(x * npy_cos@c@(y),
+ NPY_INFINITY@C@ * npy_sin@c@(y));
+ }
+
+ /*
+ * sinh(NaN + I NaN) = d(NaN) + I d(NaN).
+ *
+ * sinh(NaN +- I Inf) = d(NaN) + I d(NaN).
+ * Optionally raises the invalid floating-point exception.
+ * Choice = raise.
+ *
+ * sinh(NaN + I y) = d(NaN) + I d(NaN).
+ * Optionally raises the invalid floating-point exception for finite
+ * nonzero y. Choice = don't raise (except for signaling NaNs).
+ */
+ return npy_cpack@c@((x * x) * (y - y), (x + x) * (y - y));
+}
+#undef CSINH_BIG
+#undef CSINH_HUGE
+#endif
+
+#ifndef HAVE_CTANH@C@
+/*
+ * Taken from the msun library in FreeBSD, rev 226600.
+ *
+ * Hyperbolic tangent of a complex argument z = x + i y.
+ *
+ * The algorithm is from:
+ *
+ * W. Kahan. Branch Cuts for Complex Elementary Functions or Much
+ * Ado About Nothing's Sign Bit. In The State of the Art in
+ * Numerical Analysis, pp. 165 ff. Iserles and Powell, eds., 1987.
+ *
+ * Method:
+ *
+ * Let t = tan(x)
+ * beta = 1/cos^2(y)
+ * s = sinh(x)
+ * rho = cosh(x)
+ *
+ * We have:
+ *
+ * tanh(z) = sinh(z) / cosh(z)
+ *
+ * sinh(x) cos(y) + i cosh(x) sin(y)
+ * = ---------------------------------
+ * cosh(x) cos(y) + i sinh(x) sin(y)
+ *
+ * cosh(x) sinh(x) / cos^2(y) + i tan(y)
+ * = -------------------------------------
+ * 1 + sinh^2(x) / cos^2(y)
+ *
+ * beta rho s + i t
+ * = ----------------
+ * 1 + beta s^2
+ *
+ * Modifications:
+ *
+ * I omitted the original algorithm's handling of overflow in tan(x) after
+ * verifying with nearpi.c that this can't happen in IEEE single or double
+ * precision. I also handle large x differently.
+ */
+
+#define TANH_HUGE 22.0
+#define TANHF_HUGE 11.0F
+#define TANHL_HUGE 42.0L
+
+@ctype@
+npy_ctanh@c@(@ctype@ z)
+{
+ @type@ x, y;
+ @type@ t, beta, s, rho, denom;
+
+ x = npy_creal@c@(z);
+ y = npy_cimag@c@(z);
+
+ /*
+ * ctanh(NaN + i 0) = NaN + i 0
+ *
+ * ctanh(NaN + i y) = NaN + i NaN for y != 0
+ *
+ * The imaginary part has the sign of x*sin(2*y), but there's no
+ * special effort to get this right.
+ *
+ * ctanh(+-Inf +- i Inf) = +-1 +- 0
+ *
+ * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite
+ *
+ * The imaginary part of the sign is unspecified. This special
+ * case is only needed to avoid a spurious invalid exception when
+ * y is infinite.
+ */
+ if (!npy_isfinite(x)) {
+ if (npy_isnan(x)) {
+ return npy_cpack@c@(x, (y == 0 ? y : x * y));
+ }
+ return npy_cpack@c@(npy_copysign@c@(1,x),
+ npy_copysign@c@(0,
+ npy_isinf(y) ?
+ y : npy_sin@c@(y) * npy_cos@c@(y)));
+ }
+
+ /*
+ * ctanh(x + i NAN) = NaN + i NaN
+ * ctanh(x +- i Inf) = NaN + i NaN
+ */
+ if (!npy_isfinite(y)) {
+ return (npy_cpack@c@(y - y, y - y));
+ }
+
+ /*
+ * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the
+ * approximation sinh^2(huge) ~= exp(2*huge) / 4.
+ * We use a modified formula to avoid spurious overflow.
+ */
+ if (npy_fabs@c@(x) >= TANH@C@_HUGE) {
+ @type@ exp_mx = npy_exp@c@(-npy_fabs@c@(x));
+ return npy_cpack@c@(npy_copysign@c@(1, x),
+ 4 * npy_sin@c@(y) * npy_cos@c@(y) *
+ exp_mx * exp_mx);
+ }
+
+ /* Kahan's algorithm */
+ t = npy_tan@c@(y);
+ beta = 1 + t * t; /* = 1 / cos^2(y) */
+ s = npy_sinh@c@(x);
+ rho = npy_sqrt@c@(1 + s * s); /* = cosh(x) */
+ denom = 1 + beta * s * s;
+ return (npy_cpack@c@((beta * rho * s) / denom, t / denom));
+}
+#undef TANH_HUGE
+#undef TANHF_HUGE
+#undef TANHL_HUGE
+#endif
+
#if !defined (HAVE_CACOS@C@) || !defined (HAVE_CASINH@C@)
/*
* Complex inverse trig functions taken from the msum library in FreeBSD
@@ -573,7 +1024,7 @@ npy_cpow@c@ (@ctype@ a, @ctype@ b)
* Function f(a, b, hypot_a_b) = (hypot(a, b) - b) / 2.
* Pass hypot(a, b) as the third argument.
*/
-static NPY_INLINE @type@
+static inline @type@
_f@c@(@type@ a, @type@ b, @type@ hypot_a_b)
{
if (b < 0) {
@@ -595,7 +1046,7 @@ _f@c@(@type@ a, @type@ b, @type@ hypot_a_b)
* If returning sqrt_A2my2 has potential to result in an underflow, it is
* rescaled, and new_y is similarly rescaled.
*/
-static NPY_INLINE void
+static inline void
_do_hard_work@c@(@type@ x, @type@ y, @type@ *rx,
npy_int *B_is_usable, @type@ *B, @type@ *sqrt_A2my2, @type@ *new_y)
{
@@ -739,7 +1190,7 @@ _do_hard_work@c@(@type@ x, @type@ y, @type@ *rx,
/*
* Optimized version of clog() for |z| finite and larger than ~RECIP_EPSILON.
*/
-static NPY_INLINE void
+static inline void
_clog_for_large_values@c@(@type@ x, @type@ y,
@type@ *rr, @type@ *ri)
{
@@ -1040,7 +1491,7 @@ npy_casinh@c@(@ctype@ z)
* Assumes y is non-negative.
* Assumes fabs(x) >= DBL_EPSILON.
*/
-static NPY_INLINE @type@
+static inline @type@
_sum_squares@c@(@type@ x, @type@ y)
{
#if @precision@ == 1
@@ -1077,7 +1528,7 @@ const npy_longdouble SQRT_MIN = 1.8336038675548471656e-2466l;
#if @precision@ == 1
#define BIAS (FLT_MAX_EXP - 1)
#define CUTOFF (FLT_MANT_DIG / 2 + 1)
-static NPY_INLINE npy_float
+static inline npy_float
_real_part_reciprocalf(npy_float x, npy_float y)
{
npy_float scale;
@@ -1110,7 +1561,7 @@ _real_part_reciprocalf(npy_float x, npy_float y)
#define BIAS (DBL_MAX_EXP - 1)
/* more guard digits are useful iff there is extra precision. */
#define CUTOFF (DBL_MANT_DIG / 2 + 1) /* just half or 1 guard digit */
-static NPY_INLINE npy_double
+static inline npy_double
_real_part_reciprocal(npy_double x, npy_double y)
{
npy_double scale;
@@ -1152,7 +1603,7 @@ _real_part_reciprocal(npy_double x, npy_double y)
#define BIAS (LDBL_MAX_EXP - 1)
#define CUTOFF (LDBL_MANT_DIG / 2 + 1)
-static NPY_INLINE npy_longdouble
+static inline npy_longdouble
_real_part_reciprocall(npy_longdouble x,
npy_longdouble y)
{
@@ -1185,7 +1636,7 @@ _real_part_reciprocall(npy_longdouble x,
#else
-static NPY_INLINE npy_longdouble
+static inline npy_longdouble
_real_part_reciprocall(npy_longdouble x,
npy_longdouble y)
{
@@ -1313,8 +1764,10 @@ npy_@kind@@c@(@ctype@ z)
/**end repeat1**/
/**begin repeat1
- * #kind = cexp,clog,csqrt,cacos,casin,catan,cacosh,casinh,catanh#
- * #KIND = CEXP,CLOG,CSQRT,CACOS,CASIN,CATAN,CACOSH,CASINH,CATANH#
+ * #kind = cexp,clog,csqrt,ccos,csin,ctan,ccosh,csinh,ctanh,
+ * cacos,casin,catan,cacosh,casinh,catanh#
+ * #KIND = CEXP,CLOG,CSQRT,CCOS,CSIN,CTAN,CCOSH,CSINH,CTANH,
+ * CACOS,CASIN,CATAN,CACOSH,CASINH,CATANH#
*/
#ifdef HAVE_@KIND@@C@
@ctype@
@@ -1329,20 +1782,5 @@ npy_@kind@@c@(@ctype@ z)
#endif
/**end repeat1**/
-/* Mandatory complex functions */
-
-/**begin repeat1
- * #kind = csin,csinh,ccos,ccosh,ctan,ctanh#
- */
-@ctype@
-npy_@kind@@c@(@ctype@ z)
-{
- __@ctype@_to_c99_cast z1;
- __@ctype@_to_c99_cast ret;
- z1.npy_z = z;
- ret.c99_z = @kind@@c@(z1.c99_z);
- return ret.npy_z;
-}
-/**end repeat1**/
/**end repeat**/
diff --git a/numpy/core/src/npymath/npy_math_internal.h.src b/numpy/core/src/npymath/npy_math_internal.h.src
index 6e84a905e..c7df5e255 100644
--- a/numpy/core/src/npymath/npy_math_internal.h.src
+++ b/numpy/core/src/npymath/npy_math_internal.h.src
@@ -567,7 +567,7 @@ npy_divmod@c@(@type@ a, @type@ b, @type@ *modulus)
/* adjust fmod result to conform to Python convention of remainder */
if (mod) {
- if (isless(b, 0) != isless(mod, 0)) {
+ if (isless(b, (@type@)0) != isless(mod, (@type@)0)) {
mod += b;
div -= 1.0@c@;
}
diff --git a/numpy/core/src/npymath/npy_math_private.h b/numpy/core/src/npymath/npy_math_private.h
index a474b3de3..20c94f98a 100644
--- a/numpy/core/src/npymath/npy_math_private.h
+++ b/numpy/core/src/npymath/npy_math_private.h
@@ -21,6 +21,7 @@
#include <Python.h>
#ifdef __cplusplus
#include <cmath>
+#include <complex>
using std::isgreater;
using std::isless;
#else
@@ -494,8 +495,9 @@ do { \
* Microsoft C defines _MSC_VER
* Intel compiler does not use MSVC complex types, but defines _MSC_VER by
* default.
+ * since c++17 msvc is no longer support them.
*/
-#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#if !defined(__cplusplus) && defined(_MSC_VER) && !defined(__INTEL_COMPILER)
typedef union {
npy_cdouble npy_z;
_Dcomplex c99_z;