| 1 | /* Copyright (C) 2012-2024 Free Software Foundation, Inc. |
| 2 | This file is part of the GNU C Library. |
| 3 | |
| 4 | The GNU C Library is free software; you can redistribute it and/or |
| 5 | modify it under the terms of the GNU Lesser General Public |
| 6 | License as published by the Free Software Foundation; either |
| 7 | version 2.1 of the License, or (at your option) any later version. |
| 8 | |
| 9 | The GNU C Library is distributed in the hope that it will be useful, |
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | Lesser General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU Lesser General Public |
| 15 | License along with the GNU C Library; if not, see |
| 16 | <https://www.gnu.org/licenses/>. */ |
| 17 | |
| 18 | #include <math.h> |
| 19 | #include <math-barriers.h> |
| 20 | #include <math-narrow-eval.h> |
| 21 | #include <math-svid-compat.h> |
| 22 | #include <libm-alias-finite.h> |
| 23 | #include <libm-alias-double.h> |
| 24 | #include "math_config.h" |
| 25 | |
| 26 | #define N (1 << EXP_TABLE_BITS) |
| 27 | #define IndexMask (N - 1) |
| 28 | #define OFlowBound 0x1.34413509f79ffp8 /* log10(DBL_MAX). */ |
| 29 | #define UFlowBound -0x1.5ep+8 /* -350. */ |
| 30 | #define SmallTop 0x3c6 /* top12(0x1p-57). */ |
| 31 | #define BigTop 0x407 /* top12(0x1p8). */ |
| 32 | #define Thresh 0x41 /* BigTop - SmallTop. */ |
| 33 | #define Shift __exp_data.shift |
| 34 | #define C(i) __exp_data.exp10_poly[i] |
| 35 | |
| 36 | static double |
| 37 | special_case (uint64_t sbits, double_t tmp, uint64_t ki) |
| 38 | { |
| 39 | double_t scale, y; |
| 40 | |
| 41 | if (ki - (1ull << 16) < 0x80000000) |
| 42 | { |
| 43 | /* The exponent of scale might have overflowed by 1. */ |
| 44 | sbits -= 1ull << 52; |
| 45 | scale = asdouble (i: sbits); |
| 46 | y = 2 * (scale + scale * tmp); |
| 47 | return check_oflow (x: y); |
| 48 | } |
| 49 | |
| 50 | /* n < 0, need special care in the subnormal range. */ |
| 51 | sbits += 1022ull << 52; |
| 52 | scale = asdouble (i: sbits); |
| 53 | y = scale + scale * tmp; |
| 54 | |
| 55 | if (y < 1.0) |
| 56 | { |
| 57 | /* Round y to the right precision before scaling it into the subnormal |
| 58 | range to avoid double rounding that can cause 0.5+E/2 ulp error where |
| 59 | E is the worst-case ulp error outside the subnormal range. So this |
| 60 | is only useful if the goal is better than 1 ulp worst-case error. */ |
| 61 | double_t lo = scale - y + scale * tmp; |
| 62 | double_t hi = 1.0 + y; |
| 63 | lo = 1.0 - hi + y + lo; |
| 64 | y = math_narrow_eval (hi + lo) - 1.0; |
| 65 | /* Avoid -0.0 with downward rounding. */ |
| 66 | if (WANT_ROUNDING && y == 0.0) |
| 67 | y = 0.0; |
| 68 | /* The underflow exception needs to be signaled explicitly. */ |
| 69 | math_force_eval (math_opt_barrier (0x1p-1022) * 0x1p-1022); |
| 70 | } |
| 71 | y = 0x1p-1022 * y; |
| 72 | |
| 73 | return check_uflow (x: y); |
| 74 | } |
| 75 | |
| 76 | /* Double-precision 10^x approximation. Largest observed error is ~0.513 ULP. */ |
| 77 | double |
| 78 | __exp10 (double x) |
| 79 | { |
| 80 | uint64_t ix = asuint64 (f: x); |
| 81 | uint32_t abstop = (ix >> 52) & 0x7ff; |
| 82 | |
| 83 | if (__glibc_unlikely (abstop - SmallTop >= Thresh)) |
| 84 | { |
| 85 | if (abstop - SmallTop >= 0x80000000) |
| 86 | /* Avoid spurious underflow for tiny x. |
| 87 | Note: 0 is common input. */ |
| 88 | return x + 1; |
| 89 | if (abstop == 0x7ff) |
| 90 | return ix == asuint64 (f: -INFINITY) ? 0.0 : x + 1.0; |
| 91 | if (x >= OFlowBound) |
| 92 | return __math_oflow (0); |
| 93 | if (x < UFlowBound) |
| 94 | return __math_uflow (0); |
| 95 | |
| 96 | /* Large x is special-cased below. */ |
| 97 | abstop = 0; |
| 98 | } |
| 99 | |
| 100 | /* Reduce x: z = x * N / log10(2), k = round(z). */ |
| 101 | double_t z = __exp_data.invlog10_2N * x; |
| 102 | double_t kd; |
| 103 | int64_t ki; |
| 104 | #if TOINT_INTRINSICS |
| 105 | kd = roundtoint (z); |
| 106 | ki = converttoint (z); |
| 107 | #else |
| 108 | kd = math_narrow_eval (z + Shift); |
| 109 | kd -= Shift; |
| 110 | ki = kd; |
| 111 | #endif |
| 112 | |
| 113 | /* r = x - k * log10(2), r in [-0.5, 0.5]. */ |
| 114 | double_t r = x; |
| 115 | r = __exp_data.neglog10_2hiN * kd + r; |
| 116 | r = __exp_data.neglog10_2loN * kd + r; |
| 117 | |
| 118 | /* exp10(x) = 2^(k/N) * 2^(r/N). |
| 119 | Approximate the two components separately. */ |
| 120 | |
| 121 | /* s = 2^(k/N), using lookup table. */ |
| 122 | uint64_t e = ki << (52 - EXP_TABLE_BITS); |
| 123 | uint64_t i = (ki & IndexMask) * 2; |
| 124 | uint64_t u = __exp_data.tab[i + 1]; |
| 125 | uint64_t sbits = u + e; |
| 126 | |
| 127 | double_t tail = asdouble (i: __exp_data.tab[i]); |
| 128 | |
| 129 | /* 2^(r/N) ~= 1 + r * Poly(r). */ |
| 130 | double_t r2 = r * r; |
| 131 | double_t p = C (0) + r * C (1); |
| 132 | double_t y = C (2) + r * C (3); |
| 133 | y = y + r2 * C (4); |
| 134 | y = p + r2 * y; |
| 135 | y = tail + y * r; |
| 136 | |
| 137 | if (__glibc_unlikely (abstop == 0)) |
| 138 | return special_case (sbits, tmp: y, ki); |
| 139 | |
| 140 | /* Assemble components: |
| 141 | y = 2^(r/N) * 2^(k/N) |
| 142 | ~= (y + 1) * s. */ |
| 143 | double_t s = asdouble (i: sbits); |
| 144 | return s * y + s; |
| 145 | } |
| 146 | |
| 147 | strong_alias (__exp10, __ieee754_exp10) |
| 148 | libm_alias_finite (__ieee754_exp10, __exp10) |
| 149 | #if LIBM_SVID_COMPAT |
| 150 | versioned_symbol (libm, __exp10, exp10, GLIBC_2_39); |
| 151 | libm_alias_double_other (__exp10, exp10) |
| 152 | #else |
| 153 | libm_alias_double (__exp10, exp10) |
| 154 | #endif |
| 155 | |