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.
This commit is contained in:
Rasmus Munk Larsen
2021-01-18 13:25:16 +00:00
committed by David Tellenbach
parent bde6741641
commit cdd8fdc32e
5 changed files with 270 additions and 9 deletions

View File

@@ -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)
};
};