diff options
Diffstat (limited to 'Eigen/src/Core/MathFunctionsImpl.h')
-rw-r--r-- | Eigen/src/Core/MathFunctionsImpl.h | 60 |
1 files changed, 51 insertions, 9 deletions
diff --git a/Eigen/src/Core/MathFunctionsImpl.h b/Eigen/src/Core/MathFunctionsImpl.h index 9222285b4..0d3f317bb 100644 --- a/Eigen/src/Core/MathFunctionsImpl.h +++ b/Eigen/src/Core/MathFunctionsImpl.h @@ -79,6 +79,12 @@ template<typename RealScalar> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE RealScalar positive_real_hypot(const RealScalar& x, const RealScalar& y) { + // IEEE IEC 6059 special cases. + if ((numext::isinf)(x) || (numext::isinf)(y)) + return NumTraits<RealScalar>::infinity(); + if ((numext::isnan)(x) || (numext::isnan)(y)) + return NumTraits<RealScalar>::quiet_NaN(); + EIGEN_USING_STD(sqrt); RealScalar p, qp; p = numext::maxi(x,y); @@ -128,20 +134,56 @@ EIGEN_DEVICE_FUNC std::complex<T> complex_sqrt(const std::complex<T>& z) { const T x = numext::real(z); const T y = numext::imag(z); const T zero = T(0); - const T cst_half = T(0.5); + const T w = numext::sqrt(T(0.5) * (numext::abs(x) + numext::hypot(x, y))); - // Special case of isinf(y) - if ((numext::isinf)(y)) { - return std::complex<T>(std::numeric_limits<T>::infinity(), y); - } - - T w = numext::sqrt(cst_half * (numext::abs(x) + numext::abs(z))); return - x == zero ? std::complex<T>(w, y < zero ? -w : w) - : x > zero ? std::complex<T>(w, y / (2 * w)) + (numext::isinf)(y) ? std::complex<T>(NumTraits<T>::infinity(), y) + : x == zero ? std::complex<T>(w, y < zero ? -w : w) + : x > zero ? std::complex<T>(w, y / (2 * w)) : std::complex<T>(numext::abs(y) / (2 * w), y < zero ? -w : w ); } +// Generic complex rsqrt implementation. +template<typename T> +EIGEN_DEVICE_FUNC std::complex<T> complex_rsqrt(const std::complex<T>& z) { + // Computes the principal reciprocal sqrt of the input. + // + // For a complex reciprocal square root of the number z = x + i*y. We want to + // find real numbers u and v such that + // (u + i*v)^2 = 1 / (x + i*y) <=> + // u^2 - v^2 + i*2*u*v = x/|z|^2 - i*v/|z|^2. + // By equating the real and imaginary parts we get: + // u^2 - v^2 = x/|z|^2 + // 2*u*v = y/|z|^2. + // + // For x >= 0, this has the numerically stable solution + // u = sqrt(0.5 * (x + |z|)) / |z| + // v = -y / (2 * u * |z|) + // and for x < 0, + // v = -sign(y) * sqrt(0.5 * (-x + |z|)) / |z| + // u = -y / (2 * v * |z|) + // + // Letting w = sqrt(0.5 * (|x| + |z|)), + // if x == 0: u = w / |z|, v = -sign(y) * w / |z| + // if x > 0: u = w / |z|, v = -y / (2 * w * |z|) + // if x < 0: u = |y| / (2 * w * |z|), v = -sign(y) * w / |z| + + const T x = numext::real(z); + const T y = numext::imag(z); + const T zero = T(0); + + const T abs_z = numext::hypot(x, y); + const T w = numext::sqrt(T(0.5) * (numext::abs(x) + abs_z)); + const T woz = w / abs_z; + // Corner cases consistent with 1/sqrt(z) on gcc/clang. + return + abs_z == zero ? std::complex<T>(NumTraits<T>::infinity(), NumTraits<T>::quiet_NaN()) + : ((numext::isinf)(x) || (numext::isinf)(y)) ? std::complex<T>(zero, zero) + : x == zero ? std::complex<T>(woz, y < zero ? woz : -woz) + : x > zero ? std::complex<T>(woz, -y / (2 * w * abs_z)) + : std::complex<T>(numext::abs(y) / (2 * w * abs_z), y < zero ? woz : -woz ); +} + } // end namespace internal } // end namespace Eigen |