When output is denormal.
| 154 | |
| 155 | // When output is denormal. |
| 156 | double exp2_denorm(double x) { |
| 157 | // Range reduction. |
| 158 | int k = |
| 159 | static_cast<int>(cpp::bit_cast<uint64_t>(x + 0x1.8000'0000'4p21) >> 19); |
| 160 | double kd = static_cast<double>(k); |
| 161 | |
| 162 | uint32_t idx1 = (k >> 6) & 0x3f; |
| 163 | uint32_t idx2 = k & 0x3f; |
| 164 | |
| 165 | int hi = k >> 12; |
| 166 | |
| 167 | DoubleDouble exp_mid1{EXP2_MID1[idx1].mid, EXP2_MID1[idx1].hi}; |
| 168 | DoubleDouble exp_mid2{EXP2_MID2[idx2].mid, EXP2_MID2[idx2].hi}; |
| 169 | DoubleDouble exp_mid = fputil::quick_mult(exp_mid1, exp_mid2); |
| 170 | |
| 171 | // |dx| < 2^-13 + 2^-30. |
| 172 | double dx = fputil::multiply_add(kd, -0x1.0p-12, x); // exact |
| 173 | |
| 174 | double mid_lo = dx * exp_mid.hi; |
| 175 | |
| 176 | // Approximate (2^dx - 1)/dx ~ 1 + a0*dx + a1*dx^2 + a2*dx^3 + a3*dx^4. |
| 177 | double p = poly_approx_d(dx); |
| 178 | |
| 179 | double lo = fputil::multiply_add(p, mid_lo, exp_mid.lo); |
| 180 | |
| 181 | #ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS |
| 182 | return ziv_test_denorm</*SKIP_ZIV_TEST=*/true>(hi, exp_mid.hi, lo, ERR_D) |
| 183 | .value(); |
| 184 | #else |
| 185 | if (auto r = ziv_test_denorm(hi, exp_mid.hi, lo, ERR_D); |
| 186 | LIBC_LIKELY(r.has_value())) |
| 187 | return r.value(); |
| 188 | |
| 189 | // Use double-double |
| 190 | DoubleDouble r_dd = exp2_double_double(dx, exp_mid); |
| 191 | |
| 192 | if (auto r = ziv_test_denorm(hi, r_dd.hi, r_dd.lo, ERR_DD); |
| 193 | LIBC_LIKELY(r.has_value())) |
| 194 | return r.value(); |
| 195 | |
| 196 | // Use 128-bit precision |
| 197 | Float128 r_f128 = exp2_f128(dx, hi, idx1, idx2); |
| 198 | |
| 199 | return static_cast<double>(r_f128); |
| 200 | #endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS |
| 201 | } |
| 202 | |
| 203 | // Check for exceptional cases when: |
| 204 | // * log2(1 - 2^-54) < x < log2(1 + 2^-53) |
no test coverage detected