| 1 | //! Ported from musl, which is licensed under the MIT license: |
| 2 | //! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | //! |
| 4 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/log2f.c |
| 5 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/log2.c |
| 6 | |
| 7 | const std = @import("std"); |
| 8 | const builtin = @import("builtin"); |
| 9 | const math = std.math; |
| 10 | const expect = std.testing.expect; |
| 11 | const expectEqual = std.testing.expectEqual; |
| 12 | const maxInt = std.math.maxInt; |
| 13 | const arch = builtin.cpu.arch; |
| 14 | const compiler_rt = @import("../compiler_rt.zig"); |
| 15 | const symbol = compiler_rt.symbol; |
| 16 | |
| 17 | comptime { |
| 18 | symbol(&__log2h, "__log2h"); |
| 19 | symbol(&log2f, "log2f"); |
| 20 | symbol(&log2, "log2"); |
| 21 | symbol(&__log2x, "__log2x"); |
| 22 | symbol(&log2q, "log2f128"); |
| 23 | symbol(&log2l, "log2l"); |
| 24 | } |
| 25 | |
| 26 | fn __log2h(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { |
| 27 | return compiler_rt.f16.toAbi(log2_f16(compiler_rt.f16.fromAbi(a))); |
| 28 | } |
| 29 | pub fn log2_f16(a: f16) f16 { |
| 30 | // TODO: more efficient implementation |
| 31 | return @floatCast(log2_f32(a)); |
| 32 | } |
| 33 | |
| 34 | fn log2f(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { |
| 35 | return compiler_rt.f32.toAbi(log2_f32(compiler_rt.f32.fromAbi(a))); |
| 36 | } |
| 37 | pub fn log2_f32(x_: f32) f32 { |
| 38 | const ivln2hi: f32 = 1.4428710938e+00; |
| 39 | const ivln2lo: f32 = -1.7605285393e-04; |
| 40 | const Lg1: f32 = 0xaaaaaa.0p-24; |
| 41 | const Lg2: f32 = 0xccce13.0p-25; |
| 42 | const Lg3: f32 = 0x91e9ee.0p-25; |
| 43 | const Lg4: f32 = 0xf89e26.0p-26; |
| 44 | |
| 45 | var x = x_; |
| 46 | var u: u32 = @bitCast(x); |
| 47 | var ix = u; |
| 48 | var k: i32 = 0; |
| 49 | |
| 50 | // x < 2^(-126) |
| 51 | if (ix < 0x00800000 or ix >> 31 != 0) { |
| 52 | // log(+-0) = -inf |
| 53 | if (ix << 1 == 0) { |
| 54 | return if (compiler_rt.want_float_exceptions) -1 / (x * x) else -std.math.inf(f64); |
| 55 | } |
| 56 | // log(-#) = nan |
| 57 | if (ix >> 31 != 0) { |
| 58 | return if (compiler_rt.want_float_exceptions) (x - x) / 0.0 else math.nan(f64); |
| 59 | } |
| 60 | |
| 61 | k -= 25; |
| 62 | x *= 0x1.0p25; |
| 63 | ix = @bitCast(x); |
| 64 | } else if (ix >= 0x7F800000) { |
| 65 | return x; |
| 66 | } else if (ix == 0x3F800000) { |
| 67 | return 0; |
| 68 | } |
| 69 | |
| 70 | // x into [sqrt(2) / 2, sqrt(2)] |
| 71 | ix += 0x3F800000 - 0x3F3504F3; |
| 72 | k += @as(i32, @intCast(ix >> 23)) - 0x7F; |
| 73 | ix = (ix & 0x007FFFFF) + 0x3F3504F3; |
| 74 | x = @bitCast(ix); |
| 75 | |
| 76 | const f = x - 1.0; |
| 77 | const s = f / (2.0 + f); |
| 78 | const z = s * s; |
| 79 | const w = z * z; |
| 80 | const t1 = w * (Lg2 + w * Lg4); |
| 81 | const t2 = z * (Lg1 + w * Lg3); |
| 82 | const R = t2 + t1; |
| 83 | const hfsq = 0.5 * f * f; |
| 84 | |
| 85 | var hi = f - hfsq; |
| 86 | u = @bitCast(hi); |
| 87 | u &= 0xFFFFF000; |
| 88 | hi = @bitCast(u); |
| 89 | const lo = f - hi - hfsq + s * (hfsq + R); |
| 90 | return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + @as(f32, @floatFromInt(k)); |
| 91 | } |
| 92 | |
| 93 | fn log2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { |
| 94 | return compiler_rt.f64.toAbi(log2_f64(compiler_rt.f64.fromAbi(a))); |
| 95 | } |
| 96 | pub fn log2_f64(x_: f64) f64 { |
| 97 | const ivln2hi: f64 = 1.44269504072144627571e+00; |
| 98 | const ivln2lo: f64 = 1.67517131648865118353e-10; |
| 99 | const Lg1: f64 = 6.666666666666735130e-01; |
| 100 | const Lg2: f64 = 3.999999999940941908e-01; |
| 101 | const Lg3: f64 = 2.857142874366239149e-01; |
| 102 | const Lg4: f64 = 2.222219843214978396e-01; |
| 103 | const Lg5: f64 = 1.818357216161805012e-01; |
| 104 | const Lg6: f64 = 1.531383769920937332e-01; |
| 105 | const Lg7: f64 = 1.479819860511658591e-01; |
| 106 | |
| 107 | var x = x_; |
| 108 | var ix: u64 = @bitCast(x); |
| 109 | var hx: u32 = @intCast(ix >> 32); |
| 110 | var k: i32 = 0; |
| 111 | |
| 112 | if (hx < 0x00100000 or hx >> 31 != 0) { |
| 113 | // log(+-0) = -inf |
| 114 | if (ix << 1 == 0) { |
| 115 | return if (compiler_rt.want_float_exceptions) -1 / (x * x) else -std.math.inf(f64); |
| 116 | } |
| 117 | // log(-#) = nan |
| 118 | if (hx >> 31 != 0) { |
| 119 | return if (compiler_rt.want_float_exceptions) (x - x) / 0.0 else math.nan(f64); |
| 120 | } |
| 121 | |
| 122 | // subnormal, scale x |
| 123 | k -= 54; |
| 124 | x *= 0x1.0p54; |
| 125 | hx = @intCast(@as(u64, @bitCast(x)) >> 32); |
| 126 | } else if (hx >= 0x7FF00000) { |
| 127 | return x; |
| 128 | } else if (hx == 0x3FF00000 and ix << 32 == 0) { |
| 129 | return 0; |
| 130 | } |
| 131 | |
| 132 | // x into [sqrt(2) / 2, sqrt(2)] |
| 133 | hx += 0x3FF00000 - 0x3FE6A09E; |
| 134 | k += @as(i32, @intCast(hx >> 20)) - 0x3FF; |
| 135 | hx = (hx & 0x000FFFFF) + 0x3FE6A09E; |
| 136 | ix = (@as(u64, hx) << 32) | (ix & 0xFFFFFFFF); |
| 137 | x = @bitCast(ix); |
| 138 | |
| 139 | const f = x - 1.0; |
| 140 | const hfsq = 0.5 * f * f; |
| 141 | const s = f / (2.0 + f); |
| 142 | const z = s * s; |
| 143 | const w = z * z; |
| 144 | const t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); |
| 145 | const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); |
| 146 | const R = t2 + t1; |
| 147 | |
| 148 | // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f) |
| 149 | var hi = f - hfsq; |
| 150 | var hii = @as(u64, @bitCast(hi)); |
| 151 | hii &= @as(u64, maxInt(u64)) << 32; |
| 152 | hi = @bitCast(hii); |
| 153 | const lo = f - hi - hfsq + s * (hfsq + R); |
| 154 | |
| 155 | var val_hi = hi * ivln2hi; |
| 156 | var val_lo = (lo + hi) * ivln2lo + lo * ivln2hi; |
| 157 | |
| 158 | // spadd(val_hi, val_lo, y) |
| 159 | const y: f64 = @floatFromInt(k); |
| 160 | const ww = y + val_hi; |
| 161 | val_lo += (y - ww) + val_hi; |
| 162 | val_hi = ww; |
| 163 | |
| 164 | return val_lo + val_hi; |
| 165 | } |
| 166 | |
| 167 | fn __log2x(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { |
| 168 | return compiler_rt.f80.toAbi(log2_f80(compiler_rt.f80.fromAbi(a))); |
| 169 | } |
| 170 | pub fn log2_f80(a: f80) f80 { |
| 171 | // TODO: more efficient implementation |
| 172 | return @floatCast(log2_f128(a)); |
| 173 | } |
| 174 | |
| 175 | fn log2q(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { |
| 176 | return compiler_rt.f128.toAbi(log2_f128(compiler_rt.f128.fromAbi(a))); |
| 177 | } |
| 178 | /// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic" |
| 179 | /// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990 |
| 180 | /// |
| 181 | /// https://dl.acm.org/doi/pdf/10.1145/98267.98294 |
| 182 | /// |
| 183 | /// Adapted to work for f128 and base 2 by Christophe Delage. |
| 184 | /// |
| 185 | /// Accuracy on 100 million random numbers in [0, inf) (exponent uniformly random) |
| 186 | /// <= 0.5 ulp: 99.99%, worst case <= 0.594 ulp |
| 187 | /// |
| 188 | /// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case): |
| 189 | /// <= 0.5 ulp: 99.86%, worst case <= 0.546 ulp |
| 190 | pub fn log2_f128(x: f128) f128 { |
| 191 | const impl = @import("log_f128.zig"); |
| 192 | |
| 193 | if (impl.specialCases(x)) |y| |
| 194 | return y; |
| 195 | |
| 196 | if (impl.Proc2.lo < x and x < impl.Proc2.hi) { |
| 197 | // Polynomial approximation of log2((1 + u / 2) / (1 - u / 2)) |
| 198 | // in [2 * a / (2 + a), 2 * b / (2 + b)] |
| 199 | // where a = exp(-1 / 16) - 1 and b = exp(1 / 16) - 1 |
| 200 | const poly: impl.Proc2.Poly = .{ |
| 201 | .b1_hi = 0x1.71547652b82fep0, |
| 202 | .b1_lo = 0x1.777d0ffda0d23a7d11d6aef551bbp-56, |
| 203 | .b3 = 0.12022458674074695061332705675016125, |
| 204 | .b5 = 1.8033688011112042591999058475816515e-2, |
| 205 | .b7 = 3.2203014305557218914285331735164364e-3, |
| 206 | .b9 = 6.261697226080570342191671010883619e-4, |
| 207 | .b11 = 1.280801705334664325639770412440281e-4, |
| 208 | .b13 = 2.7093882228102330360125035037716968e-5, |
| 209 | .b15 = 5.870341197214724685339102193694838e-6, |
| 210 | .b17 = 1.294917697032820750200161813672143e-6, |
| 211 | .b19 = 2.909291439731657940692470637735429e-7, |
| 212 | }; |
| 213 | return impl.proc2(.{ .poly = poly }, x); |
| 214 | } |
| 215 | |
| 216 | // Polynomial approximation of log2(1 + 2 * u / (2 - u)) |
| 217 | // in [-(2 * fmax) / (2 + fmax), (2 * fmax) / (2 - fmax)] |
| 218 | // where fmax = 0.5 / size |
| 219 | const poly: impl.Proc1.Poly = .{ |
| 220 | .a1 = 1.442695040888963407359924681001892, |
| 221 | .a3 = 0.12022458674074695061332705675072149, |
| 222 | .a5 = 1.8033688011112042591998536830294507e-2, |
| 223 | .a7 = 3.22030143055572204818095463930704e-3, |
| 224 | .a9 = 6.261697225875019234719395591078697e-4, |
| 225 | .a11 = 1.280813940786848788109850061222256e-4, |
| 226 | }; |
| 227 | // tab[j].hi = 2^-n * round-to-integer(2^n * l) |
| 228 | // tab[j].lo = round-to-nearest-f128(l - tab[j].hi) |
| 229 | // where n = 97 and l = log2(1 + j / size) |
| 230 | const tab = [impl.size + 1]impl.Proc1.HiLo{ |
| 231 | .{ .hi = 0, .lo = 0 }, |
| 232 | .{ .hi = 0x1.6fe50b6ef08517f8e37bp-7, .lo = 0x1.794f4441ccdf648f265a41e57d75p-99 }, |
| 233 | .{ .hi = 0x1.6e79685c2d2298a6e27e212p-6, .lo = -0x1.fbd41ae7d5a2434912ad3fe21cfbp-100 }, |
| 234 | .{ .hi = 0x1.11cd1d5133412ed814504fbp-5, .lo = -0x1.b2e2b43254008aeb4167a3359577p-99 }, |
| 235 | .{ .hi = 0x1.6bad3758efd87313606f097p-5, .lo = -0x1.20fbdb7ce4c86d28e4be331fce17p-99 }, |
| 236 | .{ .hi = 0x1.c4dfab90aab5ef4f8f869e6p-5, .lo = 0x1.dc4142bd2b182fdaac375356fc29p-100 }, |
| 237 | .{ .hi = 0x1.0eb389fa29f9ab3cf74bab98p-4, .lo = 0x1.9217066b9150f3c7ddd223517be7p-100 }, |
| 238 | .{ .hi = 0x1.3aa2fdd27f1c2d804d1121b8p-4, .lo = -0x1.acec4ac95b97a0e1d121d0222ba5p-99 }, |
| 239 | .{ .hi = 0x1.663f6fac913167ccc5382618p-4, .lo = -0x1.dd4529e1ad7c182a716c033db6dep-99 }, |
| 240 | .{ .hi = 0x1.918a16e46335aae7232494d8p-4, .lo = 0x1.9d1d19046b227370f7cb86bd9e3ep-99 }, |
| 241 | .{ .hi = 0x1.bc84240adabba63b2c5a6e5p-4, .lo = 0x1.97ab879641c50810e3b820ca9aap-100 }, |
| 242 | .{ .hi = 0x1.e72ec117fa5b21cbdb5d9dcp-4, .lo = 0x1.4f902752a1dc5b384b68c4f1e669p-99 }, |
| 243 | .{ .hi = 0x1.08c588cda79e39627bc6fd0cp-3, .lo = -0x1.aad7542b0c4015f8fdff17d7ea79p-99 }, |
| 244 | .{ .hi = 0x1.1dcd197552b7b5ea45430784p-3, .lo = -0x1.a7aa295e08add52f96d8aaf3b8edp-101 }, |
| 245 | .{ .hi = 0x1.32ae9e278ae1a1f51f2c075cp-3, .lo = -0x1.8b459b26ac0ed3b39116e44d50c8p-99 }, |
| 246 | .{ .hi = 0x1.476a9f983f74d3138e941644p-3, .lo = -0x1.27d822a49870762eeaffdcde52bdp-104 }, |
| 247 | .{ .hi = 0x1.5c01a39fbd6879fa00b120ap-3, .lo = 0x1.a2eb74493cf9a8e8966c101ef964p-101 }, |
| 248 | .{ .hi = 0x1.70742d4ef027f29c01cfad78p-3, .lo = -0x1.8495d6ca3b2dcc7941a5df4c8decp-103 }, |
| 249 | .{ .hi = 0x1.84c2bd02f03b2fdd2248ee78p-3, .lo = -0x1.c56a8f0829344b50240232cdb09ep-99 }, |
| 250 | .{ .hi = 0x1.98edd077e70df02face8ca9p-3, .lo = 0x1.72b7f2fcb409899d29e3feaf9c8fp-99 }, |
| 251 | .{ .hi = 0x1.acf5e2db4ec93efe11ecbcp-3, .lo = 0x1.83634b52082beea143f1178aaf62p-99 }, |
| 252 | .{ .hi = 0x1.c0db6cdd94dee40e26d9899cp-3, .lo = 0x1.fde86bd82482b9b4a45aa674cc1bp-100 }, |
| 253 | .{ .hi = 0x1.d49ee4c32596fc8f4b565024p-3, .lo = -0x1.7eaef901f52d2d54011ca95ecca1p-101 }, |
| 254 | .{ .hi = 0x1.e840be74e6a4cc7c9f3d51ep-3, .lo = -0x1.03c7c0d8554c2c17f944fa1f93cfp-99 }, |
| 255 | .{ .hi = 0x1.fbc16b902680a23a8d998a78p-3, .lo = 0x1.3bcd7c933d5bb6b52a41ad567d8ep-101 }, |
| 256 | .{ .hi = 0x1.0790adbb030096f031a699d6p-2, .lo = -0x1.748a4ccf5e3dadf04bd0ff35f885p-99 }, |
| 257 | .{ .hi = 0x1.11307dad30b75cb09705a796p-2, .lo = -0x1.6c580f988c64f00bd800ed9b9d24p-100 }, |
| 258 | .{ .hi = 0x1.1ac05b291f070528c7386df8p-2, .lo = 0x1.94340c3b639a4e5a59fded67fcb7p-99 }, |
| 259 | .{ .hi = 0x1.24407ab0e07398245b94ba44p-2, .lo = 0x1.8077f77a0f4353b19301384099dap-99 }, |
| 260 | .{ .hi = 0x1.2db10fc4d9aaf6f137a3d8c6p-2, .lo = 0x1.e79b8ee38b380b8be44e090558d7p-99 }, |
| 261 | .{ .hi = 0x1.37124cea4cdecd991336c96p-2, .lo = 0x1.fb9186e41376f4612d4b0b9a507dp-100 }, |
| 262 | .{ .hi = 0x1.406463b1b044975b2f344252p-2, .lo = 0x1.9a92f79c803c5151cb25af73b143p-101 }, |
| 263 | .{ .hi = 0x1.49a784bcd1b8afe492bf6ff4p-2, .lo = 0x1.b5fb699b2d8abfc6f675a9d236d6p-99 }, |
| 264 | .{ .hi = 0x1.52dbdfc4c96b37dcf60e61fcp-2, .lo = 0x1.36a5977bbf78792b6a99ccb74cd5p-99 }, |
| 265 | .{ .hi = 0x1.5c01a39fbd6879fa00b120ap-2, .lo = 0x1.a2eb74493cf9a8e8966c101ef964p-100 }, |
| 266 | .{ .hi = 0x1.6518fe4677ba6e52278edc8ap-2, .lo = -0x1.6778b4ba074a8ce60972502c7262p-102 }, |
| 267 | .{ .hi = 0x1.6e221cd9d0cde578d520b45p-2, .lo = -0x1.1f87779b03b7d7e6bd0493f2e147p-99 }, |
| 268 | .{ .hi = 0x1.771d2ba7efb3be46fecd5122p-2, .lo = 0x1.29ff1c3c9184a53c236eed64d17ep-100 }, |
| 269 | .{ .hi = 0x1.800a563161c5432aeb609f4ep-2, .lo = -0x1.0a6ee4f4272036db2b8f6963d1c4p-103 }, |
| 270 | .{ .hi = 0x1.88e9c72e0b225a4b664a4c8ep-2, .lo = -0x1.59153bc13892380cd03989062763p-100 }, |
| 271 | .{ .hi = 0x1.91bba891f1708b4b2b5056b8p-2, .lo = 0x1.a7156185dba8beba3cb180b37bbbp-100 }, |
| 272 | .{ .hi = 0x1.9a802391e232f34bb6d0e43ap-2, .lo = -0x1.67caee1e30b7c2d6ff9893868aa6p-99 }, |
| 273 | .{ .hi = 0x1.a33760a7f60509d7c40d797ap-2, .lo = -0x1.3a4e0233ff8ac31bd7b2cb5c0041p-102 }, |
| 274 | .{ .hi = 0x1.abe18797f1f48e1a4725558cp-2, .lo = 0x1.6f5c786e3d2aafcee056debabb79p-100 }, |
| 275 | .{ .hi = 0x1.b47ebf73882a0a4146ef8fd8p-2, .lo = 0x1.44f1d5b8a5402f72138cbfe19e49p-99 }, |
| 276 | .{ .hi = 0x1.bd0f2e9e79030ab442ce3202p-2, .lo = -0x1.d27aeb2ddd02924cf83def704a7bp-99 }, |
| 277 | .{ .hi = 0x1.c592fad295b567e7ee54aefp-2, .lo = -0x1.99e7587ea99e677177c285c32088p-99 }, |
| 278 | .{ .hi = 0x1.ce0a4923a587cc95d0a2ee7ap-2, .lo = 0x1.6482ae04295539bf0ed23f498b8ap-104 }, |
| 279 | .{ .hi = 0x1.d6753e032ea0efe3ebe19906p-2, .lo = -0x1.55594a060c67a245f78bb523ad43p-99 }, |
| 280 | .{ .hi = 0x1.ded3fd442364c4ebb196116p-2, .lo = -0x1.df9689b34ee848b0b7818878492cp-99 }, |
| 281 | .{ .hi = 0x1.e726aa1e754d20c519e12f48p-2, .lo = -0x1.dd99950bae450ac5754344a16faep-99 }, |
| 282 | .{ .hi = 0x1.ef6d67328e2207d1e01a839p-2, .lo = 0x1.04907f9ccddb53ed88c47c7d794cp-100 }, |
| 283 | .{ .hi = 0x1.f7a8568cb06cece193180046p-2, .lo = -0x1.e149b9528336d5fee3ef52260ad1p-99 }, |
| 284 | .{ .hi = 0x1.ffd799a83ff9ab9cc7f342f8p-2, .lo = 0x1.70c458bda55b08c8c8668867736bp-99 }, |
| 285 | .{ .hi = 0x1.03fda8b97997f33943464056p-1, .lo = 0x1.eb47cb2aadd948d48bbef492995ep-99 }, |
| 286 | .{ .hi = 0x1.0809cf27f703d525b3c1d158p-1, .lo = 0x1.f51e170ccb0f7761e5ff9b93854ep-100 }, |
| 287 | .{ .hi = 0x1.0c10500d63aa6588257529b6p-1, .lo = 0x1.2ef0aa83f2869dd6be1d1cc2dc47p-100 }, |
| 288 | .{ .hi = 0x1.10113b153c8ea7b1cddae6fbp-1, .lo = -0x1.8d4296259492a32f8b327d46339p-100 }, |
| 289 | .{ .hi = 0x1.140c9faa1e5439e15a52a316p-1, .lo = 0x1.29611295daec3b07655c599a50e7p-103 }, |
| 290 | .{ .hi = 0x1.18028cf72976a4eb8e97d145p-1, .lo = 0x1.9ac318308c388b1f2e108f3d37bep-100 }, |
| 291 | .{ .hi = 0x1.1bf311e95d00de3b513a9dcdp-1, .lo = -0x1.3c8ff1c1539554d1f10759819adp-100 }, |
| 292 | .{ .hi = 0x1.1fde3d30e812642415d47384p-1, .lo = 0x1.3c458dd53d12c99743f3c4617c37p-99 }, |
| 293 | .{ .hi = 0x1.23c41d42727c8080ecc61a99p-1, .lo = -0x1.fb113740031e528bbef9ead829c7p-99 }, |
| 294 | .{ .hi = 0x1.27a4c0585cbf805784ee0e3bp-1, .lo = -0x1.60c515c0f4b1772f673312a17eep-101 }, |
| 295 | .{ .hi = 0x1.2b803473f7ad0f3f40162414p-1, .lo = 0x1.a2eb74493cf9a8e8966c101ef964p-102 }, |
| 296 | .{ .hi = 0x1.2f56875eb3f2614278cd1699p-1, .lo = 0x1.88c5d320344f129c318704371e3dp-100 }, |
| 297 | .{ .hi = 0x1.3327c6ab49ca6c86b9205fa4p-1, .lo = 0x1.1010939e6edc060bf80459dd880dp-100 }, |
| 298 | .{ .hi = 0x1.36f3ffb6d9162404772a151dp-1, .lo = -0x1.93193dd58663d90eed123bda5ea2p-100 }, |
| 299 | .{ .hi = 0x1.3abb3faa02166cccab240e9p-1, .lo = 0x1.3e5a84738c6a548017167cabbd62p-99 }, |
| 300 | .{ .hi = 0x1.3e7d9379f70166ae2a7ada55p-1, .lo = 0x1.6369ad81817bfeddee4a96320fd3p-100 }, |
| 301 | .{ .hi = 0x1.423b07e986aa9670761d14abp-1, .lo = -0x1.d93cd9e77a527017a3e16237ddd4p-100 }, |
| 302 | .{ .hi = 0x1.45f3a98a20738a4d7ffe0267p-1, .lo = 0x1.75541c775be89f0841ae8379c6adp-100 }, |
| 303 | .{ .hi = 0x1.49a784bcd1b8afe492bf6ff5p-1, .lo = -0x1.2812599349d500e4262958b724aap-100 }, |
| 304 | .{ .hi = 0x1.4d56a5b33cec44a6deff9987p-1, .lo = 0x1.fad1e37de08f5e02036d27593a4p-100 }, |
| 305 | .{ .hi = 0x1.510118708a8f8dde949378b2p-1, .lo = 0x1.348f1454e8c939a60252b34c6c66p-100 }, |
| 306 | .{ .hi = 0x1.54a6e8ca5438db1b0ca63aacp-1, .lo = -0x1.2f1784ce0b08724e7f04c9712103p-99 }, |
| 307 | .{ .hi = 0x1.5848226989d33c38d8bd28d7p-1, .lo = -0x1.a8e7bb5885dce30d5e9e8139d7b1p-99 }, |
| 308 | .{ .hi = 0x1.5be4d0cb51434aaeb3f01222p-1, .lo = 0x1.2ce7e40053a5cfc072e22bbeab1dp-100 }, |
| 309 | .{ .hi = 0x1.5f7cff41e09aeb8cb1ac05cdp-1, .lo = -0x1.4fb2c4a0dc9f7b2e29701f76805bp-100 }, |
| 310 | .{ .hi = 0x1.6310b8f553048406a5a171dep-1, .lo = 0x1.003332544881b92584a992692c7dp-99 }, |
| 311 | .{ .hi = 0x1.66a008e4788cbcd2edb4390ep-1, .lo = 0x1.4c1a88f0e7a41e948033b63cbaadp-99 }, |
| 312 | .{ .hi = 0x1.6a2af9e5a0f0a08099572f21p-1, .lo = -0x1.0665eae13d10b498acfb49ce0dep-99 }, |
| 313 | .{ .hi = 0x1.6db196a761949d97df07e357p-1, .lo = -0x1.7679e5a1e4a0e0dbeb3195d40b4dp-99 }, |
| 314 | .{ .hi = 0x1.7133e9b156c7be5167fbdc81p-1, .lo = 0x1.b935e716c7cb214a0b718fc30587p-100 }, |
| 315 | .{ .hi = 0x1.74b1fd64e0753c6e5783fd15p-1, .lo = 0x1.923a7aefc37ef9baffdf4ec86923p-102 }, |
| 316 | .{ .hi = 0x1.782bdbfdda6577bc87e125ebp-1, .lo = -0x1.56e82c9d846f9e967e496249719bp-99 }, |
| 317 | .{ .hi = 0x1.7ba18f93502e409eab77f21ap-1, .lo = -0x1.c097ea4900b7ca9ea124a56a0c75p-100 }, |
| 318 | .{ .hi = 0x1.7f1322182cf15d12ecd77fe7p-1, .lo = -0x1.0512c0ac2d3510c6f5fd964c2ae2p-99 }, |
| 319 | .{ .hi = 0x1.82809d5be7072dbdc0426c3cp-1, .lo = 0x1.3a309736edbb3eae70d10c173b0bp-100 }, |
| 320 | .{ .hi = 0x1.85ea0b0b27b261086fce864ap-1, .lo = 0x1.f5979367f112e34dbc4e07ae924cp-101 }, |
| 321 | .{ .hi = 0x1.894f74b06ef8b406ea2c7d92p-1, .lo = -0x1.54ede83a0018a21469a1f11911aep-99 }, |
| 322 | .{ .hi = 0x1.8cb0e3b4b3bbdb3688a85fb2p-1, .lo = -0x1.910d207f019516331134b0c9d172p-99 }, |
| 323 | .{ .hi = 0x1.900e6160002ccfe43f50847dp-1, .lo = 0x1.82887e54848c7603fba7d2ba264ap-101 }, |
| 324 | .{ .hi = 0x1.9367f6da0ab2e9cc865b3dd1p-1, .lo = -0x1.225541e18baff32be2709a01f861p-100 }, |
| 325 | .{ .hi = 0x1.96bdad2acb5f5efec4915314p-1, .lo = 0x1.b7c0b9db2fcb23be56be998e8e8fp-99 }, |
| 326 | .{ .hi = 0x1.9a0f8d3b0e04fde95734abd3p-1, .lo = -0x1.9f19ce27d2dca3979bbb0ca9365fp-104 }, |
| 327 | .{ .hi = 0x1.9d5d9fd5010b366655920748p-1, .lo = 0x1.3e5a84738c6a548017167cabbd62p-100 }, |
| 328 | .{ .hi = 0x1.a0a7eda4c112ce6312ebb81dp-1, .lo = -0x1.5a727dbaad60b1bf6bcd429e9fdfp-102 }, |
| 329 | .{ .hi = 0x1.a3ee7f38e181ed0798d1aa21p-1, .lo = 0x1.a51584c9dc5627ac1ab989c42834p-99 }, |
| 330 | .{ .hi = 0x1.a7315d02f20c7bd560a3fee1p-1, .lo = -0x1.dacbac02cace034400340f2319ddp-99 }, |
| 331 | .{ .hi = 0x1.aa708f58014d37cde37c86b2p-1, .lo = 0x1.06a19b5bedec4594babbdab2fd2p-100 }, |
| 332 | .{ .hi = 0x1.adac1e711c832d1562d61af7p-1, .lo = 0x1.fbfa94970bb9fab077c80ac91e28p-100 }, |
| 333 | .{ .hi = 0x1.b0e4126bcc86bd7a6ed4e1b1p-1, .lo = -0x1.b28c4122d931f14daa7bc7cc5b07p-99 }, |
| 334 | .{ .hi = 0x1.b418734a9008bd978b98f7dfp-1, .lo = -0x1.039d32863d2685d1b265e993decbp-100 }, |
| 335 | .{ .hi = 0x1.b74948f5532da4b4b7143364p-1, .lo = -0x1.ce44c707d13d9c8e8a9007c6ffb4p-99 }, |
| 336 | .{ .hi = 0x1.ba769b39e49640ef87ede14bp-1, .lo = -0x1.735f3571b2e44add58e787eb935ep-101 }, |
| 337 | .{ .hi = 0x1.bda071cc67e6db516de08136p-1, .lo = 0x1.b4d5660336e288cea5ceba447906p-99 }, |
| 338 | .{ .hi = 0x1.c0c6d447c5dd362d9a9a55c7p-1, .lo = 0x1.17b370ba83c0155dfdf1fd11696ep-99 }, |
| 339 | .{ .hi = 0x1.c3e9ca2e1a05533698b4e49bp-1, .lo = 0x1.ec0c07c38978823235b0f583d7a7p-99 }, |
| 340 | .{ .hi = 0x1.c7095ae91e1c760bc9b188c4p-1, .lo = 0x1.322631fb315aaf4da97307d1076bp-99 }, |
| 341 | .{ .hi = 0x1.ca258dca9331635fee390c0bp-1, .lo = -0x1.3e17e7a7e746edea65e0c4e7d82dp-99 }, |
| 342 | .{ .hi = 0x1.cd3e6a0ca8906c243749114cp-1, .lo = 0x1.2bbae931e8daa670e214b298ab12p-99 }, |
| 343 | .{ .hi = 0x1.d053f6d2608967318975dc0ep-1, .lo = 0x1.ea58d8245529f4e409432bd61602p-99 }, |
| 344 | .{ .hi = 0x1.d3663b27f31d5297837adb4bp-1, .lo = -0x1.38daa2d672ec54842668a312854dp-100 }, |
| 345 | .{ .hi = 0x1.d6753e032ea0efe3ebe19905p-1, .lo = 0x1.554d6bf3e730bb7410e895b8a57ap-99 }, |
| 346 | .{ .hi = 0x1.d9810643d6614c3c406eb464p-1, .lo = 0x1.05d328adc61c09915e038a135bdfp-99 }, |
| 347 | .{ .hi = 0x1.dc899ab3ff56c5e673abad44p-1, .lo = 0x1.8c6339fa7bd10d27c064978bc6f5p-100 }, |
| 348 | .{ .hi = 0x1.df8f02086af2c4bef483c68bp-1, .lo = -0x1.0baa11f1460aebb8f273d9820bc8p-99 }, |
| 349 | .{ .hi = 0x1.e29142e0e01401fbaaa67e3cp-1, .lo = -0x1.d6541223b8314593546e23de0435p-100 }, |
| 350 | .{ .hi = 0x1.e59063c8822ce561911a9bacp-1, .lo = 0x1.9b0de815b6fb0c41cac421925a11p-99 }, |
| 351 | .{ .hi = 0x1.e88c6b3626a72aa21a3c7f02p-1, .lo = -0x1.0e3aeafe4f838b64e3bde351d0f1p-102 }, |
| 352 | .{ .hi = 0x1.eb855f8ca88fb0d4b5c673bbp-1, .lo = 0x1.1db401cf29698d7b00a45b6d1082p-102 }, |
| 353 | .{ .hi = 0x1.ee7b471b3a9507d6dc1f27efp-1, .lo = 0x1.21f23cd188a03f54e360fd76a481p-99 }, |
| 354 | .{ .hi = 0x1.f16e281db76303b21928c216p-1, .lo = -0x1.2854f795db443461c5e7233e545fp-102 }, |
| 355 | .{ .hi = 0x1.f45e08bcf06554e4d5be4f7p-1, .lo = 0x1.07e81f4c1573947a3126425d9d0ap-99 }, |
| 356 | .{ .hi = 0x1.f74aef0efafadd7a1b65f639p-1, .lo = -0x1.7bc1e9882648a6b530fa4d847e3fp-100 }, |
| 357 | .{ .hi = 0x1.fa34e1177c23362928b9ed75p-1, .lo = -0x1.856dc2b529ad698bfda1e41b89bdp-101 }, |
| 358 | .{ .hi = 0x1.fd1be4c7f2af942b221ce0d1p-1, .lo = 0x1.a275c854f5bb9732fae5130be48bp-104 }, |
| 359 | .{ .hi = 0x1p0, .lo = 0 }, |
| 360 | }; |
| 361 | return impl.proc1(.{ .poly = poly, .tab = tab }, x); |
| 362 | } |
| 363 | |
| 364 | pub fn log2l(x: c_longdouble) callconv(.c) c_longdouble { |
| 365 | switch (@typeInfo(c_longdouble).float.bits) { |
| 366 | 64 => return log2_f64(x), |
| 367 | 80 => return log2_f80(x), |
| 368 | 128 => return log2_f128(x), |
| 369 | else => comptime unreachable, |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | test "log2f() special" { |
| 374 | try expectEqual(log2_f32(0.0), -math.inf(f32)); |
| 375 | try expectEqual(log2_f32(-0.0), -math.inf(f32)); |
| 376 | try expect(math.isPositiveZero(log2_f32(1.0))); |
| 377 | try expectEqual(log2_f32(2.0), 1.0); |
| 378 | try expectEqual(log2_f32(math.inf(f32)), math.inf(f32)); |
| 379 | try expect(math.isNan(log2_f32(-1.0))); |
| 380 | try expect(math.isNan(log2_f32(-math.inf(f32)))); |
| 381 | try expect(math.isNan(log2_f32(math.nan(f32)))); |
| 382 | try expect(math.isNan(log2_f32(math.snan(f32)))); |
| 383 | } |
| 384 | |
| 385 | test "log2f() sanity" { |
| 386 | try expect(math.isNan(log2_f32(-0x1.0223a0p+3))); |
| 387 | try expectEqual(log2_f32(0x1.161868p+2), 0x1.0f49acp+1); |
| 388 | try expect(math.isNan(log2_f32(-0x1.0c34b4p+3))); |
| 389 | try expect(math.isNan(log2_f32(-0x1.a206f0p+2))); |
| 390 | try expectEqual(log2_f32(0x1.288bbcp+3), 0x1.9b2676p+1); |
| 391 | try expectEqual(log2_f32(0x1.52efd0p-1), -0x1.30b494p-1); // Disagrees with GCC in last bit |
| 392 | try expect(math.isNan(log2_f32(-0x1.a05cc8p-2))); |
| 393 | try expectEqual(log2_f32(0x1.1f9efap-1), -0x1.a9f89ap-1); |
| 394 | try expectEqual(log2_f32(0x1.8c5db0p-1), -0x1.7a2c96p-2); |
| 395 | try expect(math.isNan(log2_f32(-0x1.5b86eap-1))); |
| 396 | } |
| 397 | |
| 398 | test "log2f() boundary" { |
| 399 | try expectEqual(log2_f32(0x1.fffffep+127), 0x1p+7); // Max input value |
| 400 | try expectEqual(log2_f32(0x1p-149), -0x1.2ap+7); // Min positive input value |
| 401 | try expect(math.isNan(log2_f32(-0x1p-149))); // Min negative input value |
| 402 | try expectEqual(log2_f32(0x1.000002p+0), 0x1.715474p-23); // Last value before result reaches +0 |
| 403 | try expectEqual(log2_f32(0x1.fffffep-1), -0x1.715478p-24); // Last value before result reaches -0 |
| 404 | try expectEqual(log2_f32(0x1p-126), -0x1.f8p+6); // First subnormal |
| 405 | try expect(math.isNan(log2_f32(-0x1p-126))); // First negative subnormal |
| 406 | |
| 407 | } |
| 408 | |
| 409 | test "log2() special" { |
| 410 | try expectEqual(log2_f64(0.0), -math.inf(f64)); |
| 411 | try expectEqual(log2_f64(-0.0), -math.inf(f64)); |
| 412 | try expect(math.isPositiveZero(log2_f64(1.0))); |
| 413 | try expectEqual(log2_f64(2.0), 1.0); |
| 414 | try expectEqual(log2_f64(math.inf(f64)), math.inf(f64)); |
| 415 | try expect(math.isNan(log2_f64(-1.0))); |
| 416 | try expect(math.isNan(log2_f64(-math.inf(f64)))); |
| 417 | try expect(math.isNan(log2_f64(math.nan(f64)))); |
| 418 | try expect(math.isNan(log2_f64(math.snan(f64)))); |
| 419 | } |
| 420 | |
| 421 | test "log2() sanity" { |
| 422 | try expect(math.isNan(log2_f64(-0x1.02239f3c6a8f1p+3))); |
| 423 | try expectEqual(log2_f64(0x1.161868e18bc67p+2), 0x1.0f49ac3838580p+1); |
| 424 | try expect(math.isNan(log2_f64(-0x1.0c34b3e01e6e7p+3))); |
| 425 | try expect(math.isNan(log2_f64(-0x1.a206f0a19dcc4p+2))); |
| 426 | try expectEqual(log2_f64(0x1.288bbb0d6a1e6p+3), 0x1.9b26760c2a57ep+1); |
| 427 | try expectEqual(log2_f64(0x1.52efd0cd80497p-1), -0x1.30b490ef684c7p-1); |
| 428 | try expect(math.isNan(log2_f64(-0x1.a05cc754481d1p-2))); |
| 429 | try expectEqual(log2_f64(0x1.1f9ef934745cbp-1), -0x1.a9f89b5f5acb8p-1); |
| 430 | try expectEqual(log2_f64(0x1.8c5db097f7442p-1), -0x1.7a2c947173f06p-2); |
| 431 | try expect(math.isNan(log2_f64(-0x1.5b86ea8118a0ep-1))); |
| 432 | } |
| 433 | |
| 434 | test "log2() boundary" { |
| 435 | try expectEqual(log2_f64(0x1.fffffffffffffp+1023), 0x1p+10); // Max input value |
| 436 | try expectEqual(log2_f64(0x1p-1074), -0x1.0c8p+10); // Min positive input value |
| 437 | try expect(math.isNan(log2_f64(-0x1p-1074))); // Min negative input value |
| 438 | try expectEqual(log2_f64(0x1.0000000000001p+0), 0x1.71547652b82fdp-52); // Last value before result reaches +0 |
| 439 | try expectEqual(log2_f64(0x1.fffffffffffffp-1), -0x1.71547652b82fep-53); // Last value before result reaches -0 |
| 440 | try expectEqual(log2_f64(0x1p-1022), -0x1.ffp+9); // First subnormal |
| 441 | try expect(math.isNan(log2_f64(-0x1p-1022))); // First negative subnormal |
| 442 | } |
| 443 | |
| 444 | test "log2q() special" { |
| 445 | try expectEqual(log2_f128(0.0), -math.inf(f128)); |
| 446 | try expectEqual(log2_f128(-0.0), -math.inf(f128)); |
| 447 | try expect(math.isPositiveZero(log2_f128(1.0))); |
| 448 | try expectEqual(log2_f128(2.0), 1.0); |
| 449 | try expectEqual(log2_f128(math.inf(f128)), math.inf(f128)); |
| 450 | try expect(math.isNan(log2_f128(-1.0))); |
| 451 | try expect(math.isNan(log2_f128(-math.inf(f128)))); |
| 452 | try expect(math.isNan(log2_f128(math.nan(f128)))); |
| 453 | try expect(math.isNan(log2_f128(math.snan(f128)))); |
| 454 | } |
| 455 | |
| 456 | test "log2q() boundary" { |
| 457 | try expectEqual(log2_f128(0x1.ffffffffffffffffffffffffffffp16383), 0x1p14); // Max input value |
| 458 | try expectEqual(log2_f128(0x1p-16494), -0x1.01b8p14); // Min positive input value |
| 459 | try expect(math.isNan(log2_f128(-0x1p-16494))); // Min negative input value |
| 460 | try expectEqual(log2_f128(0x1.0000000000000000000000000001p0), 0x1.71547652b82fe1777d0ffda0d23ap-112); // Last value before result reaches +0 |
| 461 | try expectEqual(log2_f128(0x1.ffffffffffffffffffffffffffffp-1), -0x1.71547652b82fe1777d0ffda0d23bp-113); // Last value before result reaches -0 |
| 462 | try expectEqual(log2_f128(0x1p-16382), -0x1.fffp13); // First subnormal |
| 463 | try expect(math.isNan(log2_f128(-0x1p-16382))); // First negative subnormal |
| 464 | } |
| 465 | |
| 466 | test "log2q() sanity" { |
| 467 | try expectEqual(log2_f128(8.0965013884643408203125e11), 3.955850767769801288865582596068254e1); |
| 468 | try expectEqual(log2_f128(8.346531942223744e15), 5.28900982928636641107356163006646e1); |
| 469 | try expectEqual(log2_f128(9.707809913413123613777865431464565e-20), -6.315941603809020445822192336703809e1); |
| 470 | try expectEqual(log2_f128(1.9179565888043380306021427656243352e-24), -7.878670421065570557450089031998522e1); |
| 471 | try expectEqual(log2_f128(2.5260048200126556877075044745936796e-25), -8.17113449801679676275805009400338e1); |
| 472 | try expectEqual(log2_f128(3.1170134002568967640399932861328125e7), 2.489366102143423848582774267206741e1); |
| 473 | // test near 1 |
| 474 | try expectEqual(log2_f128(1.026586845186097528392910049888087e0), 3.7855678902522753591699367969189364e-2); |
| 475 | try expectEqual(log2_f128(1.0005582850578053877743656130405725e0), 8.052103367568488432896147152682078e-4); |
| 476 | try expectEqual(log2_f128(1.0370174103591254835765589348284266e0), 5.244011558596899945639244281954306e-2); |
| 477 | try expectEqual(log2_f128(1.0429996503525671713075162472250667e0), 6.073867421942172944687194557176633e-2); |
| 478 | try expectEqual(log2_f128(1.0383384027961064621892184334228659e0), 5.4276706191956281784022630732940314e-2); |
| 479 | } |