diff options
author | Rasmus Munk Larsen <rmlarsen@google.com> | 2021-01-18 13:25:16 +0000 |
---|---|---|
committer | David Tellenbach <david.tellenbach@me.com> | 2021-01-18 13:25:16 +0000 |
commit | cdd8fdc32e730d5a65796a791ff13a92815c59b9 (patch) | |
tree | 3ee2ebf6295a44518d55ee3f6d9e26f4ca0a8a79 /Eigen/src/Core/functors/BinaryFunctors.h | |
parent | bde6741641b7c677d901cd48db844fcea1fd32fe (diff) |
Vectorize `pow(x, y)`. This closes https://gitlab.com/libeigen/eigen/-/issues/2085, which also contains a description of the algorithm.
I ran some testing (comparing to `std::pow(double(x), double(y)))` for `x` in the set of all (positive) floats in the interval `[std::sqrt(std::numeric_limits<float>::min()), std::sqrt(std::numeric_limits<float>::max())]`, and `y` in `{2, sqrt(2), -sqrt(2)}` I get the following error statistics:
```
max_rel_error = 8.34405e-07
rms_rel_error = 2.76654e-07
```
If I widen the range to all normal float I see lower accuracy for arguments where the result is subnormal, e.g. for `y = sqrt(2)`:
```
max_rel_error = 0.666667
rms = 6.8727e-05
count = 1335165689
argmax = 2.56049e-32, 2.10195e-45 != 1.4013e-45
```
which seems reasonable, since these results are subnormals with only couple of significant bits left.
Diffstat (limited to 'Eigen/src/Core/functors/BinaryFunctors.h')
-rw-r--r-- | Eigen/src/Core/functors/BinaryFunctors.h | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/Eigen/src/Core/functors/BinaryFunctors.h b/Eigen/src/Core/functors/BinaryFunctors.h index f3509c4b9..a3ec9e177 100644 --- a/Eigen/src/Core/functors/BinaryFunctors.h +++ b/Eigen/src/Core/functors/BinaryFunctors.h @@ -403,6 +403,7 @@ struct functor_traits<scalar_hypot_op<Scalar,Scalar> > { /** \internal * \brief Template functor to compute the pow of two scalars + * See the specification of pow in https://en.cppreference.com/w/cpp/numeric/math/pow */ template<typename Scalar, typename Exponent> struct scalar_pow_op : binary_op_base<Scalar,Exponent> @@ -417,12 +418,25 @@ struct scalar_pow_op : binary_op_base<Scalar,Exponent> EIGEN_SCALAR_BINARY_OP_PLUGIN } #endif + EIGEN_DEVICE_FUNC inline result_type operator() (const Scalar& a, const Exponent& b) const { return numext::pow(a, b); } + + template<typename Packet> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { + return generic_pow(a,b); + } }; + template<typename Scalar, typename Exponent> struct functor_traits<scalar_pow_op<Scalar,Exponent> > { - enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = false }; + enum { + Cost = 5 * NumTraits<Scalar>::MulCost, + PacketAccess = (!NumTraits<Scalar>::IsComplex && !NumTraits<Scalar>::IsInteger && + packet_traits<Scalar>::HasExp && packet_traits<Scalar>::HasLog && + packet_traits<Scalar>::HasRound && packet_traits<Scalar>::HasCmp) + }; }; |