diff --git a/Eigen/src/Core/GenericPacketMath.h b/Eigen/src/Core/GenericPacketMath.h index 1d79b4ab8..c7a9846d0 100644 --- a/Eigen/src/Core/GenericPacketMath.h +++ b/Eigen/src/Core/GenericPacketMath.h @@ -1083,8 +1083,13 @@ EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet patanh(const Packet& /** \internal \returns the exp of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp(const Packet& a) { - EIGEN_USING_STD(exp); - return exp(a); + return numext::exp(a); +} + +/** \internal \returns the exp2 of \a a (coeff-wise) */ +template +EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp2(const Packet& a) { + return numext::exp2(a); } /** \internal \returns the expm1 of \a a (coeff-wise) */ @@ -1113,7 +1118,7 @@ EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog10(const Packet& return log10(a); } -/** \internal \returns the log10 of \a a (coeff-wise) */ +/** \internal \returns the log2 of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog2(const Packet& a) { using Scalar = typename internal::unpacket_traits::type; diff --git a/Eigen/src/Core/GlobalFunctions.h b/Eigen/src/Core/GlobalFunctions.h index 3f147b8f6..df1098e27 100644 --- a/Eigen/src/Core/GlobalFunctions.h +++ b/Eigen/src/Core/GlobalFunctions.h @@ -76,6 +76,7 @@ EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erf, scalar_erf_op, error function,\sa ArrayBas EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erfc, scalar_erfc_op, complement error function,\sa ArrayBase::erfc) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(ndtri, scalar_ndtri_op, inverse normal distribution function,\sa ArrayBase::ndtri) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp, scalar_exp_op, exponential,\sa ArrayBase::exp) +EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp2, scalar_exp2_op, exponential,\sa ArrayBase::exp2) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(expm1, scalar_expm1_op, exponential of a value minus 1,\sa ArrayBase::expm1) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log, scalar_log_op, natural logarithm,\sa Eigen::log10 DOXCOMMA ArrayBase::log) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log1p, scalar_log1p_op, natural logarithm of 1 plus the value,\sa ArrayBase::log1p) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index feb9099b4..57fb3bde3 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -1477,6 +1477,63 @@ EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE std::complex exp(const std::comple } #endif +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T exp2(const T& x) { + EIGEN_USING_STD(exp2); + return exp2(x); +} + +// MSVC screws up some edge-cases for std::exp2(complex). +#ifdef EIGEN_COMP_MSVC +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE std::complex exp2(const std::complex& x) { + EIGEN_USING_STD(exp); + // If z is (x,±∞) (for any finite x), the result is (NaN,NaN) and FE_INVALID is raised. + // If z is (x,NaN) (for any finite x), the result is (NaN,NaN) and FE_INVALID may be raised. + if ((isfinite)(real_ref(x)) && !(isfinite)(imag_ref(x))) { + return std::complex(NumTraits::quiet_NaN(), NumTraits::quiet_NaN()); + } + // If z is (+∞,±∞), the result is (±∞,NaN) and FE_INVALID is raised (the sign of the real part is unspecified) + // If z is (+∞,NaN), the result is (±∞,NaN) (the sign of the real part is unspecified) + if ((real_ref(x) == NumTraits::infinity() && !(isfinite)(imag_ref(x)))) { + return std::complex(NumTraits::infinity(), NumTraits::quiet_NaN()); + } + return exp2(x); +} +#endif + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(exp2, exp2) +#endif + +#if defined(EIGEN_GPUCC) +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float exp2(const float& x) { + return ::exp2f(x); +} + +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double exp2(const double& x) { + return ::exp2(x); +} + +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE std::complex exp2(const std::complex& x) { + float com = ::exp2f(x.real()); + float res_real = com * ::cosf(static_cast(EIGEN_LN2) * x.imag()); + float res_imag = com * ::sinf(static_cast(EIGEN_LN2) * x.imag()); + return std::complex(res_real, res_imag); +} + +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE std::complex exp2(const std::complex& x) { + double com = ::exp2(x.real()); + double res_real = com * ::cos(static_cast(EIGEN_LN2) * x.imag()); + double res_imag = com * ::sin(static_cast(EIGEN_LN2) * x.imag()); + return std::complex(res_real, res_imag); +} +#endif + template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(expm1, Scalar) expm1(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(expm1, Scalar)::run(x); diff --git a/Eigen/src/Core/arch/AVX/MathFunctions.h b/Eigen/src/Core/arch/AVX/MathFunctions.h index 7b43fbb5e..a5c38e787 100644 --- a/Eigen/src/Core/arch/AVX/MathFunctions.h +++ b/Eigen/src/Core/arch/AVX/MathFunctions.h @@ -32,11 +32,8 @@ EIGEN_DOUBLE_PACKET_FUNCTION(tanh, Packet4d) EIGEN_DOUBLE_PACKET_FUNCTION(sin, Packet4d) EIGEN_DOUBLE_PACKET_FUNCTION(cos, Packet4d) #endif - -template <> -EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC EIGEN_UNUSED Packet4d patan(const Packet4d& _x) { - return generic_patan(_x); -} +EIGEN_GENERIC_PACKET_FUNCTION(atan, Packet4d) +EIGEN_GENERIC_PACKET_FUNCTION(exp2, Packet4d) // Notice that for newer processors, it is counterproductive to use Newton // iteration for square root. In particular, Skylake and Zen2 processors @@ -99,6 +96,7 @@ EIGEN_STRONG_INLINE Packet8bf pldexp(const Packet8bf& a, const Packet8bf& expone BF16_PACKET_FUNCTION(Packet8f, Packet8bf, pcos) BF16_PACKET_FUNCTION(Packet8f, Packet8bf, pexp) +BF16_PACKET_FUNCTION(Packet8f, Packet8bf, pexp2) BF16_PACKET_FUNCTION(Packet8f, Packet8bf, pexpm1) BF16_PACKET_FUNCTION(Packet8f, Packet8bf, plog) BF16_PACKET_FUNCTION(Packet8f, Packet8bf, plog1p) @@ -110,6 +108,7 @@ BF16_PACKET_FUNCTION(Packet8f, Packet8bf, psqrt) BF16_PACKET_FUNCTION(Packet8f, Packet8bf, ptanh) F16_PACKET_FUNCTION(Packet8f, Packet8h, pcos) F16_PACKET_FUNCTION(Packet8f, Packet8h, pexp) +F16_PACKET_FUNCTION(Packet8f, Packet8h, pexp2) F16_PACKET_FUNCTION(Packet8f, Packet8h, pexpm1) F16_PACKET_FUNCTION(Packet8f, Packet8h, plog) F16_PACKET_FUNCTION(Packet8f, Packet8h, plog1p) diff --git a/Eigen/src/Core/arch/AVX512/MathFunctions.h b/Eigen/src/Core/arch/AVX512/MathFunctions.h index 0677248b4..603925429 100644 --- a/Eigen/src/Core/arch/AVX512/MathFunctions.h +++ b/Eigen/src/Core/arch/AVX512/MathFunctions.h @@ -108,6 +108,7 @@ EIGEN_STRONG_INLINE Packet16f preciprocal(const Packet16f& a) { BF16_PACKET_FUNCTION(Packet16f, Packet16bf, pcos) BF16_PACKET_FUNCTION(Packet16f, Packet16bf, pexp) +BF16_PACKET_FUNCTION(Packet16f, Packet16bf, pexp2) BF16_PACKET_FUNCTION(Packet16f, Packet16bf, pexpm1) BF16_PACKET_FUNCTION(Packet16f, Packet16bf, plog) BF16_PACKET_FUNCTION(Packet16f, Packet16bf, plog1p) @@ -119,6 +120,7 @@ BF16_PACKET_FUNCTION(Packet16f, Packet16bf, psqrt) BF16_PACKET_FUNCTION(Packet16f, Packet16bf, ptanh) F16_PACKET_FUNCTION(Packet16f, Packet16h, pcos) F16_PACKET_FUNCTION(Packet16f, Packet16h, pexp) +F16_PACKET_FUNCTION(Packet16f, Packet16h, pexp2) F16_PACKET_FUNCTION(Packet16f, Packet16h, pexpm1) F16_PACKET_FUNCTION(Packet16f, Packet16h, plog) F16_PACKET_FUNCTION(Packet16f, Packet16h, plog1p) diff --git a/Eigen/src/Core/arch/Default/BFloat16.h b/Eigen/src/Core/arch/Default/BFloat16.h index 14f0524a3..b9f886fee 100644 --- a/Eigen/src/Core/arch/Default/BFloat16.h +++ b/Eigen/src/Core/arch/Default/BFloat16.h @@ -613,6 +613,7 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 abs(const bfloat16& a) { return numext::bit_cast(x); } EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 exp(const bfloat16& a) { return bfloat16(::expf(float(a))); } +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 exp2(const bfloat16& a) { return bfloat16(::exp2f(float(a))); } EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 expm1(const bfloat16& a) { return bfloat16(numext::expm1(float(a))); } EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 log(const bfloat16& a) { return bfloat16(::logf(float(a))); } EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 log1p(const bfloat16& a) { return bfloat16(numext::log1p(float(a))); } diff --git a/Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h b/Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h index c3270e132..a1849312b 100644 --- a/Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h +++ b/Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h @@ -469,7 +469,7 @@ EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog2_double(const Pa See: http://www.plunk.org/~hatch/rightway.php */ template -Packet generic_plog1p(const Packet& x) { +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_log1p(const Packet& x) { typedef typename unpacket_traits::type ScalarType; const Packet one = pset1(ScalarType(1)); Packet xp1 = padd(x, one); @@ -484,7 +484,7 @@ Packet generic_plog1p(const Packet& x) { See: http://www.plunk.org/~hatch/rightway.php */ template -Packet generic_expm1(const Packet& x) { +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_expm1(const Packet& x) { typedef typename unpacket_traits::type ScalarType; const Packet one = pset1(ScalarType(1)); const Packet neg_one = pset1(ScalarType(-1)); @@ -1109,7 +1109,7 @@ EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet patan_reduced: } template -EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_patan(const Packet& x_in) { +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_atan(const Packet& x_in) { typedef typename unpacket_traits::type Scalar; constexpr Scalar kPiOverTwo = static_cast(EIGEN_PI / 2); @@ -1973,13 +1973,13 @@ struct accurate_log2 { } }; -// This function computes exp2(x) (i.e. 2**x). +// This function accurately computes exp2(x) for x in [-0.5:0.5], which is +// needed in pow(x,y). template struct fast_accurate_exp2 { template EIGEN_STRONG_INLINE Packet operator()(const Packet& x) { - // TODO(rmlarsen): Add a pexp2 packetop. - return pexp(pmul(pset1(Scalar(EIGEN_LN2)), x)); + return generic_exp2(x); } }; @@ -2464,6 +2464,32 @@ struct unary_pow_impl { } }; +// This function computes exp2(x) = exp(ln(2) * x). +// To improve accuracy, the product ln(2)*x is computed using the twoprod +// algorithm, such that ln(2) * x = p_hi + p_lo holds exactly. Then exp2(x) is +// computed as exp2(x) = exp(p_hi) * exp(p_lo) ~= exp(p_hi) * (1 + p_lo). This +// correction step this reduces the maximum absolute error as follows: +// +// type | max error (simple product) | max error (twoprod) | +// ----------------------------------------------------------- +// float | 35 ulps | 4 ulps | +// double | 363 ulps | 110 ulps | +// +template +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_exp2(const Packet& _x) { + typedef typename unpacket_traits::type Scalar; + constexpr int max_exponent = std::numeric_limits::max_exponent; + constexpr int digits = std::numeric_limits::digits; + constexpr Scalar max_cap = Scalar(max_exponent + 1); + constexpr Scalar min_cap = -Scalar(max_exponent + digits - 1); + Packet x = pmax(pmin(_x, pset1(max_cap)), pset1(min_cap)); + Packet p_hi, p_lo; + twoprod(pset1(Scalar(EIGEN_LN2)), x, p_hi, p_lo); + Packet exp2_hi = pexp(p_hi); + Packet exp2_lo = padd(pset1(Scalar(1)), p_lo); + return pmul(exp2_hi, exp2_lo); +} + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet generic_rint(const Packet& a) { using Scalar = typename unpacket_traits::type; diff --git a/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h b/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h index f470c20d9..3b362f4f6 100644 --- a/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h +++ b/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h @@ -60,15 +60,19 @@ EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog2_double(const Pa /** \internal \returns log(1 + x) */ template -Packet generic_plog1p(const Packet& x); +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_log1p(const Packet& x); /** \internal \returns exp(x)-1 */ template -Packet generic_expm1(const Packet& x); +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_expm1(const Packet& x); /** \internal \returns atan(x) */ template -EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_patan(const Packet& x); +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_atan(const Packet& x); + +/** \internal \returns exp2(x) */ +template +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_exp2(const Packet& x); /** \internal \returns exp(x) for single precision float */ template @@ -159,44 +163,41 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet generic_round(const Packet& a); return p##METHOD##_##SCALAR(_x); \ } +// Macros for instantiating these generic functions for different backends. +#define EIGEN_GENERIC_PACKET_FUNCTION(METHOD, PACKET) \ + template <> \ + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC EIGEN_UNUSED PACKET p##METHOD(const PACKET& _x) { \ + return generic_##METHOD(_x); \ + } + #define EIGEN_FLOAT_PACKET_FUNCTION(METHOD, PACKET) EIGEN_PACKET_FUNCTION(METHOD, float, PACKET) #define EIGEN_DOUBLE_PACKET_FUNCTION(METHOD, PACKET) EIGEN_PACKET_FUNCTION(METHOD, double, PACKET) -#define EIGEN_INSTANTIATE_GENERIC_MATH_FUNCS_FLOAT(PACKET) \ - EIGEN_FLOAT_PACKET_FUNCTION(sin, PACKET) \ - EIGEN_FLOAT_PACKET_FUNCTION(cos, PACKET) \ - EIGEN_FLOAT_PACKET_FUNCTION(asin, PACKET) \ - EIGEN_FLOAT_PACKET_FUNCTION(acos, PACKET) \ - EIGEN_FLOAT_PACKET_FUNCTION(tanh, PACKET) \ - EIGEN_FLOAT_PACKET_FUNCTION(atanh, PACKET) \ - EIGEN_FLOAT_PACKET_FUNCTION(log, PACKET) \ - EIGEN_FLOAT_PACKET_FUNCTION(log2, PACKET) \ - EIGEN_FLOAT_PACKET_FUNCTION(exp, PACKET) \ - template <> \ - EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC EIGEN_UNUSED PACKET pexpm1(const PACKET& _x) { \ - return generic_expm1(_x); \ - } \ - template <> \ - EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC EIGEN_UNUSED PACKET plog1p(const PACKET& _x) { \ - return generic_plog1p(_x); \ - } \ - template <> \ - EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC EIGEN_UNUSED PACKET patan(const PACKET& _x) { \ - return generic_patan(_x); \ - } +#define EIGEN_INSTANTIATE_GENERIC_MATH_FUNCS_FLOAT(PACKET) \ + EIGEN_FLOAT_PACKET_FUNCTION(sin, PACKET) \ + EIGEN_FLOAT_PACKET_FUNCTION(cos, PACKET) \ + EIGEN_FLOAT_PACKET_FUNCTION(asin, PACKET) \ + EIGEN_FLOAT_PACKET_FUNCTION(acos, PACKET) \ + EIGEN_FLOAT_PACKET_FUNCTION(tanh, PACKET) \ + EIGEN_FLOAT_PACKET_FUNCTION(atanh, PACKET) \ + EIGEN_FLOAT_PACKET_FUNCTION(log, PACKET) \ + EIGEN_FLOAT_PACKET_FUNCTION(log2, PACKET) \ + EIGEN_FLOAT_PACKET_FUNCTION(exp, PACKET) \ + EIGEN_GENERIC_PACKET_FUNCTION(expm1, PACKET) \ + EIGEN_GENERIC_PACKET_FUNCTION(exp2, PACKET) \ + EIGEN_GENERIC_PACKET_FUNCTION(log1p, PACKET) \ + EIGEN_GENERIC_PACKET_FUNCTION(atan, PACKET) -#define EIGEN_INSTANTIATE_GENERIC_MATH_FUNCS_DOUBLE(PACKET) \ - EIGEN_DOUBLE_PACKET_FUNCTION(atanh, PACKET) \ - EIGEN_DOUBLE_PACKET_FUNCTION(log, PACKET) \ - EIGEN_DOUBLE_PACKET_FUNCTION(sin, PACKET) \ - EIGEN_DOUBLE_PACKET_FUNCTION(cos, PACKET) \ - EIGEN_DOUBLE_PACKET_FUNCTION(log2, PACKET) \ - EIGEN_DOUBLE_PACKET_FUNCTION(exp, PACKET) \ - EIGEN_DOUBLE_PACKET_FUNCTION(tanh, PACKET) \ - template <> \ - EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC EIGEN_UNUSED PACKET patan(const PACKET& _x) { \ - return generic_patan(_x); \ - } +#define EIGEN_INSTANTIATE_GENERIC_MATH_FUNCS_DOUBLE(PACKET) \ + EIGEN_DOUBLE_PACKET_FUNCTION(atanh, PACKET) \ + EIGEN_DOUBLE_PACKET_FUNCTION(log, PACKET) \ + EIGEN_DOUBLE_PACKET_FUNCTION(sin, PACKET) \ + EIGEN_DOUBLE_PACKET_FUNCTION(cos, PACKET) \ + EIGEN_DOUBLE_PACKET_FUNCTION(log2, PACKET) \ + EIGEN_DOUBLE_PACKET_FUNCTION(exp, PACKET) \ + EIGEN_DOUBLE_PACKET_FUNCTION(tanh, PACKET) \ + EIGEN_GENERIC_PACKET_FUNCTION(atan, PACKET) \ + EIGEN_GENERIC_PACKET_FUNCTION(exp2, PACKET) } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/arch/Default/Half.h b/Eigen/src/Core/arch/Default/Half.h index 1f314fae2..a8cb228c1 100644 --- a/Eigen/src/Core/arch/Default/Half.h +++ b/Eigen/src/Core/arch/Default/Half.h @@ -672,6 +672,14 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half exp(const half& a) { return half(::expf(float(a))); #endif } +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half exp2(const half& a) { +#if (EIGEN_CUDA_SDK_VER >= 80000 && defined EIGEN_CUDA_ARCH && EIGEN_CUDA_ARCH >= 530) || \ + defined(EIGEN_HIP_DEVICE_COMPILE) + return half(hexp2(a)); +#else + return half(::exp2f(float(a))); +#endif +} EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half expm1(const half& a) { return half(numext::expm1(float(a))); } EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half log(const half& a) { #if (defined(EIGEN_HAS_CUDA_FP16) && EIGEN_CUDA_SDK_VER >= 80000 && defined(EIGEN_CUDA_ARCH) && \ diff --git a/Eigen/src/Core/arch/GPU/MathFunctions.h b/Eigen/src/Core/arch/GPU/MathFunctions.h index 606215f0f..81bc8bb53 100644 --- a/Eigen/src/Core/arch/GPU/MathFunctions.h +++ b/Eigen/src/Core/arch/GPU/MathFunctions.h @@ -53,6 +53,17 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pexp(const double2& a) { return make_double2(exp(a.x), exp(a.y)); } +template <> +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pexp2(const float4& a) { + return make_float4(exp2f(a.x), exp2f(a.y), exp2f(a.z), exp2f(a.w)); +} + +template <> +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pexp2(const double2& a) { + using ::exp; + return make_double2(exp2(a.x), exp2(a.y)); +} + template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pexpm1(const float4& a) { return make_float4(expm1f(a.x), expm1f(a.y), expm1f(a.z), expm1f(a.w)); diff --git a/Eigen/src/Core/arch/NEON/MathFunctions.h b/Eigen/src/Core/arch/NEON/MathFunctions.h index bebe081a1..0046e01ef 100644 --- a/Eigen/src/Core/arch/NEON/MathFunctions.h +++ b/Eigen/src/Core/arch/NEON/MathFunctions.h @@ -37,6 +37,7 @@ BF16_PACKET_FUNCTION(Packet4f, Packet4bf, psin) BF16_PACKET_FUNCTION(Packet4f, Packet4bf, pcos) BF16_PACKET_FUNCTION(Packet4f, Packet4bf, plog) BF16_PACKET_FUNCTION(Packet4f, Packet4bf, pexp) +BF16_PACKET_FUNCTION(Packet4f, Packet4bf, pexp2) BF16_PACKET_FUNCTION(Packet4f, Packet4bf, ptanh) template <> diff --git a/Eigen/src/Core/functors/UnaryFunctors.h b/Eigen/src/Core/functors/UnaryFunctors.h index b3b7d79d6..defd3c2a1 100644 --- a/Eigen/src/Core/functors/UnaryFunctors.h +++ b/Eigen/src/Core/functors/UnaryFunctors.h @@ -376,6 +376,22 @@ struct functor_traits> { }; }; +template +struct scalar_exp2_op { + EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return internal::pexp2(a); } + template + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { + return internal::pexp2(a); + } +}; +template +struct functor_traits> { + enum { + PacketAccess = packet_traits::HasExp, + Cost = functor_traits>::Cost // TODO measure cost of exp2 + }; +}; + /** \internal * * \brief Template functor to compute the exponential of a scalar - 1. diff --git a/Eigen/src/plugins/ArrayCwiseUnaryOps.inc b/Eigen/src/plugins/ArrayCwiseUnaryOps.inc index cc708fadd..93f7eabe5 100644 --- a/Eigen/src/plugins/ArrayCwiseUnaryOps.inc +++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.inc @@ -11,6 +11,7 @@ typedef CwiseUnaryOp, const Derived> Boo typedef CwiseUnaryOp, const Derived> BitwiseNotReturnType; typedef CwiseUnaryOp, const Derived> ExpReturnType; +typedef CwiseUnaryOp, const Derived> Exp2ReturnType; typedef CwiseUnaryOp, const Derived> Expm1ReturnType; typedef CwiseUnaryOp, const Derived> LogReturnType; typedef CwiseUnaryOp, const Derived> Log1pReturnType; @@ -78,10 +79,20 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Abs2ReturnType abs2() const { return * Example: \include Cwise_exp.cpp * Output: \verbinclude Cwise_exp.out * - * \sa Math functions, pow(), log(), sin(), cos() + * \sa Math functions, exp2(), pow(), log(), sin(), + * cos() */ EIGEN_DEVICE_FUNC inline const ExpReturnType exp() const { return ExpReturnType(derived()); } +/** \returns an expression of the coefficient-wise exponential of *this. + * + * This function computes the coefficient-wise base2 exponential, i.e. 2^x. + * + * \sa Math functions, exp(), pow(), log(), sin(), + * cos() + */ +EIGEN_DEVICE_FUNC inline const Exp2ReturnType exp2() const { return Exp2ReturnType(derived()); } + /** \returns an expression of the coefficient-wise exponential of *this minus 1. * * In exact arithmetic, \c x.expm1() is equivalent to \c x.exp() - 1, diff --git a/test/array_cwise.cpp b/test/array_cwise.cpp index cc901ff4c..cf0e6e4b7 100644 --- a/test/array_cwise.cpp +++ b/test/array_cwise.cpp @@ -181,6 +181,7 @@ void unary_ops_test() { unary_op_test(UNARY_FUNCTOR_TEST_ARGS(sqrt)); unary_op_test(UNARY_FUNCTOR_TEST_ARGS(cbrt)); unary_op_test(UNARY_FUNCTOR_TEST_ARGS(exp)); + unary_op_test(UNARY_FUNCTOR_TEST_ARGS(exp2)); unary_op_test(UNARY_FUNCTOR_TEST_ARGS(log)); unary_op_test(UNARY_FUNCTOR_TEST_ARGS(sin)); unary_op_test(UNARY_FUNCTOR_TEST_ARGS(cos)); diff --git a/test/packetmath.cpp b/test/packetmath.cpp index 9afe47084..e4d1b8c06 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp @@ -931,6 +931,7 @@ void packetmath_real() { data1[0] = -NumTraits::infinity(); } CHECK_CWISE1_IF(PacketTraits::HasExp, std::exp, internal::pexp); + CHECK_CWISE1_IF(PacketTraits::HasExp, std::exp2, internal::pexp2); CHECK_CWISE1_BYREF1_IF(PacketTraits::HasExp, REF_FREXP, internal::pfrexp); if (PacketTraits::HasExp) {