| ... | ... | @@ -450,8 +450,7 @@ pub fn __logx(a: f80) callconv(.c) f80 { |
| 450 | 450 | /// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case): |
| 451 | 451 | /// <= 0.5 ulp: 99.96%, worst case <= 0.528 ulp |
| 452 | 452 | pub fn logq(x: f128) callconv(.c) f128 { |
| 453 | | const bitsize = 7; |
| 454 | | const size = 1 << bitsize; |
| 453 | const impl = @import("log_f128.zig"); |
| 455 | 454 | |
| 456 | 455 | if (!math.isFinite(x)) { |
| 457 | 456 | if (math.isNan(x)) { |
| ... | ... | @@ -469,74 +468,42 @@ pub fn logq(x: f128) callconv(.c) f128 { |
| 469 | 468 | return math.nan(f128); |
| 470 | 469 | } |
| 471 | 470 | |
| 472 | | // exp(-1 / 16) rounded down |
| 473 | | const proc2_lo: f128 = 0.939413062813475786119710824622305; |
| 474 | | // exp(1 / 16) rounded up |
| 475 | | const proc2_hi: f128 = 1.0644944589178594295633905946428897; |
| 476 | | if (proc2_lo < x and x < proc2_hi) { |
| 477 | | const f = x - 1.0; |
| 478 | | |
| 479 | | const g = 1 / (2 + f); |
| 480 | | const u = 2 * f * g; |
| 481 | | const v = u * u; |
| 482 | | const uv = u * v; |
| 483 | | const v64: f64 = @floatCast(v); |
| 484 | | |
| 471 | if (impl.Proc2.lo < x and x < impl.Proc2.hi) { |
| 485 | 472 | // Polynomial approximation of log((1 + u / 2) / (1 - u / 2)) |
| 486 | 473 | // in [2 * a / (2 + a), 2 * b / (2 + b)] |
| 487 | 474 | // where a = exp(-1 / 16) - 1 and b = exp(1 / 16) - 1 |
| 488 | | const p19 = 2.0165671588771827537210411918018159e-7; |
| 489 | | const p17 = 8.97568550755477160981619052649713e-7 + v64 * p19; |
| 490 | | const p15 = 4.069010449774280288178309893970754e-6 + v64 * p17; |
| 491 | | const p13 = 1.8780048076832339308077858301484127e-5 + v * p15; |
| 492 | | const p11 = 8.87784090909092440759545734146088e-5 + v * p13; |
| 493 | | const p9 = 4.340277777777777776216500817402857e-4 + v * p11; |
| 494 | | const p7 = 2.2321428571428571428572328745789477e-3 + v * p9; |
| 495 | | const p5 = 1.249999999999999999999999997455655e-2 + v * p7; |
| 496 | | const p3 = 8.333333333333333333333333333333581e-2; |
| 497 | | |
| 498 | | const q_hi = uv * p3; |
| 499 | | const q_lo = uv * v * p5; |
| 500 | | const q = q_hi + q_lo; |
| 501 | | |
| 502 | | const fa: f128 = @as(f64, @floatCast(f)); |
| 503 | | const ua: f128 = @as(f64, @floatCast(u)); |
| 504 | | |
| 505 | | const fb: f128 = f - fa; |
| 506 | | const ub: f128 = ((2 * (f - ua) - ua * fa) - ua * fb) * g; |
| 507 | | |
| 508 | | return ua + (ub + q); |
| 475 | const poly: impl.Proc2.Poly = .{ |
| 476 | .b1_hi = 1.0, |
| 477 | .b1_lo = 0.0, |
| 478 | .b3 = 8.333333333333333333333333333333581e-2, |
| 479 | .b5 = 1.249999999999999999999999997455655e-2, |
| 480 | .b7 = 2.2321428571428571428572328745789477e-3, |
| 481 | .b9 = 4.340277777777777776216500817402857e-4, |
| 482 | .b11 = 8.87784090909092440759545734146088e-5, |
| 483 | .b13 = 1.8780048076832339308077858301484127e-5, |
| 484 | .b15 = 4.069010449774280288178309893970754e-6, |
| 485 | .b17 = 8.97568550755477160981619052649713e-7, |
| 486 | .b19 = 2.0165671588771827537210411918018159e-7, |
| 487 | }; |
| 488 | return impl.proc2(.{ .poly = poly }, x); |
| 509 | 489 | } |
| 510 | 490 | |
| 511 | | const ym = frexp2(x); |
| 512 | | const y = ym.significand; |
| 513 | | const m = ym.exponent; |
| 514 | | |
| 515 | | const F0 = @round(math.ldexp(y, bitsize)); |
| 516 | | const j0: usize = @intFromFloat(F0); |
| 517 | | const j = j0 - size; |
| 518 | | const F = math.ldexp(F0, -bitsize); |
| 519 | | const f = y - F; |
| 520 | | |
| 521 | | const u = (f + f) / (y + F); |
| 522 | | const v = u * u; |
| 523 | | const v64: f64 = @floatCast(v); |
| 524 | | |
| 525 | 491 | // Polynomial approximation of log(1 + 2 * u / (2 - u)) |
| 526 | 492 | // in [-(2 * fmax) / (2 + fmax), (2 * fmax) / (2 - fmax)] |
| 527 | 493 | // where fmax = 0.5 / size |
| 528 | | const p11 = 8.877925718782769769445565656611838e-5; |
| 529 | | const p9 = 4.340277777635300605611118803507141e-4 + v64 * p11; |
| 530 | | const p7 = 2.2321428571428572515097318595359542e-3 + v * p9; |
| 531 | | const p5 = 1.249999999999999999999963839743372e-2 + v * p7; |
| 532 | | const p3 = 8.333333333333333333333333333372414e-2 + v * p5; |
| 533 | | |
| 534 | | const q = u * v * p3; |
| 494 | const poly: impl.Proc1.Poly = .{ |
| 495 | .a1 = 1.0, |
| 496 | .a3 = 8.333333333333333333333333333372414e-2, |
| 497 | .a5 = 1.249999999999999999999963839743372e-2, |
| 498 | .a7 = 2.2321428571428572515097318595359542e-3, |
| 499 | .a9 = 4.340277777635300605611118803507141e-4, |
| 500 | .a11 = 8.877925718782769769445565656611838e-5, |
| 501 | }; |
| 535 | 502 | |
| 536 | | // log1p_tab[j].hi = 2^-n * round-to-integer(2^n * l) |
| 537 | | // log1p_tab[j].lo = round-to-nearest-f128(l - log1p_tab[j].hi) |
| 503 | // tab[j].hi = 2^-n * round-to-integer(2^n * l) |
| 504 | // tab[j].lo = round-to-nearest-f128(l - tab[j].hi) |
| 538 | 505 | // where n = 97 and l = log(1 + j / size) |
| 539 | | const log1p_tab = [size + 1]struct { hi: f128, lo: f128 }{ |
| 506 | const tab = [impl.size + 1]impl.Proc1.HiLo{ |
| 540 | 507 | .{ .hi = 0, .lo = 0 }, |
| 541 | 508 | .{ .hi = 0x1.fe02a6b106788fc3769039p-8, .lo = 0x1.dc282d2b3db2c3ef9a073a876702p-100 }, |
| 542 | 509 | .{ .hi = 0x1.fc0a8b0fc03e3cf9eda74d4p-7, .lo = -0x1.0a8552414fc416fc223acca2ebfp-100 }, |
| ... | ... | @@ -667,11 +634,8 @@ pub fn logq(x: f128) callconv(.c) f128 { |
| 667 | 634 | .{ .hi = 0x1.60e32f44788d8ca7c895a0b5p-1, .lo = -0x1.3557995d063914a66aa81ead3fdbp-101 }, |
| 668 | 635 | .{ .hi = 0x1.62e42fefa39ef35793c7673p-1, .lo = 0x1.f97b57a079a193394c5b16c5068cp-103 }, |
| 669 | 636 | }; |
| 670 | | const xm: f128 = @floatFromInt(m); |
| 671 | | const l_hi = xm * log1p_tab[128].hi + log1p_tab[j].hi; |
| 672 | | const l_lo = xm * log1p_tab[128].lo + log1p_tab[j].lo; |
| 673 | 637 | |
| 674 | | return l_hi + (u + (q + l_lo)); |
| 638 | return impl.proc1(.{ .poly = poly, .tab = tab }, x); |
| 675 | 639 | } |
| 676 | 640 | |
| 677 | 641 | pub fn logl(x: c_longdouble) callconv(.c) c_longdouble { |