Eigen::internal::scalar_logistic_op< float > Struct Reference

Template specialization of the logistic function for float. Computes S(x) = exp(x) / (1 + exp(x)), where exp(x) is implemented using an algorithm partly adopted from the implementation of pexp_float. See the individual steps described in the code below. Note that compared to pexp, we use an additional outer multiplicative range reduction step using the identity exp(x) = exp(x/2)^2. This prevert us from having to call ldexp on values that could produce a denormal result, which allows us to call the faster implementation in pldexp_fast_impl<Packet>::run(p, m). The final squaring, however, doubles the error bound on the final approximation. Exhaustive testing shows that we have a worst case error of 4.5 ulps (compared to computing S(x) in double precision), which is acceptable. More...

#include <UnaryFunctors.h>

Public Member Functions

EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float operator() (const float &x) const
 
template<typename Packet >
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp (const Packet &_x) const
 

Detailed Description

Template specialization of the logistic function for float. Computes S(x) = exp(x) / (1 + exp(x)), where exp(x) is implemented using an algorithm partly adopted from the implementation of pexp_float. See the individual steps described in the code below. Note that compared to pexp, we use an additional outer multiplicative range reduction step using the identity exp(x) = exp(x/2)^2. This prevert us from having to call ldexp on values that could produce a denormal result, which allows us to call the faster implementation in pldexp_fast_impl<Packet>::run(p, m). The final squaring, however, doubles the error bound on the final approximation. Exhaustive testing shows that we have a worst case error of 4.5 ulps (compared to computing S(x) in double precision), which is acceptable.

Member Function Documentation

◆ operator()()

EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float Eigen::internal::scalar_logistic_op< float >::operator() ( const float &  x) const
inline
1238  {
1239  // Truncate at the first point where the interpolant is exactly one.
1240  const float cst_exp_hi = 16.6355324f;
1241  const float e = numext::exp(numext::mini(x, cst_exp_hi));
1242  return e / (1.0f + e);
1243  }
Array< double, 1, 3 > e(1./3., 0.5, 2.)
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T exp(const T &x)
Definition: MathFunctions.h:1424
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T mini(const T &x, const T &y)
Definition: MathFunctions.h:920
list x
Definition: plotDoE.py:28

References e(), Eigen::numext::exp(), Eigen::numext::mini(), and plotDoE::x.

◆ packetOp()

