Advertisement
alaestor

libFGL approximate power

Dec 20th, 2022
1,001
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 1.88 KB | Source Code | 0 0
  1. // pow approximation for little-endian IEEE-754 binary64
  2. template <bool T_improved_precision = true>
  3. [[nodiscard]] constexpr inline
  4. double pow_approximation(double base, const double exponent)
  5. {
  6.     static_assert(
  7.         std::numeric_limits<float>::is_iec559
  8.         && std::numeric_limits<double>::is_iec559
  9.         && std::numeric_limits<long double>::is_iec559,
  10.         "fgl::pow_approximation() from " __FILE__
  11.         " requires IEC-559 aka IEEE-754 floating point representations."
  12.         " The target platform and/or vendor implementation is incompatible."
  13.     );
  14.  
  15. #pragma GCC diagnostic push
  16. #pragma GCC diagnostic ignored "-Wfloat-equal"
  17.     if (exponent == 0) return 1;
  18.     else if (exponent == 1) return base;
  19. #pragma GCC diagnostic pop
  20.  
  21.     using half_t = uint_least32_t;
  22.     static_assert(sizeof(half_t) == sizeof(decltype(base)) / 2);
  23.     using array_t = std::array<half_t, 2>;
  24.  
  25.     auto intrep{ std::bit_cast<array_t>(base) };
  26.     intrep[0] = 0;
  27.  
  28.     constexpr uint_fast32_t magic{ 1072632447 };
  29.  
  30.     // TODO could be generic for any floating point type; need to
  31.     // find magic cconstants for float and long double, and selectively pick
  32.     // half_t conditionally (16 for float, 32 for double, 64 for long double)
  33.  
  34.     if constexpr (T_improved_precision)
  35.     {
  36.         // is this still the case? should test
  37.         // stolen comments from the code i adapted:
  38.         //    exponentiation by squaring with the exponent's integer part
  39.         //    double r = u.d makes everything much slower, not sure why
  40.         uint_fast32_t exp_i{ static_cast<uint_fast32_t>(exponent) };
  41.         intrep[1] = static_cast<half_t>(
  42.             (exponent - exp_i) * (intrep[1] - magic) + magic
  43.         );
  44.         double r{ 1.0 };
  45.         while (exp_i)
  46.         {
  47.             if (exp_i & 1)
  48.             {
  49.                 r *= base;
  50.             }
  51.             base *= base;
  52.             exp_i >>= 1;
  53.         }
  54.         return r * std::bit_cast<double>(intrep);
  55.     }
  56.     else
  57.     {
  58.         intrep[1] = static_cast<half_t>(exponent * (intrep[1] - magic) + magic);
  59.         return std::bit_cast<double>(intrep);
  60.     }
  61. }
Tags: math pow
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement