1 //===-- Single-precision 2^x function -------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "src/math/exp2f.h" 10 #include "src/__support/FPUtil/BasicOperations.h" 11 #include "src/__support/FPUtil/FEnvImpl.h" 12 #include "src/__support/FPUtil/FMA.h" 13 #include "src/__support/FPUtil/FPBits.h" 14 #include "src/__support/FPUtil/PolyEval.h" 15 #include "src/__support/common.h" 16 17 #include <errno.h> 18 19 namespace __llvm_libc { 20 21 // Lookup table for 2^(m * 2^(-6)) with m = 0, ..., 63. 22 // Table is generated with Sollya as follow: 23 // > display = hexadecimal; 24 // > for i from 0 to 63 do { D(2^(i / 64)); }; 25 static constexpr double EXP_M[64] = { 26 0x1.0000000000000p0, 0x1.02c9a3e778061p0, 0x1.059b0d3158574p0, 27 0x1.0874518759bc8p0, 0x1.0b5586cf9890fp0, 0x1.0e3ec32d3d1a2p0, 28 0x1.11301d0125b51p0, 0x1.1429aaea92de0p0, 0x1.172b83c7d517bp0, 29 0x1.1a35beb6fcb75p0, 0x1.1d4873168b9aap0, 0x1.2063b88628cd6p0, 30 0x1.2387a6e756238p0, 0x1.26b4565e27cddp0, 0x1.29e9df51fdee1p0, 31 0x1.2d285a6e4030bp0, 0x1.306fe0a31b715p0, 0x1.33c08b26416ffp0, 32 0x1.371a7373aa9cbp0, 0x1.3a7db34e59ff7p0, 0x1.3dea64c123422p0, 33 0x1.4160a21f72e2ap0, 0x1.44e086061892dp0, 0x1.486a2b5c13cd0p0, 34 0x1.4bfdad5362a27p0, 0x1.4f9b2769d2ca7p0, 0x1.5342b569d4f82p0, 35 0x1.56f4736b527dap0, 0x1.5ab07dd485429p0, 0x1.5e76f15ad2148p0, 36 0x1.6247eb03a5585p0, 0x1.6623882552225p0, 0x1.6a09e667f3bcdp0, 37 0x1.6dfb23c651a2fp0, 0x1.71f75e8ec5f74p0, 0x1.75feb564267c9p0, 38 0x1.7a11473eb0187p0, 0x1.7e2f336cf4e62p0, 0x1.82589994cce13p0, 39 0x1.868d99b4492edp0, 0x1.8ace5422aa0dbp0, 0x1.8f1ae99157736p0, 40 0x1.93737b0cdc5e5p0, 0x1.97d829fde4e50p0, 0x1.9c49182a3f090p0, 41 0x1.a0c667b5de565p0, 0x1.a5503b23e255dp0, 0x1.a9e6b5579fdbfp0, 42 0x1.ae89f995ad3adp0, 0x1.b33a2b84f15fbp0, 0x1.b7f76f2fb5e47p0, 43 0x1.bcc1e904bc1d2p0, 0x1.c199bdd85529cp0, 0x1.c67f12e57d14bp0, 44 0x1.cb720dcef9069p0, 0x1.d072d4a07897cp0, 0x1.d5818dcfba487p0, 45 0x1.da9e603db3285p0, 0x1.dfc97337b9b5fp0, 0x1.e502ee78b3ff6p0, 46 0x1.ea4afa2a490dap0, 0x1.efa1bee615a27p0, 0x1.f50765b6e4540p0, 47 0x1.fa7c1819e90d8p0, 48 }; 49 50 LLVM_LIBC_FUNCTION(float, exp2f, (float x)) { 51 using FPBits = typename fputil::FPBits<float>; 52 FPBits xbits(x); 53 54 uint32_t x_u = xbits.uintval(); 55 uint32_t x_abs = x_u & 0x7fff'ffffU; 56 57 // Exceptional values. 58 switch (x_u) { 59 case 0x3b42'9d37U: // x = 0x1.853a6ep-9f 60 if (fputil::get_round() == FE_TONEAREST) 61 return 0x1.00870ap+0f; 62 break; 63 case 0x3c02'a9adU: // x = 0x1.05535ap-7f 64 if (fputil::get_round() == FE_TONEAREST) 65 return 0x1.016b46p+0f; 66 break; 67 case 0x3ca6'6e26U: { // x = 0x1.4cdc4cp-6f 68 int round_mode = fputil::get_round(); 69 if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD) 70 return 0x1.03a16ap+0f; 71 return 0x1.03a168p+0f; 72 } 73 case 0x3d92'a282U: // x = 0x1.254504p-4f 74 if (fputil::get_round() == FE_UPWARD) 75 return 0x1.0d0688p+0f; 76 return 0x1.0d0686p+0f; 77 case 0xbcf3'a937U: // x = -0x1.e7526ep-6f 78 if (fputil::get_round() == FE_TONEAREST) 79 return 0x1.f58d62p-1f; 80 break; 81 case 0xb8d3'd026U: // x = -0x1.a7a04cp-14f 82 if (fputil::get_round() == FE_TONEAREST) 83 return 0x1.fff6d2p-1f; 84 break; 85 } 86 87 // // When |x| >= 128, |x| < 2^-25, or x is nan 88 if (unlikely(x_abs >= 0x4300'0000U || x_abs <= 0x3280'0000U)) { 89 // |x| < 2^-25 90 if (x_abs <= 0x3280'0000U) { 91 return 1.0f + x; 92 } 93 // x >= 128 94 if (!xbits.get_sign()) { 95 // x is finite 96 if (x_u < 0x7f80'0000U) { 97 int rounding = fputil::get_round(); 98 if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) 99 return static_cast<float>(FPBits(FPBits::MAX_NORMAL)); 100 101 errno = ERANGE; 102 } 103 // x is +inf or nan 104 return x + static_cast<float>(FPBits::inf()); 105 } 106 // x < -150 107 if (x_u >= 0xc316'0000U) { 108 // exp(-Inf) = 0 109 if (xbits.is_inf()) 110 return 0.0f; 111 // exp(nan) = nan 112 if (xbits.is_nan()) 113 return x; 114 if (fputil::get_round() == FE_UPWARD) 115 return static_cast<float>(FPBits(FPBits::MIN_SUBNORMAL)); 116 if (x != 0.0f) 117 errno = ERANGE; 118 return 0.0f; 119 } 120 } 121 // For -150 <= x < 128, to compute 2^x, we perform the following range 122 // reduction: find hi, mid, lo such that: 123 // x = hi + mid + lo, in which 124 // hi is an integer, 125 // mid * 2^6 is an integer 126 // -2^(-7) <= lo < 2^-7. 127 // In particular, 128 // hi + mid = round(x * 2^6) * 2^(-6). 129 // Then, 130 // 2^(x) = 2^(hi + mid + lo) = 2^hi * 2^mid * 2^lo. 131 // Multiply by 2^hi is simply adding hi to the exponent field. We store 132 // exp(mid) in the lookup tables EXP_M. exp(lo) is computed using a degree-4 133 // minimax polynomial generated by Sollya. 134 135 // x_hi = round(hi + mid). 136 // The default rounding mode for float-to-int conversion in C++ is 137 // round-toward-zero. To make it round-to-nearest, we add (-1)^sign(x) * 0.5 138 // before conversion. 139 int x_hi = 140 static_cast<int>(x * 0x1.0p+6f + (xbits.get_sign() ? -0.5f : 0.5f)); 141 // For 2-complement integers, arithmetic right shift is the same as dividing 142 // by a power of 2 and then round down (toward negative infinity). 143 int e_hi = (x_hi >> 6) + 144 static_cast<int>(fputil::FloatProperties<double>::EXPONENT_BIAS); 145 fputil::FPBits<double> exp_hi( 146 static_cast<uint64_t>(e_hi) 147 << fputil::FloatProperties<double>::MANTISSA_WIDTH); 148 // mid = x_hi & 0x0000'003fU; 149 double exp_hi_mid = static_cast<double>(exp_hi) * EXP_M[x_hi & 0x3f]; 150 // Subtract (hi + mid) from x to get lo. 151 x -= static_cast<float>(x_hi) * 0x1.0p-6f; 152 double xd = static_cast<double>(x); 153 // Degree-4 minimax polynomial generated by Sollya with the following 154 // commands: 155 // > display = hexadecimal; 156 // > Q = fpminimax((2^x - 1)/x, 3, [|D...|], [-2^-7, 2^-7]); 157 // > Q; 158 double exp_lo = 159 fputil::polyeval(xd, 0x1p0, 0x1.62e42fefa2417p-1, 0x1.ebfbdff82f809p-3, 160 0x1.c6b0b92131c47p-5, 0x1.3b2ab6fb568a3p-7); 161 double result = exp_hi_mid * exp_lo; 162 return static_cast<float>(result); 163 } 164 165 } // namespace __llvm_libc 166