Add exp2() as a packet op and array method.
diff --git a/Eigen/src/Core/GenericPacketMath.h b/Eigen/src/Core/GenericPacketMath.h index 1d79b4a..c7a9846 100644 --- a/Eigen/src/Core/GenericPacketMath.h +++ b/Eigen/src/Core/GenericPacketMath.h
@@ -1083,8 +1083,13 @@ /** \internal \returns the exp of \a a (coeff-wise) */ template <typename Packet> 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 <typename Packet> +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 @@ return log10(a); } -/** \internal \returns the log10 of \a a (coeff-wise) */ +/** \internal \returns the log2 of \a a (coeff-wise) */ template <typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog2(const Packet& a) { using Scalar = typename internal::unpacket_traits<Packet>::type;
diff --git a/Eigen/src/Core/GlobalFunctions.h b/Eigen/src/Core/GlobalFunctions.h index 3f147b8..df1098e 100644 --- a/Eigen/src/Core/GlobalFunctions.h +++ b/Eigen/src/Core/GlobalFunctions.h
@@ -76,6 +76,7 @@ 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 feb9099..57fb3bd 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h
@@ -1477,6 +1477,63 @@ } #endif +template <typename T> +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 <typename RealScalar> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE std::complex<RealScalar> exp2(const std::complex<RealScalar>& 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<RealScalar>(NumTraits<RealScalar>::quiet_NaN(), NumTraits<RealScalar>::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<RealScalar>::infinity() && !(isfinite)(imag_ref(x)))) { + return std::complex<RealScalar>(NumTraits<RealScalar>::infinity(), NumTraits<RealScalar>::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<float> exp2(const std::complex<float>& x) { + float com = ::exp2f(x.real()); + float res_real = com * ::cosf(static_cast<float>(EIGEN_LN2) * x.imag()); + float res_imag = com * ::sinf(static_cast<float>(EIGEN_LN2) * x.imag()); + return std::complex<float>(res_real, res_imag); +} + +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE std::complex<double> exp2(const std::complex<double>& x) { + double com = ::exp2(x.real()); + double res_real = com * ::cos(static_cast<double>(EIGEN_LN2) * x.imag()); + double res_imag = com * ::sin(static_cast<double>(EIGEN_LN2) * x.imag()); + return std::complex<double>(res_real, res_imag); +} +#endif + template <typename Scalar> 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 7b43fbb..a5c38e7 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(sin, Packet4d) EIGEN_DOUBLE_PACKET_FUNCTION(cos, Packet4d) #endif - -template <> -EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC EIGEN_UNUSED Packet4d patan<Packet4d>(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 @@ 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, 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 0677248..6039254 100644 --- a/Eigen/src/Core/arch/AVX512/MathFunctions.h +++ b/Eigen/src/Core/arch/AVX512/MathFunctions.h
@@ -108,6 +108,7 @@ 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, 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 14f0524..b9f886f 100644 --- a/Eigen/src/Core/arch/Default/BFloat16.h +++ b/Eigen/src/Core/arch/Default/BFloat16.h
@@ -613,6 +613,7 @@ return numext::bit_cast<bfloat16>(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 c3270e1..a184931 100644 --- a/Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h +++ b/Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h
@@ -469,7 +469,7 @@ See: http://www.plunk.org/~hatch/rightway.php */ template <typename Packet> -Packet generic_plog1p(const Packet& x) { +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_log1p(const Packet& x) { typedef typename unpacket_traits<Packet>::type ScalarType; const Packet one = pset1<Packet>(ScalarType(1)); Packet xp1 = padd(x, one); @@ -484,7 +484,7 @@ See: http://www.plunk.org/~hatch/rightway.php */ template <typename Packet> -Packet generic_expm1(const Packet& x) { +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_expm1(const Packet& x) { typedef typename unpacket_traits<Packet>::type ScalarType; const Packet one = pset1<Packet>(ScalarType(1)); const Packet neg_one = pset1<Packet>(ScalarType(-1)); @@ -1109,7 +1109,7 @@ } template <typename Packet> -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<Packet>::type Scalar; constexpr Scalar kPiOverTwo = static_cast<Scalar>(EIGEN_PI / 2); @@ -1973,13 +1973,13 @@ } }; -// 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 <typename Scalar> struct fast_accurate_exp2 { template <typename Packet> EIGEN_STRONG_INLINE Packet operator()(const Packet& x) { - // TODO(rmlarsen): Add a pexp2 packetop. - return pexp(pmul(pset1<Packet>(Scalar(EIGEN_LN2)), x)); + return generic_exp2(x); } }; @@ -2464,6 +2464,32 @@ } }; +// 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 <typename Packet> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_exp2(const Packet& _x) { + typedef typename unpacket_traits<Packet>::type Scalar; + constexpr int max_exponent = std::numeric_limits<Scalar>::max_exponent; + constexpr int digits = std::numeric_limits<Scalar>::digits; + constexpr Scalar max_cap = Scalar(max_exponent + 1); + constexpr Scalar min_cap = -Scalar(max_exponent + digits - 1); + Packet x = pmax(pmin(_x, pset1<Packet>(max_cap)), pset1<Packet>(min_cap)); + Packet p_hi, p_lo; + twoprod(pset1<Packet>(Scalar(EIGEN_LN2)), x, p_hi, p_lo); + Packet exp2_hi = pexp(p_hi); + Packet exp2_lo = padd(pset1<Packet>(Scalar(1)), p_lo); + return pmul(exp2_hi, exp2_lo); +} + template <typename Packet> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet generic_rint(const Packet& a) { using Scalar = typename unpacket_traits<Packet>::type;
diff --git a/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h b/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h index f470c20..3b362f4 100644 --- a/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h +++ b/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h
@@ -60,15 +60,19 @@ /** \internal \returns log(1 + x) */ template <typename Packet> -Packet generic_plog1p(const Packet& x); +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_log1p(const Packet& x); /** \internal \returns exp(x)-1 */ template <typename Packet> -Packet generic_expm1(const Packet& x); +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_expm1(const Packet& x); /** \internal \returns atan(x) */ template <typename Packet> -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 <typename Packet> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_exp2(const Packet& x); /** \internal \returns exp(x) for single precision float */ template <typename Packet> @@ -159,44 +163,41 @@ 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<PACKET>(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<PACKET>(const PACKET& _x) { \ - return generic_expm1(_x); \ - } \ - template <> \ - EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC EIGEN_UNUSED PACKET plog1p<PACKET>(const PACKET& _x) { \ - return generic_plog1p(_x); \ - } \ - template <> \ - EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC EIGEN_UNUSED PACKET patan<PACKET>(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<PACKET>(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 1f314fa..a8cb228 100644 --- a/Eigen/src/Core/arch/Default/Half.h +++ b/Eigen/src/Core/arch/Default/Half.h
@@ -672,6 +672,14 @@ 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 606215f..81bc8bb 100644 --- a/Eigen/src/Core/arch/GPU/MathFunctions.h +++ b/Eigen/src/Core/arch/GPU/MathFunctions.h
@@ -54,6 +54,17 @@ } template <> +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pexp2<float4>(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<double2>(const double2& a) { + using ::exp; + return make_double2(exp2(a.x), exp2(a.y)); +} + +template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pexpm1<float4>(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 bebe081..0046e01 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, 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 b3b7d79..defd3c2 100644 --- a/Eigen/src/Core/functors/UnaryFunctors.h +++ b/Eigen/src/Core/functors/UnaryFunctors.h
@@ -376,6 +376,22 @@ }; }; +template <typename Scalar> +struct scalar_exp2_op { + EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { return internal::pexp2(a); } + template <typename Packet> + EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { + return internal::pexp2(a); + } +}; +template <typename Scalar> +struct functor_traits<scalar_exp2_op<Scalar>> { + enum { + PacketAccess = packet_traits<Scalar>::HasExp, + Cost = functor_traits<scalar_exp_op<Scalar>>::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 cc708fa..93f7eab 100644 --- a/Eigen/src/plugins/ArrayCwiseUnaryOps.inc +++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.inc
@@ -11,6 +11,7 @@ typedef CwiseUnaryOp<internal::scalar_bitwise_not_op<Scalar>, const Derived> BitwiseNotReturnType; typedef CwiseUnaryOp<internal::scalar_exp_op<Scalar>, const Derived> ExpReturnType; +typedef CwiseUnaryOp<internal::scalar_exp2_op<Scalar>, const Derived> Exp2ReturnType; typedef CwiseUnaryOp<internal::scalar_expm1_op<Scalar>, const Derived> Expm1ReturnType; typedef CwiseUnaryOp<internal::scalar_log_op<Scalar>, const Derived> LogReturnType; typedef CwiseUnaryOp<internal::scalar_log1p_op<Scalar>, const Derived> Log1pReturnType; @@ -78,10 +79,20 @@ * Example: \include Cwise_exp.cpp * Output: \verbinclude Cwise_exp.out * - * \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_exp">Math functions</a>, pow(), log(), sin(), cos() + * \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_exp">Math functions</a>, 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 <a href="group__CoeffwiseMathFunctions.html#cwisetable_exp">Math functions</a>, 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 cc901ff..cf0e6e4 100644 --- a/test/array_cwise.cpp +++ b/test/array_cwise.cpp
@@ -181,6 +181,7 @@ unary_op_test<Scalar>(UNARY_FUNCTOR_TEST_ARGS(sqrt)); unary_op_test<Scalar>(UNARY_FUNCTOR_TEST_ARGS(cbrt)); unary_op_test<Scalar>(UNARY_FUNCTOR_TEST_ARGS(exp)); + unary_op_test<Scalar>(UNARY_FUNCTOR_TEST_ARGS(exp2)); unary_op_test<Scalar>(UNARY_FUNCTOR_TEST_ARGS(log)); unary_op_test<Scalar>(UNARY_FUNCTOR_TEST_ARGS(sin)); unary_op_test<Scalar>(UNARY_FUNCTOR_TEST_ARGS(cos));
diff --git a/test/packetmath.cpp b/test/packetmath.cpp index 9afe470..e4d1b8c 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp
@@ -931,6 +931,7 @@ data1[0] = -NumTraits<Scalar>::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) {