template<typename Packet >
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet Eigen::internal::scalar_logistic_op< float >::packetOp ( const Packet _x) const
inline
1246  {
1247  const Packet cst_zero = pset1<Packet>(0.0f);
1248  const Packet cst_one = pset1<Packet>(1.0f);
1249  const Packet cst_half = pset1<Packet>(0.5f);
1250  // Truncate at the first point where the interpolant is exactly one.
1251  const Packet cst_exp_hi = pset1<Packet>(16.6355324f);
1252  const Packet cst_exp_lo = pset1<Packet>(-104.f);
1253 
1254  // Clamp x to the non-trivial range where S(x). Outside this
1255  // interval the correctly rounded value of S(x) is either zero
1256  // or one.
1257  Packet zero_mask = pcmp_lt(_x, cst_exp_lo);
1258  Packet x = pmin(_x, cst_exp_hi);
1259 
1260  // 1. Multiplicative range reduction:
1261  // Reduce the range of x by a factor of 2. This avoids having
1262  // to compute exp(x) accurately where the result is a denormalized
1263  // value.
1264  x = pmul(x, cst_half);
1265 
1266  // 2. Subtractive range reduction:
1267  // Express exp(x) as exp(m*ln(2) + r) = 2^m*exp(r), start by extracting
1268  // m = floor(x/ln(2) + 0.5), such that x = m*ln(2) + r.
1269  const Packet cst_cephes_LOG2EF = pset1<Packet>(1.44269504088896341f);
1270  Packet m = pfloor(pmadd(x, cst_cephes_LOG2EF, cst_half));
1271  // Get r = x - m*ln(2). We use a trick from Cephes where the term
1272  // m*ln(2) is subtracted out in two parts, m*C1+m*C2 = m*ln(2),
1273  // to avoid accumulating truncation errors.
1274  const Packet cst_cephes_exp_C1 = pset1<Packet>(-0.693359375f);
1275  const Packet cst_cephes_exp_C2 = pset1<Packet>(2.12194440e-4f);
1276  Packet r = pmadd(m, cst_cephes_exp_C1, x);
1277  r = pmadd(m, cst_cephes_exp_C2, r);
1278 
1279  // 3. Compute an approximation to exp(r) using a degree 5 minimax polynomial.
1280  // We compute even and odd terms separately to increase instruction level
1281  // parallelism.
1282  Packet r2 = pmul(r, r);
1283  const Packet cst_p2 = pset1<Packet>(0.49999141693115234375f);
1284  const Packet cst_p3 = pset1<Packet>(0.16666877269744873046875f);
1285  const Packet cst_p4 = pset1<Packet>(4.1898667812347412109375e-2f);
1286  const Packet cst_p5 = pset1<Packet>(8.33471305668354034423828125e-3f);
1287 
1288  const Packet p_even = pmadd(r2, cst_p4, cst_p2);
1289  const Packet p_odd = pmadd(r2, cst_p5, cst_p3);
1290  const Packet p_low = padd(r, cst_one);
1291  Packet p = pmadd(r, p_odd, p_even);
1292  p = pmadd(r2, p, p_low);
1293 
1294  // 4. Undo subtractive range reduction exp(m*ln(2) + r) = 2^m * exp(r).
1295  Packet e = pldexp_fast(p, m);
1296 
1297  // 5. Undo multiplicative range reduction by using exp(r) = exp(r/2)^2.
1298  e = pmul(e, e);
1299 
1300  // Return exp(x) / (1 + exp(x))
1301  return pselect(zero_mask, cst_zero, pdiv(e, padd(cst_one, e)));
1302  }
float * p
Definition: Tutorial_Map_using.cpp:9
int * m
Definition: level2_cplx_impl.h:294
EIGEN_DEVICE_FUNC Packet padd(const Packet &a, const Packet &b)
Definition: GenericPacketMath.h:318
EIGEN_DEVICE_FUNC Packet pdiv(const Packet &a, const Packet &b)
Definition: GenericPacketMath.h:368
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Packet pldexp_fast(const Packet &a, const Packet &exponent)
Definition: GenericPacketMathFunctions.h:277
EIGEN_STRONG_INLINE Packet4i pcmp_lt(const Packet4i &a, const Packet4i &b)
Definition: AltiVec/PacketMath.h:1341
EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f &a, const Packet4f &b, const Packet4f &c)
Definition: AltiVec/PacketMath.h:1218
EIGEN_STRONG_INLINE Packet4cf pmul(const Packet4cf &a, const Packet4cf &b)
Definition: AVX/Complex.h:88
EIGEN_DEVICE_FUNC Packet pmin(const Packet &a, const Packet &b)
Definition: GenericPacketMath.h:649
EIGEN_STRONG_INLINE Packet4f pselect(const Packet4f &mask, const Packet4f &a, const Packet4f &b)
Definition: AltiVec/PacketMath.h:1474
EIGEN_STRONG_INLINE Packet4f pfloor(const Packet4f &a)
Definition: LSX/PacketMath.h:2537
r
Definition: UniformPSDSelfTest.py:20

References e(), m, p, Eigen::internal::padd(), Eigen::internal::pcmp_lt(), Eigen::internal::pdiv(), Eigen::internal::pfloor(), Eigen::internal::pldexp_fast(), Eigen::internal::pmadd(), Eigen::internal::pmin(), Eigen::internal::pmul(), Eigen::internal::pselect(), UniformPSDSelfTest::r, and plotDoE::x.


The documentation for this struct was generated from the following file: