commit 748e7c5e39fcba3ed6b2b6e4cc4c01e1d442acbe (tree)
parent 7be3b1de455c9cf247dc3ab8c4fd75c9b16d77cf
Author: Andrew Kelley <andrew@ziglang.org>
Date: Mon, 1 Jun 2026 00:39:03 +0200
Merge pull request 'compiler_rt: f128 support for @log, @log2 and @log10' (#35532) from chocapix/zig:log-f128 into master
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35532
Reviewed-by: Andrew Kelley <andrew@ziglang.org>
Diffstat:
4 files changed, 852 insertions(+), 9 deletions(-)
diff --git a/lib/compiler_rt/log.zig b/lib/compiler_rt/log.zig
@@ -8,6 +8,7 @@ const std = @import("std");
const math = std.math;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
+const expectApproxEqRel = std.testing.expectApproxEqRel;
const compiler_rt = @import("../compiler_rt.zig");
const symbol = @import("../compiler_rt.zig").symbol;
@@ -436,9 +437,191 @@ pub fn __logx(a: f80) callconv(.c) f80 {
return @floatCast(logq(a));
}
-pub fn logq(a: f128) callconv(.c) f128 {
- // TODO: more correct implementation
- return log(@floatCast(a));
+/// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic"
+/// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990
+///
+/// https://dl.acm.org/doi/pdf/10.1145/98267.98294
+///
+/// Adapted to work for f128 by Christophe Delage.
+///
+/// Accuracy on 100 million random numbers in [0, inf) (exponent uniformly random)
+/// <= 0.5 ulp: 99.99%, worst case <= 0.530 ulp
+///
+/// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case):
+/// <= 0.5 ulp: 99.96%, worst case <= 0.528 ulp
+pub fn logq(x: f128) callconv(.c) f128 {
+ const impl = @import("log_f128.zig");
+
+ if (impl.specialCases(x)) |y|
+ return y;
+
+ if (impl.Proc2.lo < x and x < impl.Proc2.hi) {
+ // Polynomial approximation of log((1 + u / 2) / (1 - u / 2))
+ // in [2 * a / (2 + a), 2 * b / (2 + b)]
+ // where a = exp(-1 / 16) - 1 and b = exp(1 / 16) - 1
+ const poly: impl.Proc2.Poly = .{
+ .b1_hi = 1.0,
+ .b1_lo = 0.0,
+ .b3 = 8.333333333333333333333333333333581e-2,
+ .b5 = 1.249999999999999999999999997455655e-2,
+ .b7 = 2.2321428571428571428572328745789477e-3,
+ .b9 = 4.340277777777777776216500817402857e-4,
+ .b11 = 8.87784090909092440759545734146088e-5,
+ .b13 = 1.8780048076832339308077858301484127e-5,
+ .b15 = 4.069010449774280288178309893970754e-6,
+ .b17 = 8.97568550755477160981619052649713e-7,
+ .b19 = 2.0165671588771827537210411918018159e-7,
+ };
+ return impl.proc2(.{ .poly = poly }, x);
+ }
+
+ // Polynomial approximation of log(1 + 2 * u / (2 - u))
+ // in [-(2 * fmax) / (2 + fmax), (2 * fmax) / (2 - fmax)]
+ // where fmax = 0.5 / size
+ const poly: impl.Proc1.Poly = .{
+ .a1 = 1.0,
+ .a3 = 8.333333333333333333333333333372414e-2,
+ .a5 = 1.249999999999999999999963839743372e-2,
+ .a7 = 2.2321428571428572515097318595359542e-3,
+ .a9 = 4.340277777635300605611118803507141e-4,
+ .a11 = 8.877925718782769769445565656611838e-5,
+ };
+
+ // tab[j].hi = 2^-n * round-to-integer(2^n * l)
+ // tab[j].lo = round-to-nearest-f128(l - tab[j].hi)
+ // where n = 97 and l = log(1 + j / size)
+ const tab = [impl.size + 1]impl.Proc1.HiLo{
+ .{ .hi = 0, .lo = 0 },
+ .{ .hi = 0x1.fe02a6b106788fc3769039p-8, .lo = 0x1.dc282d2b3db2c3ef9a073a876702p-100 },
+ .{ .hi = 0x1.fc0a8b0fc03e3cf9eda74d4p-7, .lo = -0x1.0a8552414fc416fc223acca2ebfp-100 },
+ .{ .hi = 0x1.7b91b07d5b11aa927f54c72p-6, .lo = -0x1.287fc46561dfab5bc5cceecb4882p-99 },
+ .{ .hi = 0x1.f829b0e7833004cf8fc13c8p-6, .lo = -0x1.0dd605151051eb3220ca52e20939p-100 },
+ .{ .hi = 0x1.39e87b9febd5fa9015b202bp-5, .lo = -0x1.1bac6e550a3c3dc859cfe2e178a8p-99 },
+ .{ .hi = 0x1.77458f632dcfc4634f2a1eep-5, .lo = 0x1.2960b1e4dfb80d9544ec6583eb3ap-99 },
+ .{ .hi = 0x1.b42dd711971bec28d14c7dap-5, .lo = -0x1.2645ad50c7672fc0eb08d862221dp-102 },
+ .{ .hi = 0x1.f0a30c01162a6617cc9716fp-5, .lo = -0x1.4cd0ece597165991495b4d31cf5cp-101 },
+ .{ .hi = 0x1.16536eea37ae0e8625c173ep-4, .lo = -0x1.66d0dc92deb7d2ccbd2caa9640cap-99 },
+ .{ .hi = 0x1.341d7961bd1d092998376108p-4, .lo = -0x1.976457ef2f89ad243dcc3578cf7ep-99 },
+ .{ .hi = 0x1.51b073f06183f69278e686ap-4, .lo = 0x1.7c8ac25e4e3f04de1f086f5cb4b1p-99 },
+ .{ .hi = 0x1.6f0d28ae56b4b9be499b9edp-4, .lo = 0x1.9b640ce50c1ef65087fdf23812f4p-100 },
+ .{ .hi = 0x1.8c345d6319b20f5acb42a66p-4, .lo = -0x1.254bca8fd9fc1bf283b3b4b8662dp-100 },
+ .{ .hi = 0x1.a926d3a4ad563650bd22a9cp-4, .lo = 0x1.d5263cd4fb3f11769cc680ef5589p-99 },
+ .{ .hi = 0x1.c5e548f5bc74315d617ef818p-4, .lo = -0x1.e4e896269950723c88d353ee9c18p-100 },
+ .{ .hi = 0x1.e27076e2af2e5e9ea87ffe2p-4, .lo = -0x1.61eaa246b143bfe80906a822f768p-104 },
+ .{ .hi = 0x1.fec9131dbeabaaa2e5199f9p-4, .lo = 0x1.9271dff48f15d409017630a93931p-99 },
+ .{ .hi = 0x1.0d77e7cd08e596697717a40cp-3, .lo = 0x1.574712132d3f6340e183be2031c6p-102 },
+ .{ .hi = 0x1.1b72ad52f67a029060468e58p-3, .lo = 0x1.ae73f3bc7ec84ca997609536a037p-99 },
+ .{ .hi = 0x1.29552f81ff5234c05dc7102p-3, .lo = -0x1.20b2ef60436f8f081d60452c9fc1p-100 },
+ .{ .hi = 0x1.371fc201e8f743bcd96c55e4p-3, .lo = -0x1.d80d17e0cd92558ad6fcd608bb1bp-100 },
+ .{ .hi = 0x1.44d2b6ccb7d1e67d3d950f88p-3, .lo = -0x1.e1f3be9a83374584faad83fa4fecp-103 },
+ .{ .hi = 0x1.526e5e3a1b437a2e401d6e3cp-3, .lo = 0x1.6334db798c76a888aa87317b14f8p-100 },
+ .{ .hi = 0x1.5ff3070a793d3c873e20a074p-3, .lo = -0x1.edc45019551c65501060ce71fa98p-99 },
+ .{ .hi = 0x1.6d60fe719d21c8d54765c4ccp-3, .lo = -0x1.790e412e6d3ed18e4a7c22362e49p-101 },
+ .{ .hi = 0x1.7ab890210d9091be36b2d6ap-3, .lo = 0x1.820191ff8525362042cad5d8c597p-101 },
+ .{ .hi = 0x1.87fa06520c910902009017dcp-3, .lo = 0x1.32ef5a55704b6b7eb4ebea28a6cdp-100 },
+ .{ .hi = 0x1.9525a9cf456b47641307538cp-3, .lo = -0x1.da62766be8258611d132d71d84acp-101 },
+ .{ .hi = 0x1.a23bc1fe2b563193711b07a8p-3, .lo = 0x1.98c27e3f1b66d8b32de61c04cf95p-99 },
+ .{ .hi = 0x1.af3c94e80bff2d8ce601937cp-3, .lo = 0x1.9eb976769b8b9a5d50ca14a7622fp-100 },
+ .{ .hi = 0x1.bc286742d8cd629f9ce890ep-3, .lo = 0x1.ea9e1e2c3dca46c83cd6d19e5e9bp-99 },
+ .{ .hi = 0x1.c8ff7c79a9a21ac25d81ef3p-3, .lo = -0x1.1976d471342b17dca47c9d1e1d98p-105 },
+ .{ .hi = 0x1.d5c216b4fbb915b910d65f94p-3, .lo = -0x1.5ff1e1c98c2ed4063968ad2332f8p-100 },
+ .{ .hi = 0x1.e27076e2af2e5e9ea87ffe2p-3, .lo = -0x1.61eaa246b143bfe80906a822f768p-103 },
+ .{ .hi = 0x1.ef0adcbdc59365218de5437p-3, .lo = 0x1.06429f5a5098683a47c3a3ca5835p-100 },
+ .{ .hi = 0x1.fb9186d5e3e2a8d55466c378p-3, .lo = 0x1.4d2ca09202c222ad91640bd8b2fcp-99 },
+ .{ .hi = 0x1.0402594b4d040dae27bd0b6p-2, .lo = -0x1.16a1bbb899f343f105ee37cafa25p-100 },
+ .{ .hi = 0x1.0a324e27390e35f73f7a0188p-2, .lo = -0x1.fe78eb90fe52820fb4690e4910e3p-99 },
+ .{ .hi = 0x1.1058bf9ae4ad5189fa0ab4ccp-2, .lo = -0x1.9c60f598d3a32076376a5960e735p-99 },
+ .{ .hi = 0x1.1675cababa60e039cc7d571p-2, .lo = 0x1.b8b823f067d04a43c19f534c3c8ep-100 },
+ .{ .hi = 0x1.1c898c16999fafbc68e75404p-2, .lo = -0x1.c443cc477d114a1350a26c9b5535p-100 },
+ .{ .hi = 0x1.22941fbcf7965a242853da76p-2, .lo = -0x1.5e685a2caa590b0f13a31703b136p-101 },
+ .{ .hi = 0x1.2895a13de86a35eb49304fc2p-2, .lo = -0x1.f8d3a52b8aa6834f50a903b31253p-99 },
+ .{ .hi = 0x1.2e8e2bae11d309c2cc91a85p-2, .lo = 0x1.03679bdbbd6b7d91378a909a6793p-99 },
+ .{ .hi = 0x1.347dd9a987d54d645674fedcp-2, .lo = 0x1.821ee510a580b3b30ef57f83ca28p-99 },
+ .{ .hi = 0x1.3a64c556945e9c72f35cd74p-2, .lo = 0x1.a11beb7a3cee7e029e46e1334dfep-99 },
+ .{ .hi = 0x1.404308686a7e3bd0c127df4cp-2, .lo = 0x1.92985641827d9d91a2da0d4f2207p-100 },
+ .{ .hi = 0x1.4618bc21c5ec27d0b7b37b34p-2, .lo = -0x1.c65df511a65b67fe9778d8694229p-101 },
+ .{ .hi = 0x1.4be5f957778a0db4c9949f7p-2, .lo = -0x1.3cdc28d5974f3185a1f581529353p-101 },
+ .{ .hi = 0x1.51aad872df82d09c93d60cfap-2, .lo = 0x1.5e311d4f4f357cbfae095f10fcd3p-99 },
+ .{ .hi = 0x1.5767717455a6c549ab6ca0dap-2, .lo = -0x1.f42ff0747cbcce6c0841fd7ceb87p-100 },
+ .{ .hi = 0x1.5d1bdbf5809ca508d8e0f72p-2, .lo = -0x1.eea60c7f4b594bd65b44f6b20634p-104 },
+ .{ .hi = 0x1.62c82f2b9c7952f6f5f22a6p-2, .lo = 0x1.ca2e7226c55dd257f44b5002c8cdp-102 },
+ .{ .hi = 0x1.686c81e9b14aec442be1014ep-2, .lo = 0x1.c34b25bdbda38672b32ca47f535dp-101 },
+ .{ .hi = 0x1.6e08eaa2ba1e38c139318d72p-2, .lo = -0x1.07a1f9d2a3058cd3f047b933d485p-99 },
+ .{ .hi = 0x1.739d7f6bbd0069ce24c53faep-2, .lo = -0x1.8210d2a910f7918ad34542221b6cp-99 },
+ .{ .hi = 0x1.792a55fdd47a27c15da47fa8p-2, .lo = -0x1.297ea603cd10e7c702842a1590aep-100 },
+ .{ .hi = 0x1.7eaf83b82afc364b3a5e7b4ap-2, .lo = 0x1.50437160cbfcbf71ee8d4b3cd067p-100 },
+ .{ .hi = 0x1.842d1da1e8b17493b1465e12p-2, .lo = -0x1.899770fb9eb8e0c7f06a12cd88c3p-100 },
+ .{ .hi = 0x1.89a3386c1425ab5a71881104p-2, .lo = -0x1.f549800739afc97f5d4b9c15fc12p-101 },
+ .{ .hi = 0x1.8f11e873662c77e1769d5698p-2, .lo = 0x1.a29979cbfcbc0e45410ee8ca0d17p-100 },
+ .{ .hi = 0x1.947941c2116faba4cdd147d2p-2, .lo = -0x1.f22a2b6b19ed11af82f2c0e6730ep-99 },
+ .{ .hi = 0x1.99d958117e08acba92eec478p-2, .lo = 0x1.8dfba4bb71c95f44a3225b5d8f8fp-101 },
+ .{ .hi = 0x1.9f323ecbf984bf2b68d766f4p-2, .lo = 0x1.4886067d20ffb34547d7c2b38ad8p-104 },
+ .{ .hi = 0x1.a484090e5bb0a2bfca6b70ecp-2, .lo = -0x1.62da6c6290af3949ca12eb97e6bbp-99 },
+ .{ .hi = 0x1.a9cec9a9a08498d484ff52f2p-2, .lo = 0x1.50d7be11fc8ee26768c44e9f35aap-100 },
+ .{ .hi = 0x1.af1293247786b1133844a15ep-2, .lo = -0x1.ebf9e3b2fb68378f9b7aa0ef6685p-101 },
+ .{ .hi = 0x1.b44f77bcc8f628cbeedaae98p-2, .lo = 0x1.c3c779029d5a684301e7888d5449p-99 },
+ .{ .hi = 0x1.b9858969310fb598fb14f88ep-2, .lo = 0x1.e1cf79039d5a31010282d8264afap-99 },
+ .{ .hi = 0x1.beb4d9da71b7bf7861d37abcp-2, .lo = -0x1.f29b495a7c83dffb9899ad6da116p-101 },
+ .{ .hi = 0x1.c3dd7a7cdad4d73b3c14b7aap-2, .lo = -0x1.649f44ae71a827ebf6601862d429p-100 },
+ .{ .hi = 0x1.c8ff7c79a9a21ac25d81ef3p-2, .lo = -0x1.1976d471342b17dca47c9d1e1d98p-104 },
+ .{ .hi = 0x1.ce1af0b85f3eb7b7d2bcaadp-2, .lo = 0x1.33a4e218c8c00b2f6f2b23998791p-99 },
+ .{ .hi = 0x1.d32fe7e00ebd561dec8cbebep-2, .lo = 0x1.1b7e8c55a6ffaf7eb72c1ff893cdp-99 },
+ .{ .hi = 0x1.d83e7258a2f3e50515ba2ecap-2, .lo = -0x1.7778ad7b599f3edc40a13fe57cp-99 },
+ .{ .hi = 0x1.dd46a04c1c4a0bee626a49d2p-2, .lo = -0x1.23c02c15f2f66328a06054db5e01p-101 },
+ .{ .hi = 0x1.e24881a7c6c261cbd8f45954p-2, .lo = 0x1.48c6c5403df1764e1ed219643a85p-99 },
+ .{ .hi = 0x1.e744261d68787e37da36f3ccp-2, .lo = -0x1.2e44bfb5e71d55a11feaedf56a94p-100 },
+ .{ .hi = 0x1.ec399d2468cc0175cee53f36p-2, .lo = -0x1.8d2027bb4681af8a138d77633327p-99 },
+ .{ .hi = 0x1.f128f5faf06ecb35c83b1132p-2, .lo = -0x1.851461536ddd17ac271709c2b464p-101 },
+ .{ .hi = 0x1.f6123fa7028ac61456c3cb6cp-2, .lo = 0x1.a0a432a2414cc0b049c0fb73b4dep-99 },
+ .{ .hi = 0x1.faf588f78f31ed9afb3e4ea8p-2, .lo = 0x1.afec6d4cde2ef184dc7b6e634ba1p-100 },
+ .{ .hi = 0x1.ffd2e0857f4985597d0364c8p-2, .lo = 0x1.af246e3379d3ea68e29866b3b38bp-100 },
+ .{ .hi = 0x1.02552a5a5d0fec69c695d7eep-1, .lo = 0x1.fff1a3725c5c6261a75dc4f512adp-99 },
+ .{ .hi = 0x1.04bdf9da926d265fcc1008b2p-1, .lo = 0x1.df6a6d08e4470f10c7053f04f1ep-99 },
+ .{ .hi = 0x1.0723e5c1cdf404e579638911p-1, .lo = 0x1.baad95bd2eba9089087bae740509p-99 },
+ .{ .hi = 0x1.0986f4f573520b91fda94ff4p-1, .lo = 0x1.fe038113f135a26389f13c4bde3ap-100 },
+ .{ .hi = 0x1.0be72e4252a82b69897bb33ep-1, .lo = -0x1.9649bc990440ca2c12ee56f6c90bp-108 },
+ .{ .hi = 0x1.0e44985d1cc8bf6eae5de969p-1, .lo = 0x1.8f8d1fbacf70a2da185e84859e36p-99 },
+ .{ .hi = 0x1.109f39e2d4c96fde3ec9b0b8p-1, .lo = -0x1.b9d06df4e0c8337c0da8f63aefc7p-99 },
+ .{ .hi = 0x1.12f719593efbc53012319c7dp-1, .lo = 0x1.a96893b2757f50123379aecd147cp-102 },
+ .{ .hi = 0x1.154c3d2f4d5e9a98f33a3966p-1, .lo = -0x1.d7f56258b99e197c61c0a23b2403p-101 },
+ .{ .hi = 0x1.179eabbd899a0bfc60e6fa08p-1, .lo = -0x1.68f2a71c8279b89eb8392b7a41ep-100 },
+ .{ .hi = 0x1.19ee6b467c96ecc5cbdd7782p-1, .lo = -0x1.0c2a8ef8715f93d3c8e2c9016713p-100 },
+ .{ .hi = 0x1.1c3b81f713c24bc94f8ecdfcp-1, .lo = -0x1.d103880b3dc864d107231c87eaa7p-100 },
+ .{ .hi = 0x1.1e85f5e7040d03dec59a5f3ep-1, .lo = 0x1.e35f2e7ca4f4817696ad39f9a4b2p-100 },
+ .{ .hi = 0x1.20cdcd192ab6d93503d0f75cp-1, .lo = -0x1.3db0bb5bf2b76be256c1a2a08a8p-103 },
+ .{ .hi = 0x1.23130d7bebf4282de368722dp-1, .lo = -0x1.6dfadc7219019f05279c9cfd2b08p-99 },
+ .{ .hi = 0x1.2555bce98f7cb3c043adad1p-1, .lo = 0x1.e71084750a06eb301ae8308feca1p-100 },
+ .{ .hi = 0x1.2795e1289b11aeb783f3db97p-1, .lo = -0x1.e3801fe56c1467b5e622105c5e41p-99 },
+ .{ .hi = 0x1.29d37fec2b08ac85cd6cba5dp-1, .lo = -0x1.824a2f303e0aa6995ef5598cc5b7p-100 },
+ .{ .hi = 0x1.2c0e9ed448e8bb97a9c31ba3p-1, .lo = -0x1.8676adfad5c83dea45d7349693e3p-99 },
+ .{ .hi = 0x1.2e47436e4026840542186922p-1, .lo = 0x1.ab1252cf29452c88ebc5ce2f36f2p-101 },
+ .{ .hi = 0x1.307d7334f10be1fb590a1f56p-1, .lo = 0x1.b66f70c05b80999c08cdd48a021p-99 },
+ .{ .hi = 0x1.32b1339121d71320556b67b2p-1, .lo = 0x1.6b06715ba133462ddf94bde6b3a5p-100 },
+ .{ .hi = 0x1.34e289d9ce1d316eb92d885dp-1, .lo = -0x1.b151b59c44058fa92837dec71351p-101 },
+ .{ .hi = 0x1.37117b54747b5c5dd024844ep-1, .lo = -0x1.037076a726793d7e93c9b2f3eef6p-100 },
+ .{ .hi = 0x1.393e0d3562a19a9c4426036ep-1, .lo = -0x1.cf1c277a3a0d863fefb367ef8616p-102 },
+ .{ .hi = 0x1.3b68449fffc22af8edec1859p-1, .lo = 0x1.b341d6de6d9b9591a54790d29adcp-100 },
+ .{ .hi = 0x1.3d9026a7156faa404263d0adp-1, .lo = 0x1.3cf6b809d96954adf1ff9360bd04p-100 },
+ .{ .hi = 0x1.3fb5b84d16f425b4e9d505cbp-1, .lo = -0x1.110c9bd8986629a5a46a5834774cp-99 },
+ .{ .hi = 0x1.41d8fe84672ae6464bcc2f46p-1, .lo = 0x1.779538890dd44eadeb32e848f817p-105 },
+ .{ .hi = 0x1.43f9fe2f9ce677a727b9b60fp-1, .lo = -0x1.e6927c891167a0306333dca3b8a4p-101 },
+ .{ .hi = 0x1.4618bc21c5ec27d0b7b37b34p-1, .lo = -0x1.c65df511a65b67fe9778d8694229p-100 },
+ .{ .hi = 0x1.48353d1ea88df73d5e8bb302p-1, .lo = -0x1.7b4f3e104187cc8aca358d9263f9p-104 },
+ .{ .hi = 0x1.4a4f85db03ebb0227bf47a6fp-1, .lo = -0x1.e49ce91908e6e2750b818bba40e6p-100 },
+ .{ .hi = 0x1.4c679afccee39b168ecdd318p-1, .lo = 0x1.bf619db0d889bbe38f559618dbd3p-99 },
+ .{ .hi = 0x1.4e7d811b75bb09cb09856458p-1, .lo = 0x1.5770d0c5ebca2047bba2c9ee4f52p-99 },
+ .{ .hi = 0x1.50913cc01686b4bcb3a5b0b5p-1, .lo = 0x1.b0f69791cf6c54c4e5d96f1d584fp-99 },
+ .{ .hi = 0x1.52a2d265bc5aaee77c8af15bp-1, .lo = 0x1.7aea7bed0920f6a4c39b31ea388bp-100 },
+ .{ .hi = 0x1.54b2467999497a915428b43ep-1, .lo = -0x1.f434bb5d154a84758a2a5033748cp-99 },
+ .{ .hi = 0x1.56bf9d5b3f399411c6217364p-1, .lo = -0x1.a6323ea9ce40a3caf6baebad2c64p-104 },
+ .{ .hi = 0x1.58cadb5cd79893092f25d931p-1, .lo = -0x1.d3d5761cff2a6a51ddc9c241881cp-99 },
+ .{ .hi = 0x1.5ad404c359f2cfb29aaa5f02p-1, .lo = 0x1.cd40845839e04578161ccf77753bp-100 },
+ .{ .hi = 0x1.5cdb1dc6c17648cf6e3c5d71p-1, .lo = -0x1.f3a84fed7a8e6b8a7923783c6bf7p-99 },
+ .{ .hi = 0x1.5ee02a924167570d6095fd24p-1, .lo = 0x1.03ef4c629f04ae4e7a29309e6688p-100 },
+ .{ .hi = 0x1.60e32f44788d8ca7c895a0b5p-1, .lo = -0x1.3557995d063914a66aa81ead3fdbp-101 },
+ .{ .hi = 0x1.62e42fefa39ef35793c7673p-1, .lo = 0x1.f97b57a079a193394c5b16c5068cp-103 },
+ };
+ return impl.proc1(.{ .poly = poly, .tab = tab }, x);
}
pub fn logl(x: c_longdouble) callconv(.c) c_longdouble {
@@ -519,3 +702,47 @@ test "log() boundary" {
try expectEqual(log(0x1p-1022), -0x1.6232bdd7abcd2p+9); // First subnormal
try expect(math.isNan(log(-0x1p-1022))); // First negative subnormal
}
+
+test "logq() special" {
+ try expectEqual(logq(0.0), -math.inf(f128));
+ try expectEqual(logq(-0.0), -math.inf(f128));
+ try expect(math.isPositiveZero(logq(1.0)));
+ // Sadly, the rounding gods decided that 0.9999999999999999999999999999999999
+ // is the correctly rounded value of logq(math.e)
+ try expectApproxEqRel(logq(math.e), 1.0, math.floatEpsAt(f128, 1.0));
+ try expectEqual(logq(math.inf(f128)), math.inf(f128));
+ try expect(math.isNan(logq(-1.0)));
+ try expect(math.isNan(logq(-math.inf(f128))));
+ try expect(math.isNan(logq(math.nan(f128))));
+ try expect(math.isNan(logq(math.snan(f128))));
+}
+
+test "logq() boundary" {
+ try expectEqual(logq(0x1.ffffffffffffffffffffffffffffp16383), 0x1.62e42fefa39ef35793c7673007e6p13); // Max input value
+ try expectEqual(logq(0x1p-16494), -0x1.6546282207802c89d24d65e96274p13); // Min positive input value
+ try expect(math.isNan(logq(-0x1p-16494))); // Min negative input value
+ try expectEqual(logq(0x1.0000000000000000000000000001p0), 0x1.ffffffffffffffffffffffffffffp-113); // Last value before result reaches +0
+ try expectEqual(logq(0x1.ffffffffffffffffffffffffffffp-1), -0x1p-113); // Last value before result reaches -0
+ try expectEqual(logq(0x1p-16382), -0x1.62d918ce2421d65ff90ac8f4ce66p13); // First subnormal
+ try expect(math.isNan(logq(-0x1p-16382))); // First negative subnormal
+}
+
+test "logq() sanity" {
+ try expectEqual(logq(4.151135979023751199079583784623537e-4), -7.7869583453055243113993340258295346e0);
+ try expectEqual(logq(9.614234245933828353176667689130293e-14), -2.9972946567656004014786271559909435e1);
+ try expectEqual(logq(1.012889803704721484375e13), 2.9946413646144315985379677542014356e1);
+ try expectEqual(logq(2.397741857206453154086912e24), 5.613656963346284538829358703465392e1);
+ try expectEqual(logq(3.442377567808290806386655232e27), 6.3405959896920645453203836625419693e1);
+ try expectEqual(logq(1.0689155158234028407981544637594257e-8), -1.835403614606774451014272772421113e1);
+ try expectEqual(logq(1.4813913545768791536741499811327596e-10), -2.263286917934202003739900705050399e1);
+ try expectEqual(logq(4.518948965781299591064453125e10), 2.453413036705097282892685629562292e1);
+ try expectEqual(logq(1.200355637363589375e14), 3.2418809179272977400408325788186897e1);
+ try expectEqual(logq(6.6145398293682003021240234375e9), 2.261253606737223221601998075023261e1);
+ try expectEqual(logq(5.16179116383965741056e20), 4.7692985503915646405875629300054525e1);
+ // testing near 1
+ try expectEqual(logq(1.026586845186097528392910049888087e0), 2.6239557099466251374193777672800004e-2);
+ try expectEqual(logq(9.878220373715243107115568932385941e-1), -1.2252721576456821219120474521538944e-2);
+ try expectEqual(logq(9.417921077517196685541245315675951e-1), -5.997072116986790367958922503195352e-2);
+ try expectEqual(logq(1.043095786320424537962914257605007e0), 4.219300911769055080390811808602425e-2);
+ try expectEqual(logq(1.019043049323190694932517175175235e0), 1.8863999985309781522599012445793722e-2);
+}
diff --git a/lib/compiler_rt/log10.zig b/lib/compiler_rt/log10.zig
@@ -170,9 +170,191 @@ pub fn __log10x(a: f80) callconv(.c) f80 {
return @floatCast(log10q(a));
}
-pub fn log10q(a: f128) callconv(.c) f128 {
- // TODO: more correct implementation
- return log10(@floatCast(a));
+/// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic"
+/// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990
+///
+/// https://dl.acm.org/doi/pdf/10.1145/98267.98294
+///
+/// Adapted to work for f128 and base 10 by Christophe Delage.
+///
+/// Accuracy on 100 million random numbers in [0, inf) (exponent uniformly random)
+/// <= 0.5 ulp: 99.99%, worst case 0.591 <= ulp
+///
+/// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case):
+/// <= 0.5 ulp: 99.96%, worst case <= 0.565 ulp
+pub fn log10q(x: f128) callconv(.c) f128 {
+ const impl = @import("log_f128.zig");
+
+ if (impl.specialCases(x)) |y|
+ return y;
+
+ if (impl.Proc2.lo < x and x < impl.Proc2.hi) {
+ // Polynomial approximation of log10((1 + u / 2) / (1 - u / 2))
+ // in [2 * a / (2 + a), 2 * b / (2 + b)]
+ // where a = exp(-1 / 16) - 1 and b = exp(1 / 16) - 1
+ const poly: impl.Proc2.Poly = .{
+ .b1_hi = 0x1.bcb7b1526e50ep-2,
+ .b1_lo = 0x1.95355baaafad33dc323ee3460246p-57,
+ .b3 = 3.619120682527098563759407657638483e-2,
+ .b5 = 5.428681023790647845639111475407614e-3,
+ .b7 = 9.694073256769014010070232880860484e-4,
+ .b9 = 1.8849586888161971679466375197398104e-4,
+ .b11 = 3.855597318033137224139238937796866e-5,
+ .b13 = 8.156071249646061672592451832809541e-6,
+ .b15 = 1.7671487851436387503930903139882346e-6,
+ .b17 = 3.898090687230025454479255130305971e-7,
+ .b19 = 8.757839894876785986064901881670424e-8,
+ };
+ return impl.proc2(.{ .poly = poly }, x);
+ }
+
+ // Polynomial approximation of log10(1 + 2 * u / (2 - u))
+ // in [-(2 * fmax) / (2 + fmax), (2 * fmax) / (2 - fmax)]
+ // where fmax = 0.5 / size
+ const poly: impl.Proc1.Poly = .{
+ .a1 = 0.4342944819032518276511289189166051,
+ .a3 = 3.619120682527098563759407657655348e-2,
+ .a5 = 5.428681023790647845638954444458386e-3,
+ .a7 = 9.694073256769014481942040422515466e-4,
+ .a9 = 1.884958688754320118955531917460363e-4,
+ .a11 = 3.8556341504143175800053507804546873e-5,
+ };
+
+ // log1p_tab[j].hi = 2^-n * round-to-integer(2^n * l)
+ // log1p_tab[j].lo = round-to-nearest-f128(l - log1p_tab[j].hi)
+ // where n = 97 and l = log10(1 + j / size)
+ const tab = [impl.size + 1]impl.Proc1.HiLo{
+ .{ .hi = 0, .lo = 0 },
+ .{ .hi = 0x1.bafd47221ed2665c1ba949p-9, .lo = -0x1.eb6f20a90ad48515635f3b8a1d22p-104 },
+ .{ .hi = 0x1.b9476a4fcd10ed89b5a417p-8, .lo = 0x1.0b153c94bfd2527c3dce31e5e226p-100 },
+ .{ .hi = 0x1.49b0851443683ce1bf0b26p-7, .lo = -0x1.a16199f2b1be9a7a84e03b9c38c2p-99 },
+ .{ .hi = 0x1.b5e908eb137900f974ff1b4p-7, .lo = -0x1.6bbc5e42b470cbc0ccc513d93932p-102 },
+ .{ .hi = 0x1.10a83a8446c77a1180aaf6p-6, .lo = -0x1.09ecab3c0cf83110cf07e44c289fp-101 },
+ .{ .hi = 0x1.45f4f5acb8be07769e25e96p-6, .lo = -0x1.0a58d59387d112136c57591afc6cp-99 },
+ .{ .hi = 0x1.7adc3df3b1ff81b980714c6p-6, .lo = -0x1.a572fb60daf72fbfab402e472463p-100 },
+ .{ .hi = 0x1.af5f92b00e60fa6de0a6da8p-6, .lo = -0x1.8335cd731aa841e5f6959299c961p-100 },
+ .{ .hi = 0x1.e3806acbd058f0d79f59da2p-6, .lo = 0x1.9ab1b88f11b4d4ea94e47e000ae6p-102 },
+ .{ .hi = 0x1.0ba01a81700002be3a8a48ap-5, .lo = -0x1.792eb9b5df590083e09dc0929a7p-101 },
+ .{ .hi = 0x1.25502c0fc314b801dad7dedp-5, .lo = 0x1.197c6c848f1b1ad18fd42fe32cb2p-99 },
+ .{ .hi = 0x1.3ed1199a5e425037527d748p-5, .lo = -0x1.c78118e73744326912f10c802895p-100 },
+ .{ .hi = 0x1.58238eeb353da7bf5153dfbp-5, .lo = -0x1.9663eec734789fdf5fb0469aa7eep-99 },
+ .{ .hi = 0x1.71483427d2a98ce1e11006p-5, .lo = 0x1.c4ea21ef8f4a97aa1e6e70df2d95p-101 },
+ .{ .hi = 0x1.8a3fadeb847f393aed3e7b6p-5, .lo = 0x1.098634c8ec2a09971ad607875b6ep-99 },
+ .{ .hi = 0x1.a30a9d609efe9c281982d7ep-5, .lo = -0x1.0a32db4c5564f07600c430a0057dp-102 },
+ .{ .hi = 0x1.bba9a058dfd841a9796c345p-5, .lo = -0x1.d9dd77e08e9e5f8d9f32d76bef47p-99 },
+ .{ .hi = 0x1.d41d5164facb3a0188eb21p-5, .lo = 0x1.0128f682aeb0fa34321a7e97187fp-101 },
+ .{ .hi = 0x1.ec6647eb5880847d0188c2dp-5, .lo = -0x1.5afb00d01e071acf1f55342436abp-100 },
+ .{ .hi = 0x1.02428c1f08015ea6bc2bc8cp-4, .lo = 0x1.5daed7d59e78eef0247b7ffb956ep-99 },
+ .{ .hi = 0x1.0e3d29d81165e62559618f2p-4, .lo = 0x1.9e819128f90a0d3db1dc752ed073p-99 },
+ .{ .hi = 0x1.1a23445501815c0cde7a7f08p-4, .lo = -0x1.3b49f3e8b2ed4310435ef8820defp-99 },
+ .{ .hi = 0x1.25f5215eb5949df2a5fb46b8p-4, .lo = 0x1.6f0f6ab32f3e61f26e9b3ac1bf9cp-101 },
+ .{ .hi = 0x1.31b3055c4711801b420b9b2p-4, .lo = 0x1.76e9002c845c3b127df25ba8db5bp-103 },
+ .{ .hi = 0x1.3d5d335c53178caf84eb229p-4, .lo = -0x1.c5c2844630017e0376c69ec1cacp-100 },
+ .{ .hi = 0x1.48f3ed1df48fb5e08483b68p-4, .lo = -0x1.7f13d7d43d84e36e36265eaea7bcp-101 },
+ .{ .hi = 0x1.5477731973e848790c13ee28p-4, .lo = -0x1.ebaaf88383e9199df31ecf871835p-99 },
+ .{ .hi = 0x1.5fe80488af4fca9254c0c638p-4, .lo = 0x1.15b76527b80b8500745623ee81e5p-99 },
+ .{ .hi = 0x1.6b45df6f3e2c9590e0d54c78p-4, .lo = -0x1.c495b5c030bcef16e4f8bb12e196p-100 },
+ .{ .hi = 0x1.769140a2526fc94ecf23d47p-4, .lo = 0x1.f1841f017a7f6e08b6413b02da64p-101 },
+ .{ .hi = 0x1.81ca63d05a449827184d3fd8p-4, .lo = -0x1.073284788f12d4768b8aae8dcde3p-99 },
+ .{ .hi = 0x1.8cf183886480c9b28b1f97ep-4, .lo = -0x1.13ada343a03c927e5baecee4f8dap-100 },
+ .{ .hi = 0x1.9806d9414a2097207328f768p-4, .lo = -0x1.213231346152bf08d830caaa52cap-100 },
+ .{ .hi = 0x1.a30a9d609efe9c281982d7ep-4, .lo = -0x1.0a32db4c5564f07600c430a0057dp-101 },
+ .{ .hi = 0x1.adfd07416be06fd76ea69ee8p-4, .lo = -0x1.2f27508996b3721df510fce30125p-101 },
+ .{ .hi = 0x1.b8de4d3ab3d97f5dc97fa3e8p-4, .lo = 0x1.94aec3c479e9b616ea5d5f658c63p-99 },
+ .{ .hi = 0x1.c3aea4a5c6efe9d1b9bf7b48p-4, .lo = -0x1.6e9cbad44d58c56e8ee013db4727p-100 },
+ .{ .hi = 0x1.ce6e41e463da4f487cfe37bp-4, .lo = 0x1.79fd0d2e29710fa19cd9b24bc4a6p-99 },
+ .{ .hi = 0x1.d91d5866aa99b8c5ecd85448p-4, .lo = -0x1.bcfa9ad8f74e8fb09b3e2aa21032p-101 },
+ .{ .hi = 0x1.e3bc1ab0e19fe3d562a53f08p-4, .lo = -0x1.4e4f16590dfef5c8d025ed120de1p-101 },
+ .{ .hi = 0x1.ee4aba610f2047109cc02088p-4, .lo = -0x1.b34ada47053c57f0573b320efb86p-99 },
+ .{ .hi = 0x1.f8c968346819084e03494e8p-4, .lo = -0x1.4b71b85b5d726a32292230bf611dp-99 },
+ .{ .hi = 0x1.019c2a064b486717a7668388p-3, .lo = -0x1.3af96cd84cdb4bb3072c0b2e5f3fp-104 },
+ .{ .hi = 0x1.06cbd67a6c3b65458c50fd8p-3, .lo = 0x1.840d79fca5a0c693c952fc0c42bap-103 },
+ .{ .hi = 0x1.0bf3d0937c41c3c2f40d06dcp-3, .lo = -0x1.27324307eb41430185683c421ffap-100 },
+ .{ .hi = 0x1.11142f0811356e473b0e4f78p-3, .lo = -0x1.49b0b103367c03cb49c3cc705e75p-99 },
+ .{ .hi = 0x1.162d082ac9d0f8e71a2f291p-3, .lo = -0x1.6d975e156bc06273b74fedb290b8p-99 },
+ .{ .hi = 0x1.1b3e71ec94f7abbbb3324a1p-3, .lo = -0x1.76cec8d0f75a398c7a1e37848466p-105 },
+ .{ .hi = 0x1.204881dee8777552c136a76p-3, .lo = -0x1.267ee5ddb2e8b583793d15630abcp-102 },
+ .{ .hi = 0x1.254b4d35e7d3c1d7958ffee8p-3, .lo = -0x1.aa823ea433ce74aca4dce2431023p-100 },
+ .{ .hi = 0x1.2a46e8ca7ba29955cdd7839p-3, .lo = -0x1.7eb9688bc0de799a1f9e3e37c715p-99 },
+ .{ .hi = 0x1.2f3b691c5a000be34bf081e8p-3, .lo = -0x1.563a5a16b595ce9bdbdfdb0cfa3ap-100 },
+ .{ .hi = 0x1.3428e2540096d3b633e04614p-3, .lo = 0x1.f1625e245d85bd4c99622577f507p-99 },
+ .{ .hi = 0x1.390f6844a0b83029d5524ca8p-3, .lo = 0x1.c6d3f5f5fe70cb3a00ca5d7bfe39p-100 },
+ .{ .hi = 0x1.3def0e6dfdf84ea10095aeacp-3, .lo = -0x1.7ddc01913fed4a930dc964e19d64p-99 },
+ .{ .hi = 0x1.42c7e7fe3fc01c5baa84ea84p-3, .lo = -0x1.b57aee43292c7c7883ba343c8c3bp-102 },
+ .{ .hi = 0x1.479a07d3b641142ca3a5b05p-3, .lo = 0x1.a7b00c679cb54b61ed4831123201p-100 },
+ .{ .hi = 0x1.4c65807e9333821962bd3978p-3, .lo = -0x1.5b7e31a62bc6bddb9dafc48b8763p-99 },
+ .{ .hi = 0x1.512a644296c3cb096f47256p-3, .lo = -0x1.8eec43b9a26313b25a668455ed84p-100 },
+ .{ .hi = 0x1.55e8c518b10f859bf0375048p-3, .lo = -0x1.6ec79e2221c7ef4d78001cfd92d9p-99 },
+ .{ .hi = 0x1.5aa0b4b0988f98f4b7b3557cp-3, .lo = -0x1.d36883ff38b16e03d088056210ap-101 },
+ .{ .hi = 0x1.5f52447255c924e6e695998p-3, .lo = -0x1.c9a1067c1f62163817e106dfbadep-101 },
+ .{ .hi = 0x1.63fd857fc49baa7c0cd1066cp-3, .lo = 0x1.4bef4a4a1c2f253a333d0447df04p-99 },
+ .{ .hi = 0x1.68a288b60b7fc2b622430e54p-3, .lo = 0x1.957d4ee20104a0c9e5e8e2451944p-105 },
+ .{ .hi = 0x1.6d415eaf0906a9ea9d132f18p-3, .lo = 0x1.c7e96850691a6d0789a335fcf1f2p-100 },
+ .{ .hi = 0x1.71da17c2b7e7fea4e079fe8p-3, .lo = -0x1.47eea7b2200159b5df6c05428549p-101 },
+ .{ .hi = 0x1.766cc40889e84a226ff02f0cp-3, .lo = 0x1.17c1270bcfda77828cfd78f80afp-100 },
+ .{ .hi = 0x1.7af97358b9e03ccb5c44891p-3, .lo = -0x1.0bc25f85f8a5b9ab4ff4e0ea0c82p-100 },
+ .{ .hi = 0x1.7f80354d9529f92f3616977cp-3, .lo = 0x1.c73d68ec26da004f63fb3e4ca71dp-99 },
+ .{ .hi = 0x1.84011944bcb752c5b9930008p-3, .lo = -0x1.390cb466745037a79007f790960ap-102 },
+ .{ .hi = 0x1.887c2e605e1189c603f25d9p-3, .lo = -0x1.3a2bdea0dd3c942f3b7415d59507p-99 },
+ .{ .hi = 0x1.8cf183886480c9b28b1f97ep-3, .lo = -0x1.13ada343a03c927e5baecee4f8dap-99 },
+ .{ .hi = 0x1.9161276ba29783a4f607cb8p-3, .lo = -0x1.0402e057ffccff9044bfb591e807p-99 },
+ .{ .hi = 0x1.95cb2880f45ba6eadb35485p-3, .lo = 0x1.cdd9e9ad6d4f6c05d3a33d86f1a8p-102 },
+ .{ .hi = 0x1.9a2f95085a45b927e6003904p-3, .lo = -0x1.7bfe1b2fef4f232ebdb4c1a0e13ep-99 },
+ .{ .hi = 0x1.9e8e7b0c0d4be203de57e9a4p-3, .lo = -0x1.7689e2fc0aa01cdfa7664b87a096p-100 },
+ .{ .hi = 0x1.a2e7e8618c2d24882a4f9de4p-3, .lo = 0x1.0ad7f222a9cb6cd7bc85f7f30ff5p-99 },
+ .{ .hi = 0x1.a73beaaaa22f38e04a37a21cp-3, .lo = 0x1.6fed007694a60b3a89d53c8a6096p-100 },
+ .{ .hi = 0x1.ab8a8f56677fc365b0e5a07cp-3, .lo = -0x1.5fd6e4c7bf48b677423f326e48dcp-101 },
+ .{ .hi = 0x1.afd3e3a23b6800f54642bb78p-3, .lo = 0x1.3d53b5cccabc35925c064d8b96fap-99 },
+ .{ .hi = 0x1.b417f49ab8806bc9543817ap-3, .lo = 0x1.19354df84685acaf5f6acdc7ba41p-103 },
+ .{ .hi = 0x1.b856cf1ca31056c3f6e26b74p-3, .lo = -0x1.bad52e70273c0d62c3c1c56dffcbp-100 },
+ .{ .hi = 0x1.bc907fd5d1c4069339ff22ep-3, .lo = 0x1.55d384963ee98afc3078d3044017p-99 },
+ .{ .hi = 0x1.c0c5134610e267bfa808f848p-3, .lo = -0x1.bf2c67a6f8c447c947b509e1719ep-100 },
+ .{ .hi = 0x1.c4f495c0002a25ee9a870fd4p-3, .lo = 0x1.de41f6ddaf5ae1b6bcccff037f29p-101 },
+ .{ .hi = 0x1.c91f1369eb7c9ad8af7db3a4p-3, .lo = -0x1.75624a957be051fcc1561cb35d19p-101 },
+ .{ .hi = 0x1.cd44983e9e7bca1ed1e0c97p-3, .lo = -0x1.c657e8081710f357c508dec6e106p-101 },
+ .{ .hi = 0x1.d165300e333f69c028a3c44cp-3, .lo = -0x1.af0662e02a88b8b9880e28aec4a9p-103 },
+ .{ .hi = 0x1.d580e67edc43ccfa0daf2304p-3, .lo = -0x1.8dcb9bd2e499dd3f11a0b9bc0a2bp-99 },
+ .{ .hi = 0x1.d997c70da9b46857c60d08e4p-3, .lo = -0x1.416b471cfcc11bbf284b644ffe95p-104 },
+ .{ .hi = 0x1.dda9dd0f4a329136847dd694p-3, .lo = 0x1.1a80cb70cec14440d0790cbb6a14p-101 },
+ .{ .hi = 0x1.e1b733b0c7381094f8c216p-3, .lo = -0x1.1f64198a27f7644abf7fc0a11cfep-100 },
+ .{ .hi = 0x1.e5bfd5f83d342043025796c8p-3, .lo = 0x1.eee33c4cf5a0527d82ee10fac926p-101 },
+ .{ .hi = 0x1.e9c3cec58f8072098058f2b4p-3, .lo = 0x1.6404cd11267d01734c132384a9d3p-99 },
+ .{ .hi = 0x1.edc328d3184af1cba1b7464cp-3, .lo = 0x1.aee952dcd721c2bd1b9abe8a0fc4p-99 },
+ .{ .hi = 0x1.f1bdeeb654900d96cd34f7ep-3, .lo = -0x1.5fbba7898678670262ca8d3b731dp-102 },
+ .{ .hi = 0x1.f5b42ae08c4070bc91804dd8p-3, .lo = -0x1.34f3fead2ae9308d1bc754f8f98ap-99 },
+ .{ .hi = 0x1.f9a5e79f76ac491748bb64p-3, .lo = 0x1.46fc084fcb735851dd511e9ab6fap-99 },
+ .{ .hi = 0x1.fd932f1ddb4d5f2e278b32c8p-3, .lo = -0x1.f7fe463a5a2fd566ad5e27e0cd8p-100 },
+ .{ .hi = 0x1.00be05b217844161e1a46df2p-2, .lo = 0x1.dc4853e5049d6344f76c943a21abp-103 },
+ .{ .hi = 0x1.02b0432c96ff0694c1c8d108p-2, .lo = -0x1.25d66fcf4861577bb9fd14424be7p-101 },
+ .{ .hi = 0x1.04a054e13900409a780a5b3ap-2, .lo = -0x1.810c5ed46a87b19c7c9d5bf41be9p-100 },
+ .{ .hi = 0x1.068e3fa282e3ced3324274cap-2, .lo = -0x1.65bc02e61d74996197c7d08a5628p-101 },
+ .{ .hi = 0x1.087a0832fa7ac4f9ab7853eap-2, .lo = -0x1.2214605e23cb53396213a2d34961p-99 },
+ .{ .hi = 0x1.0a63b3456c818f3ddb757cccp-2, .lo = -0x1.10d47a8504490cf7c88c75d66fcp-99 },
+ .{ .hi = 0x1.0c4b457d3193d3ffa651b8b8p-2, .lo = 0x1.1c0d5a63400f97839bedc777964ap-99 },
+ .{ .hi = 0x1.0e30c36e71a7f53a9ae38e1cp-2, .lo = -0x1.f89e6fc3f1e6388ca5d784700f47p-99 },
+ .{ .hi = 0x1.1014319e661bc87f6e8c7fdep-2, .lo = 0x1.6639f4ae29ccf0bc44437859de9bp-106 },
+ .{ .hi = 0x1.11f594839a5bd3aec4ea7c46p-2, .lo = 0x1.056df9f7cd47dc0aaa4fe49395fcp-100 },
+ .{ .hi = 0x1.13d4f0862b2e167244a4e998p-2, .lo = -0x1.db24b7557c465ba68f4835e8a628p-100 },
+ .{ .hi = 0x1.15b24a0004a924955aced3a4p-2, .lo = -0x1.32961e32127f178b4381d107f47dp-99 },
+ .{ .hi = 0x1.178da53d1ee013c7b3e96d22p-2, .lo = -0x1.0701b8cc90346d780c7f87d2d01p-100 },
+ .{ .hi = 0x1.1967067bb94b7feaa558f2f2p-2, .lo = -0x1.03e52851cf5d1510eac0efac64adp-100 },
+ .{ .hi = 0x1.1b3e71ec94f7abbbb3324a1p-2, .lo = -0x1.76cec8d0f75a398c7a1e37848466p-104 },
+ .{ .hi = 0x1.1d13ebb32d7f886517823d22p-2, .lo = -0x1.e1b60cbc6aa94cd2c4cb44f767d2p-102 },
+ .{ .hi = 0x1.1ee777e5f0dc35268e3c0384p-2, .lo = -0x1.563fb0ec2d3c9a0126193b44884fp-99 },
+ .{ .hi = 0x1.20b91a8e761050d250ea2a8p-2, .lo = -0x1.0fb80164cc712614d5d1d7e782aep-99 },
+ .{ .hi = 0x1.2288d7a9b2b6413283817024p-2, .lo = 0x1.9b04b90001edc89a11f502eea0c8p-99 },
+ .{ .hi = 0x1.2456b3282f78608173a44484p-2, .lo = 0x1.54c245cf9301f94383e5734624afp-99 },
+ .{ .hi = 0x1.2622b0ee3b79cee2bf4fc8eap-2, .lo = -0x1.33e1e10119160d49b5ff9aee724ep-99 },
+ .{ .hi = 0x1.27ecd4d41eb6752d30611516p-2, .lo = 0x1.80530269b1752224c47155d4d90bp-99 },
+ .{ .hi = 0x1.29b522a64b609745e857b1e8p-2, .lo = -0x1.9d8474e5705adbbd898636577548p-99 },
+ .{ .hi = 0x1.2b7b9e258e4226bf0485fabp-2, .lo = -0x1.619c76c7c7c5060bbd811063be07p-100 },
+ .{ .hi = 0x1.2d404b073e27da5069cad6ecp-2, .lo = -0x1.34f7416aedeeabbc31c75eedbc4dp-101 },
+ .{ .hi = 0x1.2f032cf56a5be40baedb9a4ap-2, .lo = -0x1.e454c75d4817c3aa12fdfb2d1cc8p-102 },
+ .{ .hi = 0x1.30c4478f0835f6cf717bf672p-2, .lo = 0x1.aeef5062051e012dc44bd3ce1929p-99 },
+ .{ .hi = 0x1.32839e681fc6236e91f3dacap-2, .lo = -0x1.451bc31fd56e57af018a8d364cb8p-99 },
+ .{ .hi = 0x1.34413509f79fef311f12b358p-2, .lo = 0x1.6f922f04d5a618a87a3e69314bcep-102 },
+ };
+ return impl.proc1(.{ .poly = poly, .tab = tab }, x);
}
pub fn log10l(x: c_longdouble) callconv(.c) c_longdouble {
@@ -255,3 +437,46 @@ test "log10() boundary" {
try expectEqual(log10(0x1p-1022), -0x1.33a7146f72a42p+8); // First subnormal
try expect(math.isNan(log10(-0x1p-1022))); // First negative subnormal
}
+
+test "log10q() special" {
+ try expectEqual(log10q(0.0), -math.inf(f128));
+ try expectEqual(log10q(-0.0), -math.inf(f128));
+ try expect(math.isPositiveZero(log10q(1.0)));
+ try expectEqual(log10q(10.0), 1.0);
+ try expectEqual(log10q(0.1), -1.0);
+ try expectEqual(log10q(math.inf(f128)), math.inf(f128));
+ try expect(math.isNan(log10q(-1.0)));
+ try expect(math.isNan(log10q(-math.inf(f128))));
+ try expect(math.isNan(log10q(math.nan(f128))));
+ try expect(math.isNan(log10q(math.snan(f128))));
+}
+
+test "log10q() sanity" {
+ try expectEqual(log10q(2.1744503117482705706605762784484114e1949), 1.949337349488073972035715318447419e3);
+ try expectEqual(log10q(2.3695331993665660983204066767386505e2150), 2.1503746627979481420243846411400265e3);
+ try expectEqual(log10q(1.8071775728314983136779370752110857e612), 6.122570008283284411311428111991705e2);
+ try expectEqual(log10q(2.612170297226630737309271722008693e-2629), -2.628582998513179919647069989114319e3);
+ try expectEqual(log10q(8.485091636263895897993044621224502e-3748), -3.7470713434630800881474518447042895e3);
+ try expectEqual(log10q(4.3668077579803801413736022136116655e-4051), -4.0503598359268068567757367259544416e3);
+ try expectEqual(log10q(2.9321353260885285826237030859036923e4830), 4.830467184010313310864606285356782e3);
+ try expectEqual(log10q(6.6119754254652455408442826553161645e-1417), -1.416179668769227128601620567685071e3);
+ try expectEqual(log10q(5.2459104673488555418645321788108695e4178), 4.178719820874155944446586083585479e3);
+ try expectEqual(log10q(7.809812890804996586377267218360886e-418), -4.1710735937091966815220294599598215e2);
+ // testing near 1
+ try expectEqual(log10q(1.0291437165967803055610652052109798e0), 1.2476026819466393459130418401605807e-2);
+ try expectEqual(log10q(1.043095786320424537962914257605007e0), 1.8324191034706598279642145362763252e-2);
+ try expectEqual(log10q(9.900264873754467234601150948947179e-1), -4.3531860417287584780652055666513634e-3);
+ try expectEqual(log10q(1.038295346547007736348611217636062e0), 1.6320907588397540309035279023485962e-2);
+ try expectEqual(log10q(9.821701941230028324703038578036285e-1), -7.813249520562034832371814409278784e-3);
+ try expectEqual(log10q(9.593555263530179895381522214847791e-1), -1.8020418356217558657107271163588764e-2);
+}
+
+test "log10q() boundary" {
+ try expectEqual(log10q(0x1.ffffffffffffffffffffffffffffp16383), 0x1.34413509f79fef311f12b35816f9p12); // Max input value
+ try expectEqual(log10q(0x1p-16494), -0x1.3653051d20c18a143b801b7c5661p12); // Min positive input value
+ try expect(math.isNan(log10q(-0x1p-16494))); // Min negative input value
+ try expectEqual(log10q(0x1.0000000000000000000000000001p0), 0x1.bcb7b1526e50e32a6ab7555f5a67p-114); // Last value before result reaches +0
+ try expectEqual(log10q(0x1.ffffffffffffffffffffffffffffp-1), -0x1.bcb7b1526e50e32a6ab7555f5a68p-115); // Last value before result reaches -0
+ try expectEqual(log10q(0x1p-16382), -0x1.343793004f503231a589bac27c38p12); // First subnormal
+ try expect(math.isNan(log10q(-0x1p-16382))); // First negative subnormal
+}
diff --git a/lib/compiler_rt/log2.zig b/lib/compiler_rt/log2.zig
@@ -163,9 +163,190 @@ pub fn __log2x(a: f80) callconv(.c) f80 {
return @floatCast(log2q(a));
}
-pub fn log2q(a: f128) callconv(.c) f128 {
- // TODO: more correct implementation
- return log2(@floatCast(a));
+/// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic"
+/// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990
+///
+/// https://dl.acm.org/doi/pdf/10.1145/98267.98294
+///
+/// Adapted to work for f128 and base 2 by Christophe Delage.
+///
+/// Accuracy on 100 million random numbers in [0, inf) (exponent uniformly random)
+/// <= 0.5 ulp: 99.99%, worst case <= 0.594 ulp
+///
+/// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case):
+/// <= 0.5 ulp: 99.86%, worst case <= 0.546 ulp
+pub fn log2q(x: f128) callconv(.c) f128 {
+ const impl = @import("log_f128.zig");
+
+ if (impl.specialCases(x)) |y|
+ return y;
+
+ if (impl.Proc2.lo < x and x < impl.Proc2.hi) {
+ // Polynomial approximation of log2((1 + u / 2) / (1 - u / 2))
+ // in [2 * a / (2 + a), 2 * b / (2 + b)]
+ // where a = exp(-1 / 16) - 1 and b = exp(1 / 16) - 1
+ const poly: impl.Proc2.Poly = .{
+ .b1_hi = 0x1.71547652b82fep0,
+ .b1_lo = 0x1.777d0ffda0d23a7d11d6aef551bbp-56,
+ .b3 = 0.12022458674074695061332705675016125,
+ .b5 = 1.8033688011112042591999058475816515e-2,
+ .b7 = 3.2203014305557218914285331735164364e-3,
+ .b9 = 6.261697226080570342191671010883619e-4,
+ .b11 = 1.280801705334664325639770412440281e-4,
+ .b13 = 2.7093882228102330360125035037716968e-5,
+ .b15 = 5.870341197214724685339102193694838e-6,
+ .b17 = 1.294917697032820750200161813672143e-6,
+ .b19 = 2.909291439731657940692470637735429e-7,
+ };
+ return impl.proc2(.{ .poly = poly }, x);
+ }
+
+ // Polynomial approximation of log2(1 + 2 * u / (2 - u))
+ // in [-(2 * fmax) / (2 + fmax), (2 * fmax) / (2 - fmax)]
+ // where fmax = 0.5 / size
+ const poly: impl.Proc1.Poly = .{
+ .a1 = 1.442695040888963407359924681001892,
+ .a3 = 0.12022458674074695061332705675072149,
+ .a5 = 1.8033688011112042591998536830294507e-2,
+ .a7 = 3.22030143055572204818095463930704e-3,
+ .a9 = 6.261697225875019234719395591078697e-4,
+ .a11 = 1.280813940786848788109850061222256e-4,
+ };
+ // tab[j].hi = 2^-n * round-to-integer(2^n * l)
+ // tab[j].lo = round-to-nearest-f128(l - tab[j].hi)
+ // where n = 97 and l = log2(1 + j / size)
+ const tab = [impl.size + 1]impl.Proc1.HiLo{
+ .{ .hi = 0, .lo = 0 },
+ .{ .hi = 0x1.6fe50b6ef08517f8e37bp-7, .lo = 0x1.794f4441ccdf648f265a41e57d75p-99 },
+ .{ .hi = 0x1.6e79685c2d2298a6e27e212p-6, .lo = -0x1.fbd41ae7d5a2434912ad3fe21cfbp-100 },
+ .{ .hi = 0x1.11cd1d5133412ed814504fbp-5, .lo = -0x1.b2e2b43254008aeb4167a3359577p-99 },
+ .{ .hi = 0x1.6bad3758efd87313606f097p-5, .lo = -0x1.20fbdb7ce4c86d28e4be331fce17p-99 },
+ .{ .hi = 0x1.c4dfab90aab5ef4f8f869e6p-5, .lo = 0x1.dc4142bd2b182fdaac375356fc29p-100 },
+ .{ .hi = 0x1.0eb389fa29f9ab3cf74bab98p-4, .lo = 0x1.9217066b9150f3c7ddd223517be7p-100 },
+ .{ .hi = 0x1.3aa2fdd27f1c2d804d1121b8p-4, .lo = -0x1.acec4ac95b97a0e1d121d0222ba5p-99 },
+ .{ .hi = 0x1.663f6fac913167ccc5382618p-4, .lo = -0x1.dd4529e1ad7c182a716c033db6dep-99 },
+ .{ .hi = 0x1.918a16e46335aae7232494d8p-4, .lo = 0x1.9d1d19046b227370f7cb86bd9e3ep-99 },
+ .{ .hi = 0x1.bc84240adabba63b2c5a6e5p-4, .lo = 0x1.97ab879641c50810e3b820ca9aap-100 },
+ .{ .hi = 0x1.e72ec117fa5b21cbdb5d9dcp-4, .lo = 0x1.4f902752a1dc5b384b68c4f1e669p-99 },
+ .{ .hi = 0x1.08c588cda79e39627bc6fd0cp-3, .lo = -0x1.aad7542b0c4015f8fdff17d7ea79p-99 },
+ .{ .hi = 0x1.1dcd197552b7b5ea45430784p-3, .lo = -0x1.a7aa295e08add52f96d8aaf3b8edp-101 },
+ .{ .hi = 0x1.32ae9e278ae1a1f51f2c075cp-3, .lo = -0x1.8b459b26ac0ed3b39116e44d50c8p-99 },
+ .{ .hi = 0x1.476a9f983f74d3138e941644p-3, .lo = -0x1.27d822a49870762eeaffdcde52bdp-104 },
+ .{ .hi = 0x1.5c01a39fbd6879fa00b120ap-3, .lo = 0x1.a2eb74493cf9a8e8966c101ef964p-101 },
+ .{ .hi = 0x1.70742d4ef027f29c01cfad78p-3, .lo = -0x1.8495d6ca3b2dcc7941a5df4c8decp-103 },
+ .{ .hi = 0x1.84c2bd02f03b2fdd2248ee78p-3, .lo = -0x1.c56a8f0829344b50240232cdb09ep-99 },
+ .{ .hi = 0x1.98edd077e70df02face8ca9p-3, .lo = 0x1.72b7f2fcb409899d29e3feaf9c8fp-99 },
+ .{ .hi = 0x1.acf5e2db4ec93efe11ecbcp-3, .lo = 0x1.83634b52082beea143f1178aaf62p-99 },
+ .{ .hi = 0x1.c0db6cdd94dee40e26d9899cp-3, .lo = 0x1.fde86bd82482b9b4a45aa674cc1bp-100 },
+ .{ .hi = 0x1.d49ee4c32596fc8f4b565024p-3, .lo = -0x1.7eaef901f52d2d54011ca95ecca1p-101 },
+ .{ .hi = 0x1.e840be74e6a4cc7c9f3d51ep-3, .lo = -0x1.03c7c0d8554c2c17f944fa1f93cfp-99 },
+ .{ .hi = 0x1.fbc16b902680a23a8d998a78p-3, .lo = 0x1.3bcd7c933d5bb6b52a41ad567d8ep-101 },
+ .{ .hi = 0x1.0790adbb030096f031a699d6p-2, .lo = -0x1.748a4ccf5e3dadf04bd0ff35f885p-99 },
+ .{ .hi = 0x1.11307dad30b75cb09705a796p-2, .lo = -0x1.6c580f988c64f00bd800ed9b9d24p-100 },
+ .{ .hi = 0x1.1ac05b291f070528c7386df8p-2, .lo = 0x1.94340c3b639a4e5a59fded67fcb7p-99 },
+ .{ .hi = 0x1.24407ab0e07398245b94ba44p-2, .lo = 0x1.8077f77a0f4353b19301384099dap-99 },
+ .{ .hi = 0x1.2db10fc4d9aaf6f137a3d8c6p-2, .lo = 0x1.e79b8ee38b380b8be44e090558d7p-99 },
+ .{ .hi = 0x1.37124cea4cdecd991336c96p-2, .lo = 0x1.fb9186e41376f4612d4b0b9a507dp-100 },
+ .{ .hi = 0x1.406463b1b044975b2f344252p-2, .lo = 0x1.9a92f79c803c5151cb25af73b143p-101 },
+ .{ .hi = 0x1.49a784bcd1b8afe492bf6ff4p-2, .lo = 0x1.b5fb699b2d8abfc6f675a9d236d6p-99 },
+ .{ .hi = 0x1.52dbdfc4c96b37dcf60e61fcp-2, .lo = 0x1.36a5977bbf78792b6a99ccb74cd5p-99 },
+ .{ .hi = 0x1.5c01a39fbd6879fa00b120ap-2, .lo = 0x1.a2eb74493cf9a8e8966c101ef964p-100 },
+ .{ .hi = 0x1.6518fe4677ba6e52278edc8ap-2, .lo = -0x1.6778b4ba074a8ce60972502c7262p-102 },
+ .{ .hi = 0x1.6e221cd9d0cde578d520b45p-2, .lo = -0x1.1f87779b03b7d7e6bd0493f2e147p-99 },
+ .{ .hi = 0x1.771d2ba7efb3be46fecd5122p-2, .lo = 0x1.29ff1c3c9184a53c236eed64d17ep-100 },
+ .{ .hi = 0x1.800a563161c5432aeb609f4ep-2, .lo = -0x1.0a6ee4f4272036db2b8f6963d1c4p-103 },
+ .{ .hi = 0x1.88e9c72e0b225a4b664a4c8ep-2, .lo = -0x1.59153bc13892380cd03989062763p-100 },
+ .{ .hi = 0x1.91bba891f1708b4b2b5056b8p-2, .lo = 0x1.a7156185dba8beba3cb180b37bbbp-100 },
+ .{ .hi = 0x1.9a802391e232f34bb6d0e43ap-2, .lo = -0x1.67caee1e30b7c2d6ff9893868aa6p-99 },
+ .{ .hi = 0x1.a33760a7f60509d7c40d797ap-2, .lo = -0x1.3a4e0233ff8ac31bd7b2cb5c0041p-102 },
+ .{ .hi = 0x1.abe18797f1f48e1a4725558cp-2, .lo = 0x1.6f5c786e3d2aafcee056debabb79p-100 },
+ .{ .hi = 0x1.b47ebf73882a0a4146ef8fd8p-2, .lo = 0x1.44f1d5b8a5402f72138cbfe19e49p-99 },
+ .{ .hi = 0x1.bd0f2e9e79030ab442ce3202p-2, .lo = -0x1.d27aeb2ddd02924cf83def704a7bp-99 },
+ .{ .hi = 0x1.c592fad295b567e7ee54aefp-2, .lo = -0x1.99e7587ea99e677177c285c32088p-99 },
+ .{ .hi = 0x1.ce0a4923a587cc95d0a2ee7ap-2, .lo = 0x1.6482ae04295539bf0ed23f498b8ap-104 },
+ .{ .hi = 0x1.d6753e032ea0efe3ebe19906p-2, .lo = -0x1.55594a060c67a245f78bb523ad43p-99 },
+ .{ .hi = 0x1.ded3fd442364c4ebb196116p-2, .lo = -0x1.df9689b34ee848b0b7818878492cp-99 },
+ .{ .hi = 0x1.e726aa1e754d20c519e12f48p-2, .lo = -0x1.dd99950bae450ac5754344a16faep-99 },
+ .{ .hi = 0x1.ef6d67328e2207d1e01a839p-2, .lo = 0x1.04907f9ccddb53ed88c47c7d794cp-100 },
+ .{ .hi = 0x1.f7a8568cb06cece193180046p-2, .lo = -0x1.e149b9528336d5fee3ef52260ad1p-99 },
+ .{ .hi = 0x1.ffd799a83ff9ab9cc7f342f8p-2, .lo = 0x1.70c458bda55b08c8c8668867736bp-99 },
+ .{ .hi = 0x1.03fda8b97997f33943464056p-1, .lo = 0x1.eb47cb2aadd948d48bbef492995ep-99 },
+ .{ .hi = 0x1.0809cf27f703d525b3c1d158p-1, .lo = 0x1.f51e170ccb0f7761e5ff9b93854ep-100 },
+ .{ .hi = 0x1.0c10500d63aa6588257529b6p-1, .lo = 0x1.2ef0aa83f2869dd6be1d1cc2dc47p-100 },
+ .{ .hi = 0x1.10113b153c8ea7b1cddae6fbp-1, .lo = -0x1.8d4296259492a32f8b327d46339p-100 },
+ .{ .hi = 0x1.140c9faa1e5439e15a52a316p-1, .lo = 0x1.29611295daec3b07655c599a50e7p-103 },
+ .{ .hi = 0x1.18028cf72976a4eb8e97d145p-1, .lo = 0x1.9ac318308c388b1f2e108f3d37bep-100 },
+ .{ .hi = 0x1.1bf311e95d00de3b513a9dcdp-1, .lo = -0x1.3c8ff1c1539554d1f10759819adp-100 },
+ .{ .hi = 0x1.1fde3d30e812642415d47384p-1, .lo = 0x1.3c458dd53d12c99743f3c4617c37p-99 },
+ .{ .hi = 0x1.23c41d42727c8080ecc61a99p-1, .lo = -0x1.fb113740031e528bbef9ead829c7p-99 },
+ .{ .hi = 0x1.27a4c0585cbf805784ee0e3bp-1, .lo = -0x1.60c515c0f4b1772f673312a17eep-101 },
+ .{ .hi = 0x1.2b803473f7ad0f3f40162414p-1, .lo = 0x1.a2eb74493cf9a8e8966c101ef964p-102 },
+ .{ .hi = 0x1.2f56875eb3f2614278cd1699p-1, .lo = 0x1.88c5d320344f129c318704371e3dp-100 },
+ .{ .hi = 0x1.3327c6ab49ca6c86b9205fa4p-1, .lo = 0x1.1010939e6edc060bf80459dd880dp-100 },
+ .{ .hi = 0x1.36f3ffb6d9162404772a151dp-1, .lo = -0x1.93193dd58663d90eed123bda5ea2p-100 },
+ .{ .hi = 0x1.3abb3faa02166cccab240e9p-1, .lo = 0x1.3e5a84738c6a548017167cabbd62p-99 },
+ .{ .hi = 0x1.3e7d9379f70166ae2a7ada55p-1, .lo = 0x1.6369ad81817bfeddee4a96320fd3p-100 },
+ .{ .hi = 0x1.423b07e986aa9670761d14abp-1, .lo = -0x1.d93cd9e77a527017a3e16237ddd4p-100 },
+ .{ .hi = 0x1.45f3a98a20738a4d7ffe0267p-1, .lo = 0x1.75541c775be89f0841ae8379c6adp-100 },
+ .{ .hi = 0x1.49a784bcd1b8afe492bf6ff5p-1, .lo = -0x1.2812599349d500e4262958b724aap-100 },
+ .{ .hi = 0x1.4d56a5b33cec44a6deff9987p-1, .lo = 0x1.fad1e37de08f5e02036d27593a4p-100 },
+ .{ .hi = 0x1.510118708a8f8dde949378b2p-1, .lo = 0x1.348f1454e8c939a60252b34c6c66p-100 },
+ .{ .hi = 0x1.54a6e8ca5438db1b0ca63aacp-1, .lo = -0x1.2f1784ce0b08724e7f04c9712103p-99 },
+ .{ .hi = 0x1.5848226989d33c38d8bd28d7p-1, .lo = -0x1.a8e7bb5885dce30d5e9e8139d7b1p-99 },
+ .{ .hi = 0x1.5be4d0cb51434aaeb3f01222p-1, .lo = 0x1.2ce7e40053a5cfc072e22bbeab1dp-100 },
+ .{ .hi = 0x1.5f7cff41e09aeb8cb1ac05cdp-1, .lo = -0x1.4fb2c4a0dc9f7b2e29701f76805bp-100 },
+ .{ .hi = 0x1.6310b8f553048406a5a171dep-1, .lo = 0x1.003332544881b92584a992692c7dp-99 },
+ .{ .hi = 0x1.66a008e4788cbcd2edb4390ep-1, .lo = 0x1.4c1a88f0e7a41e948033b63cbaadp-99 },
+ .{ .hi = 0x1.6a2af9e5a0f0a08099572f21p-1, .lo = -0x1.0665eae13d10b498acfb49ce0dep-99 },
+ .{ .hi = 0x1.6db196a761949d97df07e357p-1, .lo = -0x1.7679e5a1e4a0e0dbeb3195d40b4dp-99 },
+ .{ .hi = 0x1.7133e9b156c7be5167fbdc81p-1, .lo = 0x1.b935e716c7cb214a0b718fc30587p-100 },
+ .{ .hi = 0x1.74b1fd64e0753c6e5783fd15p-1, .lo = 0x1.923a7aefc37ef9baffdf4ec86923p-102 },
+ .{ .hi = 0x1.782bdbfdda6577bc87e125ebp-1, .lo = -0x1.56e82c9d846f9e967e496249719bp-99 },
+ .{ .hi = 0x1.7ba18f93502e409eab77f21ap-1, .lo = -0x1.c097ea4900b7ca9ea124a56a0c75p-100 },
+ .{ .hi = 0x1.7f1322182cf15d12ecd77fe7p-1, .lo = -0x1.0512c0ac2d3510c6f5fd964c2ae2p-99 },
+ .{ .hi = 0x1.82809d5be7072dbdc0426c3cp-1, .lo = 0x1.3a309736edbb3eae70d10c173b0bp-100 },
+ .{ .hi = 0x1.85ea0b0b27b261086fce864ap-1, .lo = 0x1.f5979367f112e34dbc4e07ae924cp-101 },
+ .{ .hi = 0x1.894f74b06ef8b406ea2c7d92p-1, .lo = -0x1.54ede83a0018a21469a1f11911aep-99 },
+ .{ .hi = 0x1.8cb0e3b4b3bbdb3688a85fb2p-1, .lo = -0x1.910d207f019516331134b0c9d172p-99 },
+ .{ .hi = 0x1.900e6160002ccfe43f50847dp-1, .lo = 0x1.82887e54848c7603fba7d2ba264ap-101 },
+ .{ .hi = 0x1.9367f6da0ab2e9cc865b3dd1p-1, .lo = -0x1.225541e18baff32be2709a01f861p-100 },
+ .{ .hi = 0x1.96bdad2acb5f5efec4915314p-1, .lo = 0x1.b7c0b9db2fcb23be56be998e8e8fp-99 },
+ .{ .hi = 0x1.9a0f8d3b0e04fde95734abd3p-1, .lo = -0x1.9f19ce27d2dca3979bbb0ca9365fp-104 },
+ .{ .hi = 0x1.9d5d9fd5010b366655920748p-1, .lo = 0x1.3e5a84738c6a548017167cabbd62p-100 },
+ .{ .hi = 0x1.a0a7eda4c112ce6312ebb81dp-1, .lo = -0x1.5a727dbaad60b1bf6bcd429e9fdfp-102 },
+ .{ .hi = 0x1.a3ee7f38e181ed0798d1aa21p-1, .lo = 0x1.a51584c9dc5627ac1ab989c42834p-99 },
+ .{ .hi = 0x1.a7315d02f20c7bd560a3fee1p-1, .lo = -0x1.dacbac02cace034400340f2319ddp-99 },
+ .{ .hi = 0x1.aa708f58014d37cde37c86b2p-1, .lo = 0x1.06a19b5bedec4594babbdab2fd2p-100 },
+ .{ .hi = 0x1.adac1e711c832d1562d61af7p-1, .lo = 0x1.fbfa94970bb9fab077c80ac91e28p-100 },
+ .{ .hi = 0x1.b0e4126bcc86bd7a6ed4e1b1p-1, .lo = -0x1.b28c4122d931f14daa7bc7cc5b07p-99 },
+ .{ .hi = 0x1.b418734a9008bd978b98f7dfp-1, .lo = -0x1.039d32863d2685d1b265e993decbp-100 },
+ .{ .hi = 0x1.b74948f5532da4b4b7143364p-1, .lo = -0x1.ce44c707d13d9c8e8a9007c6ffb4p-99 },
+ .{ .hi = 0x1.ba769b39e49640ef87ede14bp-1, .lo = -0x1.735f3571b2e44add58e787eb935ep-101 },
+ .{ .hi = 0x1.bda071cc67e6db516de08136p-1, .lo = 0x1.b4d5660336e288cea5ceba447906p-99 },
+ .{ .hi = 0x1.c0c6d447c5dd362d9a9a55c7p-1, .lo = 0x1.17b370ba83c0155dfdf1fd11696ep-99 },
+ .{ .hi = 0x1.c3e9ca2e1a05533698b4e49bp-1, .lo = 0x1.ec0c07c38978823235b0f583d7a7p-99 },
+ .{ .hi = 0x1.c7095ae91e1c760bc9b188c4p-1, .lo = 0x1.322631fb315aaf4da97307d1076bp-99 },
+ .{ .hi = 0x1.ca258dca9331635fee390c0bp-1, .lo = -0x1.3e17e7a7e746edea65e0c4e7d82dp-99 },
+ .{ .hi = 0x1.cd3e6a0ca8906c243749114cp-1, .lo = 0x1.2bbae931e8daa670e214b298ab12p-99 },
+ .{ .hi = 0x1.d053f6d2608967318975dc0ep-1, .lo = 0x1.ea58d8245529f4e409432bd61602p-99 },
+ .{ .hi = 0x1.d3663b27f31d5297837adb4bp-1, .lo = -0x1.38daa2d672ec54842668a312854dp-100 },
+ .{ .hi = 0x1.d6753e032ea0efe3ebe19905p-1, .lo = 0x1.554d6bf3e730bb7410e895b8a57ap-99 },
+ .{ .hi = 0x1.d9810643d6614c3c406eb464p-1, .lo = 0x1.05d328adc61c09915e038a135bdfp-99 },
+ .{ .hi = 0x1.dc899ab3ff56c5e673abad44p-1, .lo = 0x1.8c6339fa7bd10d27c064978bc6f5p-100 },
+ .{ .hi = 0x1.df8f02086af2c4bef483c68bp-1, .lo = -0x1.0baa11f1460aebb8f273d9820bc8p-99 },
+ .{ .hi = 0x1.e29142e0e01401fbaaa67e3cp-1, .lo = -0x1.d6541223b8314593546e23de0435p-100 },
+ .{ .hi = 0x1.e59063c8822ce561911a9bacp-1, .lo = 0x1.9b0de815b6fb0c41cac421925a11p-99 },
+ .{ .hi = 0x1.e88c6b3626a72aa21a3c7f02p-1, .lo = -0x1.0e3aeafe4f838b64e3bde351d0f1p-102 },
+ .{ .hi = 0x1.eb855f8ca88fb0d4b5c673bbp-1, .lo = 0x1.1db401cf29698d7b00a45b6d1082p-102 },
+ .{ .hi = 0x1.ee7b471b3a9507d6dc1f27efp-1, .lo = 0x1.21f23cd188a03f54e360fd76a481p-99 },
+ .{ .hi = 0x1.f16e281db76303b21928c216p-1, .lo = -0x1.2854f795db443461c5e7233e545fp-102 },
+ .{ .hi = 0x1.f45e08bcf06554e4d5be4f7p-1, .lo = 0x1.07e81f4c1573947a3126425d9d0ap-99 },
+ .{ .hi = 0x1.f74aef0efafadd7a1b65f639p-1, .lo = -0x1.7bc1e9882648a6b530fa4d847e3fp-100 },
+ .{ .hi = 0x1.fa34e1177c23362928b9ed75p-1, .lo = -0x1.856dc2b529ad698bfda1e41b89bdp-101 },
+ .{ .hi = 0x1.fd1be4c7f2af942b221ce0d1p-1, .lo = 0x1.a275c854f5bb9732fae5130be48bp-104 },
+ .{ .hi = 0x1p0, .lo = 0 },
+ };
+ return impl.proc1(.{ .poly = poly, .tab = tab }, x);
}
pub fn log2l(x: c_longdouble) callconv(.c) c_longdouble {
@@ -247,3 +428,40 @@ test "log2() boundary" {
try expectEqual(log2(0x1p-1022), -0x1.ffp+9); // First subnormal
try expect(math.isNan(log2(-0x1p-1022))); // First negative subnormal
}
+
+test "log2q() special" {
+ try expectEqual(log2q(0.0), -math.inf(f128));
+ try expectEqual(log2q(-0.0), -math.inf(f128));
+ try expect(math.isPositiveZero(log2q(1.0)));
+ try expectEqual(log2q(2.0), 1.0);
+ try expectEqual(log2q(math.inf(f128)), math.inf(f128));
+ try expect(math.isNan(log2q(-1.0)));
+ try expect(math.isNan(log2q(-math.inf(f128))));
+ try expect(math.isNan(log2q(math.nan(f128))));
+ try expect(math.isNan(log2q(math.snan(f128))));
+}
+
+test "log2q() boundary" {
+ try expectEqual(log2q(0x1.ffffffffffffffffffffffffffffp16383), 0x1p14); // Max input value
+ try expectEqual(log2q(0x1p-16494), -0x1.01b8p14); // Min positive input value
+ try expect(math.isNan(log2q(-0x1p-16494))); // Min negative input value
+ try expectEqual(log2q(0x1.0000000000000000000000000001p0), 0x1.71547652b82fe1777d0ffda0d23ap-112); // Last value before result reaches +0
+ try expectEqual(log2q(0x1.ffffffffffffffffffffffffffffp-1), -0x1.71547652b82fe1777d0ffda0d23bp-113); // Last value before result reaches -0
+ try expectEqual(log2q(0x1p-16382), -0x1.fffp13); // First subnormal
+ try expect(math.isNan(log2q(-0x1p-16382))); // First negative subnormal
+}
+
+test "log2q() sanity" {
+ try expectEqual(log2q(8.0965013884643408203125e11), 3.955850767769801288865582596068254e1);
+ try expectEqual(log2q(8.346531942223744e15), 5.28900982928636641107356163006646e1);
+ try expectEqual(log2q(9.707809913413123613777865431464565e-20), -6.315941603809020445822192336703809e1);
+ try expectEqual(log2q(1.9179565888043380306021427656243352e-24), -7.878670421065570557450089031998522e1);
+ try expectEqual(log2q(2.5260048200126556877075044745936796e-25), -8.17113449801679676275805009400338e1);
+ try expectEqual(log2q(3.1170134002568967640399932861328125e7), 2.489366102143423848582774267206741e1);
+ // test near 1
+ try expectEqual(log2q(1.026586845186097528392910049888087e0), 3.7855678902522753591699367969189364e-2);
+ try expectEqual(log2q(1.0005582850578053877743656130405725e0), 8.052103367568488432896147152682078e-4);
+ try expectEqual(log2q(1.0370174103591254835765589348284266e0), 5.244011558596899945639244281954306e-2);
+ try expectEqual(log2q(1.0429996503525671713075162472250667e0), 6.073867421942172944687194557176633e-2);
+ try expectEqual(log2q(1.0383384027961064621892184334228659e0), 5.4276706191956281784022630732940314e-2);
+}
diff --git a/lib/compiler_rt/log_f128.zig b/lib/compiler_rt/log_f128.zig
@@ -0,0 +1,173 @@
+/// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic"
+/// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990
+///
+/// https://dl.acm.org/doi/pdf/10.1145/98267.98294
+///
+/// Adapted to work for f128 and bases 2 and 10 by Christophe Delage.
+///
+/// This file contains the code shared between logq, log2q and log10q.
+const log_f128 = @This();
+
+const std = @import("std");
+const math = std.math;
+
+pub const log2size = 7;
+pub const size = 1 << log2size;
+
+/// Filter out special cases for log in bases {e,2,10}.
+///
+/// If x is finite and positive, returns null.
+/// Returns the appropriate NaN or inf otherwise.
+pub fn specialCases(x: f128) ?f128 {
+ if (!math.isFinite(x)) {
+ if (math.isNan(x)) {
+ if (math.isSignalNan(x)) math.raiseInvalid();
+ return math.nan(f128);
+ }
+ if (math.isPositiveInf(x)) return x;
+ }
+ if (x <= 0.0) {
+ if (x >= 0.0) {
+ math.raiseDivByZero();
+ return -math.inf(f128);
+ }
+ math.raiseInvalid();
+ return math.nan(f128);
+ }
+
+ return null;
+}
+
+pub const Proc1 = struct {
+ pub const Poly = struct {
+ a1: f128,
+ a3: f128,
+ a5: f128,
+ a7: f128,
+ a9: f64,
+ a11: f64,
+ };
+ pub const HiLo = struct { hi: f128, lo: f128 };
+ poly: Poly,
+ tab: [size + 1]HiLo,
+};
+
+pub fn proc1(comptime p: Proc1, x: f128) f128 {
+ const ym = frexp2(x);
+ const y = ym.significand;
+ const m = ym.exponent;
+
+ const F0 = @round(math.ldexp(y, log2size));
+ const j0: usize = @intFromFloat(F0);
+ const j = j0 - size;
+ const F = math.ldexp(F0, -log2size);
+ const f = y - F;
+
+ const u = (f + f) / (y + F);
+ const v = u * u;
+ const v64: f64 = @floatCast(v);
+
+ const p9 = p.poly.a9 + v64 * p.poly.a11;
+ const p7 = p.poly.a7 + v * p9;
+ const p5 = p.poly.a5 + v * p7;
+ const p3 = p.poly.a3 + v * p5;
+
+ const q = u * v * p3;
+
+ const xm: f128 = @floatFromInt(m);
+ const l_hi = xm * p.tab[128].hi + p.tab[j].hi;
+ const l_lo = xm * p.tab[128].lo + p.tab[j].lo;
+
+ if (comptime p.poly.a1 == 1.0)
+ return l_hi + (u + (q + l_lo))
+ else
+ return l_hi + (u * p.poly.a1 + (q + l_lo));
+}
+
+pub const Proc2 = struct {
+ // exp(-1 / 16) rounded down
+ pub const lo: f128 = 0.939413062813475786119710824622305;
+ // exp(1 / 16) rounded up
+ pub const hi: f128 = 1.0644944589178594295633905946428897;
+
+ pub const Poly = struct {
+ b1_hi: f128,
+ b1_lo: f128,
+ b3: f128,
+ b5: f128,
+ b7: f128,
+ b9: f128,
+ b11: f128,
+ b13: f128,
+ b15: f64,
+ b17: f64,
+ b19: f64,
+ };
+
+ poly: Poly,
+};
+
+pub fn proc2(comptime p: Proc2, x: f128) f128 {
+ std.debug.assert(Proc2.lo < x and x < Proc2.hi);
+
+ const f = x - 1.0;
+ const g = 1 / (2 + f);
+ const u = 2 * f * g;
+ const v = u * u;
+ const uv = u * v;
+ const v64: f64 = @floatCast(v);
+
+ const p17 = p.poly.b17 + v64 * p.poly.b19;
+ const p15 = p.poly.b15 + v64 * p17;
+ const p13 = p.poly.b13 + v * p15;
+ const p11 = p.poly.b11 + v * p13;
+ const p9 = p.poly.b9 + v * p11;
+ const p7 = p.poly.b7 + v * p9;
+ const p5 = p.poly.b5 + v * p7;
+
+ const q_hi = uv * p.poly.b3;
+ const q_lo = uv * v * p5;
+
+ const f_hi: f128 = @as(f64, @floatCast(f));
+ const f_lo = f - f_hi;
+
+ const u_hi: f128 = @as(f64, @floatCast(u));
+ const u_lo = ((2 * (f - u_hi) - u_hi * f_hi) - u_hi * f_lo) * g;
+
+ if (comptime p.poly.b1_hi == 1.0 and p.poly.b1_lo == 0.0)
+ return u_hi + (u_lo + (q_hi + q_lo));
+
+ // t = u * p.poly.b1
+ const t_hi = u_hi * p.poly.b1_hi;
+ const t_lo = u_lo * p.poly.b1_hi + u * p.poly.b1_lo;
+
+ // y = t + q
+ const y_hi = t_hi + q_hi;
+ const y_lo = t_lo + (t_hi - y_hi + q_hi) + q_lo;
+
+ return y_hi + y_lo;
+}
+
+/// Returns (f, k) such that x = f * 2^k and f in [1,2).
+/// Asserts that x is finite and positive.
+pub fn frexp2(x: f128) math.Frexp(f128) {
+ std.debug.assert(math.isFinite(x));
+ std.debug.assert(x > 0.0);
+
+ const bits: u128 = @bitCast(x);
+ const uexp: i32 = @intCast(bits >> 112);
+
+ std.debug.assert(uexp >= 0);
+
+ if (uexp == 0) {
+ const shift: u7 = @intCast(@clz(bits) - 15);
+
+ const exp = -@as(i32, shift) - 0x3ffe;
+ const frac: f128 = @bitCast((bits << shift) | (0x3fff << 112));
+ return .{ .significand = frac, .exponent = exp };
+ }
+
+ const exp = uexp - 0x3fff;
+ const frac: f128 = @bitCast((0x3fff << 112) | ((bits << 16) >> 16));
+ return .{ .significand = frac, .exponent = exp };
+}