ref: cec2ed10f355e59322f3d148837dca47aab083a6
dir: /lib/math/log-impl.myr/
use std use "fpmath" use "util" /* See [Mul16] (6.2.2) and [Tan90]. */ pkg math = pkglocal const log32 : (x : flt32 -> flt32) pkglocal const log64 : (x : flt64 -> flt64) pkglocal const log1p32 : (x : flt32 -> flt32) pkglocal const log1p64 : (x : flt64 -> flt64) /* Constants from [Tan90], note that [128] contains accurate log(2) */ pkglocal const accurate_logs32 : (uint32, uint32)[129] pkglocal const accurate_logs64 : (uint64, uint64)[129] ;; extern const horner_polyu32 : (f : flt32, a : uint32[:] -> flt32) extern const horner_polyu64 : (f : flt64, a : uint64[:] -> flt64) type fltdesc(@f, @u, @i) = struct explode : (f : @f -> (bool, @i, @u)) assem : (n : bool, e : @i, s : @u -> @f) horner : (f : @f, a : @u[:] -> @f) tobits : (f : @f -> @u) frombits : (u : @u -> @f) sgnmask : @u sig8mask : @u sig8last : @u emin : @i emax : @i precision : @u inf : @u ninf : @u nan : @u /* For log */ logT1 : @u logT2 : @u /* For log1p */ log1pT1 : @u log1pT2 : @u T3exp : @u /* For procedure 1 */ C : (@u, @u)[:] Ai : @u[:] /* For procedure 2 */ Bi : @u[:] Mtruncmask : @u ;; /* Accurate representations for log(1 + j/2^7), all j */ const accurate_logs32 = [ (0000000000, 0000000000), (0x3bff0000, 0x3429ac42), (0x3c7e0000, 0x35a8b0fc), (0x3cbdc000, 0x368d83eb), (0x3cfc2000, 0xb6b278c4), (0x3d1cf000, 0x3687b9ff), (0x3d3ba000, 0x3631ec66), (0x3d5a1000, 0x36dd7119), (0x3d785000, 0x35c30046), (0x3d8b2800, 0x365bba8e), (0x3d9a1000, 0xb621a791), (0x3da8d800, 0x34e7e0c3), (0x3db78800, 0xb635d46a), (0x3dc61800, 0x368bac63), (0x3dd49000, 0x36da7496), (0x3de2f000, 0x36a91eb8), (0x3df13800, 0x34edc55e), (0x3dff6800, 0xb6dd9c48), (0x3e06bc00, 0xb44197b9), (0x3e0db800, 0x36ab54be), (0x3e14ac00, 0xb6b41f80), (0x3e1b9000, 0xb4f7f85c), (0x3e226800, 0x36adb32e), (0x3e293800, 0xb650e2f2), (0x3e2ff800, 0x36c1c29e), (0x3e36b000, 0x35fe719d), (0x3e3d5c00, 0x3590210e), (0x3e43fc00, 0x36819483), (0x3e4a9400, 0xb6958c2f), (0x3e511c00, 0x36f07f8b), (0x3e57a000, 0xb6dac5fd), (0x3e5e1400, 0x354e85b2), (0x3e648000, 0xb5838656), (0x3e6ae000, 0x3685ad3f), (0x3e713800, 0x356dc55e), (0x3e778400, 0x36b72f71), (0x3e7dc800, 0x36436af2), (0x3e820200, 0xb6d35a59), (0x3e851a00, 0xb6d8ec63), (0x3e882c00, 0x363f9ae5), (0x3e8b3a00, 0x36e55d5d), (0x3e8e4400, 0x36c60b4d), (0x3e914a00, 0x34fde7bd), (0x3e944a00, 0x36d09ef4), (0x3e974800, 0xb6ea28f7), (0x3e9a3e00, 0x36ecd4c4), (0x3e9d3200, 0x36455694), (0x3ea02200, 0xb6779796), (0x3ea30c00, 0x363c21c6), (0x3ea5f200, 0x36fcabbc), (0x3ea8d600, 0xb693c690), (0x3eabb400, 0xb60e8baa), (0x3eae8e00, 0xb51029fe), (0x3eb16400, 0x353cae72), (0x3eb43600, 0x3601e9b1), (0x3eb70400, 0x366aa2ba), (0x3eb9ce00, 0x36bfb5df), (0x3ebc9600, 0xb6d50116), (0x3ebf5800, 0xb5f88faa), (0x3ec21600, 0x368ed0f4), (0x3ec4d200, 0xb64793ec), (0x3ec78800, 0x36f439b3), (0x3eca3c00, 0x36a0e109), (0x3eccec00, 0x36ac08bf), (0x3ecf9a00, 0xb6e09a03), (0x3ed24200, 0x3410e5bb), (0x3ed4e800, 0xb69b2b30), (0x3ed78a00, 0xb6b66dc4), (0x3eda2800, 0xb6084337), (0x3edcc200, 0x36c4b499), (0x3edf5a00, 0x3659da72), (0x3ee1ee00, 0x36bd3e6d), (0x3ee48000, 0xb6038656), (0x3ee70e00, 0xb687a3d0), (0x3ee99800, 0xb4c0ff8a), (0x3eec2000, 0xb6c6d3af), (0x3eeea400, 0xb6afd9f2), (0x3ef12400, 0x3601a7c7), (0x3ef3a200, 0x351875a2), (0x3ef61c00, 0x36ce9234), (0x3ef89400, 0x3675faf0), (0x3efb0a00, 0xb6e02c7f), (0x3efd7a00, 0x36c47bc8), (0x3effea00, 0xb68fbd40), (0x3f012b00, 0xb6d5a5a3), (0x3f025f00, 0xb444adb2), (0x3f039200, 0xb551f190), (0x3f04c300, 0x36f4f573), (0x3f05f400, 0xb6d1bdad), (0x3f072200, 0x36985d1d), (0x3f085000, 0xb6c61d2b), (0x3f097c00, 0xb6e6a6c1), (0x3f0aa600, 0x35f4bd35), (0x3f0bcf00, 0x36abbd8a), (0x3f0cf700, 0x36568cf9), (0x3f0e1e00, 0xb67c11d8), (0x3f0f4300, 0xb4a18fbf), (0x3f106700, 0xb5cb9b55), (0x3f118a00, 0xb6f28414), (0x3f12ab00, 0xb6062ce1), (0x3f13cb00, 0xb576bb27), (0x3f14ea00, 0xb68013d5), (0x3f160700, 0x369ed449), (0x3f172400, 0xb6bc91c0), (0x3f183f00, 0xb68ccb0f), (0x3f195900, 0xb6cc6ede), (0x3f1a7100, 0x3689d9ce), (0x3f1b8900, 0xb684ab8c), (0x3f1c9f00, 0x34d3562a), (0x3f1db400, 0x36094000), (0x3f1ec800, 0x359a9c56), (0x3f1fdb00, 0xb60f65d2), (0x3f20ec00, 0x36fe8467), (0x3f21fd00, 0xb368318d), (0x3f230c00, 0x36bc21c6), (0x3f241b00, 0xb6c2e157), (0x3f252800, 0xb67449f8), (0x3f263400, 0xb64a0662), (0x3f273f00, 0xb67dc915), (0x3f284900, 0xb6c33fe9), (0x3f295100, 0x36d265bc), (0x3f2a5900, 0x360cf333), (0x3f2b6000, 0xb6454982), (0x3f2c6500, 0x36db5cd8), (0x3f2d6a00, 0x34186b3e), (0x3f2e6e00, 0xb6e2393f), (0x3f2f7000, 0x35aa4906), (0x3f307200, 0xb6d0bb87), (0x3f317200, 0x35bfbe8e), /* Note C[128] is log2 */ ] const accurate_logs64 = [ (000000000000000000, 000000000000000000), (0x3f7fe02a6b200000, 0xbd6f30ee07912df9), (0x3f8fc0a8b1000000, 0xbd5fe0e183092c59), (0x3f97b91b07d80000, 0xbd62772ab6c0559c), (0x3f9f829b0e780000, 0x3d2980267c7e09e4), (0x3fa39e87ba000000, 0xbd642a056fea4dfd), (0x3fa77458f6340000, 0xbd62303b9cb0d5e1), (0x3fab42dd71180000, 0x3d671bec28d14c7e), (0x3faf0a30c0100000, 0x3d662a6617cc9717), (0x3fb16536eea40000, 0xbd60a3e2f3b47d18), (0x3fb341d7961c0000, 0xbd4717b6b33e44f8), (0x3fb51b073f060000, 0x3d383f69278e686a), (0x3fb6f0d28ae60000, 0xbd62968c836cc8c2), (0x3fb8c345d6320000, 0xbd5937c294d2f567), (0x3fba926d3a4a0000, 0x3d6aac6ca17a4554), (0x3fbc5e548f5c0000, 0xbd4c5e7514f4083f), (0x3fbe27076e2a0000, 0x3d6e5cbd3d50fffc), (0x3fbfec9131dc0000, 0xbd354555d1ae6607), (0x3fc0d77e7cd10000, 0xbd6c69a65a23a170), (0x3fc1b72ad52f0000, 0x3d69e80a41811a39), (0x3fc29552f8200000, 0xbd35b967f4471dfc), (0x3fc371fc201f0000, 0xbd6c22f10c9a4ea8), (0x3fc44d2b6ccb0000, 0x3d6f4799f4f6543e), (0x3fc526e5e3a20000, 0xbd62f21746ff8a47), (0x3fc5ff3070a80000, 0xbd6b0b0de3077d7e), (0x3fc6d60fe71a0000, 0xbd56f1b955c4d1da), (0x3fc7ab8902110000, 0xbd537b720e4a694b), (0x3fc87fa065210000, 0xbd5b77b7effb7f41), (0x3fc9525a9cf40000, 0x3d65ad1d904c1d4e), (0x3fca23bc1fe30000, 0xbd62a739b23b93e1), (0x3fcaf3c94e810000, 0xbd600349cc67f9b2), (0x3fcbc286742e0000, 0xbd6cca75818c5dbc), (0x3fcc8ff7c79b0000, 0xbd697794f689f843), (0x3fcd5c216b500000, 0xbd611ba91bbca682), (0x3fce27076e2b0000, 0xbd3a342c2af0003c), (0x3fcef0adcbdc0000, 0x3d664d948637950e), (0x3fcfb9186d5e0000, 0x3d5f1546aaa3361c), (0x3fd0402594b50000, 0xbd67df928ec217a5), (0x3fd0a324e2738000, 0x3d50e35f73f7a018), (0x3fd1058bf9ae8000, 0xbd6a9573b02faa5a), (0x3fd1675cabab8000, 0x3d630701ce63eab9), (0x3fd1c898c1698000, 0x3d59fafbc68e7540), (0x3fd22941fbcf8000, 0xbd3a6976f5eb0963), (0x3fd2895a13de8000, 0x3d3a8d7ad24c13f0), (0x3fd2e8e2bae10000, 0x3d5d309c2cc91a85), (0x3fd347dd9a988000, 0xbd25594dd4c58092), (0x3fd3a64c55698000, 0xbd6d0b1c68651946), (0x3fd4043086868000, 0x3d63f1de86093efa), (0x3fd4618bc21c8000, 0xbd609ec17a426426), (0x3fd4be5f95778000, 0xbd3d7c92cd9ad824), (0x3fd51aad872e0000, 0xbd3f4bd8db0a7cc1), (0x3fd5767717458000, 0xbd62c9d5b2a49af9), (0x3fd5d1bdbf580000, 0x3d4394a11b1c1ee4), (0x3fd62c82f2ba0000, 0xbd6c356848506ead), (0x3fd686c81e9b0000, 0x3d54aec442be1015), (0x3fd6e08eaa2b8000, 0x3d60f1c609c98c6c), (0x3fd739d7f6bc0000, 0xbd67fcb18ed9d603), (0x3fd792a55fdd8000, 0xbd6c2ec1f512dc03), (0x3fd7eaf83b828000, 0x3d67e1b259d2f3da), (0x3fd842d1da1e8000, 0x3d462e927628cbc2), (0x3fd89a3386c18000, 0xbd6ed2a52c73bf78), (0x3fd8f11e87368000, 0xbd5d3881e8962a96), (0x3fd947941c210000, 0x3d56faba4cdd147d), (0x3fd99d9581180000, 0xbd5f753456d113b8), (0x3fd9f323ecbf8000, 0x3d584bf2b68d766f), (0x3fda484090e58000, 0x3d6d8515fe535b87), (0x3fda9cec9a9a0000, 0x3d40931a909fea5e), (0x3fdaf12932478000, 0xbd3e53bb31eed7a9), (0x3fdb44f77bcc8000, 0x3d4ec5197ddb55d3), (0x3fdb985896930000, 0x3d50fb598fb14f89), (0x3fdbeb4d9da70000, 0x3d5b7bf7861d37ac), (0x3fdc3dd7a7cd8000, 0x3d66a6b9d9e0a5bd), (0x3fdc8ff7c79a8000, 0x3d5a21ac25d81ef3), (0x3fdce1af0b860000, 0xbd48290905a86aa6), (0x3fdd32fe7e010000, 0xbd542a9e21373414), (0x3fdd83e7258a0000, 0x3d679f2828add176), (0x3fddd46a04c20000, 0xbd6dafa08cecadb1), (0x3fde24881a7c8000, 0xbd53d9e34270ba6b), (0x3fde744261d68000, 0x3d3e1f8df68dbcf3), (0x3fdec399d2468000, 0x3d49802eb9dca7e7), (0x3fdf128f5faf0000, 0x3d3bb2cd720ec44c), (0x3fdf6123fa700000, 0x3d645630a2b61e5b), (0x3fdfaf588f790000, 0xbd49c24ca098362b), (0x3fdffd2e08580000, 0xbd46cf54d05f9367), (0x3fe02552a5a5c000, 0x3d60fec69c695d7f), (0x3fe04bdf9da94000, 0xbd692d9a033eff75), (0x3fe0723e5c1cc000, 0x3d6f404e57963891), (0x3fe0986f4f574000, 0xbd55be8dc04ad601), (0x3fe0be72e4254000, 0xbd657d49676844cc), (0x3fe0e44985d1c000, 0x3d5917edd5cbbd2d), (0x3fe109f39e2d4000, 0x3d592dfbc7d93617), (0x3fe12f7195940000, 0xbd6043acfedce638), (0x3fe154c3d2f4c000, 0x3d65e9a98f33a396), (0x3fe179eabbd88000, 0x3d69a0bfc60e6fa0), (0x3fe19ee6b467c000, 0x3d52dd98b97baef0), (0x3fe1c3b81f714000, 0xbd3eda1b58389902), (0x3fe1e85f5e704000, 0x3d1a07bd8b34be7c), (0x3fe20cdcd192c000, 0xbd64926cafc2f08a), (0x3fe23130d7bec000, 0xbd17afa4392f1ba7), (0x3fe2555bce990000, 0xbd506987f78a4a5e), (0x3fe2795e1289c000, 0xbd5dca290f81848d), (0x3fe29d37fec2c000, 0xbd5eea6f465268b4), (0x3fe2c0e9ed448000, 0x3d5d1772f5386374), (0x3fe2e47436e40000, 0x3d334202a10c3491), (0x3fe307d7334f0000, 0x3d60be1fb590a1f5), (0x3fe32b1339120000, 0x3d6d71320556b67b), (0x3fe34e289d9d0000, 0xbd6e2ce9146d277a), (0x3fe37117b5474000, 0x3d4ed71774092113), (0x3fe393e0d3564000, 0xbd65e6563bbd9fc9), (0x3fe3b6844a000000, 0xbd3eea838909f3d3), (0x3fe3d9026a714000, 0x3d66faa404263d0b), (0x3fe3fb5b84d18000, 0xbd60bda4b162afa3), (0x3fe41d8fe8468000, 0xbd5aa33736867a17), (0x3fe43f9fe2f9c000, 0x3d5ccef4e4f736c2), (0x3fe4618bc21c4000, 0x3d6ec27d0b7b37b3), (0x3fe48353d1ea8000, 0x3d51bee7abd17660), (0x3fe4a4f85db04000, 0xbd244fdd840b8591), (0x3fe4c679afcd0000, 0xbd61c64e971322ce), (0x3fe4e7d811b74000, 0x3d6bb09cb0985646), (0x3fe50913cc018000, 0xbd6794b434c5a4f5), (0x3fe52a2d265bc000, 0x3d46abb9df22bc57), (0x3fe54b2467998000, 0x3d6497a915428b44), (0x3fe56bf9d5b40000, 0xbd58cd7dc73bd194), (0x3fe58cadb5cd8000, 0xbd49db3db43689b4), (0x3fe5ad404c358000, 0x3d6f2cfb29aaa5f0), (0x3fe5cdb1dc6c0000, 0x3d67648cf6e3c5d7), (0x3fe5ee02a9240000, 0x3d667570d6095fd2), (0x3fe60e32f4478000, 0x3d51b194f912b417), (0x3fe62e42fefa4000, 0xbd48432a1b0e2634), ] const desc32 : fltdesc(flt32, uint32, int32) = [ .explode = std.flt32explode, .assem = std.flt32assem, .horner = horner_polyu32, .tobits = std.flt32bits, .frombits = std.flt32frombits, .sgnmask = (1 << 31), .sig8mask = 0xffff0000, /* Mask to get 8 significant bits */ .sig8last = 16, /* Last bit kept when masking */ .emin = -126, .emax = 127, .precision = 24, .inf = 0x7f800000, .ninf = 0xff800000, .nan = 0x7fc00000, .logT1 = 0x3f707d5f, /* Just smaller than e^(-1/16) ~= 0.939413 */ .logT2 = 0x3f88415b, /* Just larger than e^(1/16) ~= 1.06449 */ .log1pT1 = 0xbd782a03, /* Just smaller than e^(-1/16) - 1 ~= -0.0605869 */ .log1pT2 = 0x3d8415ac, /* Just larger than e^(1/16) - 1 ~= 0.06449445 */ .T3exp = 26, /* Beyond 2^T3exp, 1 + x rounds to x */ .C = accurate_logs32[:], .Ai = [ 0x3daaaac2 ][:], /* Coefficients for log(1 + f/F) */ .Bi = [ /* Coefficients for log(1 + f) in terms of a = 2f/(2 + f) */ 0x3daaaaa9, 0x3c4d0095, ][:], .Mtruncmask = 0xfffff000, /* Mask to get 12 significant bits */ ] const desc64 : fltdesc(flt64, uint64, int64) = [ .explode = std.flt64explode, .assem = std.flt64assem, .horner = horner_polyu64, .tobits = std.flt64bits, .frombits = std.flt64frombits, .sgnmask = (1 << 63), .sig8mask = 0xffffe00000000000, /* Mask to get 8 significant bits */ .sig8last = 45, /* Last bit kept when masking */ .emin = -1022, .emax = 1023, .precision = 53, .inf = 0x7ff0000000000000, .ninf = 0xfff0000000000000, .nan = 0x7ff8000000000000, .logT1 = 0x3fee0fabfbc702a3, /* Just smaller than e^(-1/16) ~= 0.939413 */ .logT2 = 0x3ff1082b577d34ee, /* Just larger than e^(1/16) ~= 1.06449 */ .log1pT1 = 0xbfaf0540428fd5c4, /* Just smaller than e^(-1/16) - 1 ~= -0.0605869 */ .log1pT2 = 0x3fb082b577d34ed8, /* Just larger than e^(1/16) - 1 ~= 0.06449445 */ .T3exp = 55, /* Beyond 2^T3exp, 1 + x rounds to x */ .C = accurate_logs64[:], .Ai = [ 0x3fb5555555550286, 0x3f8999a0bc712416, ][:], .Bi = [ 0x3fb55555555554e6, 0x3f89999999bac6d4, 0x3f62492307f1519f, 0x3f3c8034c85dfff0, ][:], .Mtruncmask = 0xfffffffff0000000, /* Mask to get 24 significant bits */ ] const log32 = {x : flt32 -> loggen(x, desc32) } const log64 = {x : flt64 -> loggen(x, desc64) } generic loggen = {x : @f, d : fltdesc(@f, @u, @i) :: numeric,floating @f, numeric,integral @u, numeric,integral @i, roundable @f -> @i var b = d.tobits(x) var n : bool, e : @i, s : @u (n, e, s) = d.explode(x) /* Special cases for NaN, +/- 0, < 0, inf, and 1. There are certain exceptions (inexact, division by 0, &c) that should be flagged in these cases, which we do not honor currently. See [Tan90]. */ if std.isnan(x) -> d.frombits(d.nan) elif (b & ~d.sgnmask == 0) -> d.frombits(d.ninf) elif n -> d.frombits(d.nan) elif (b == d.inf) -> x elif std.eq(x, (1.0 : @f)) -> (0.0 : @f) ;; /* If x is close to 1, polynomial log1p(x - 1) will be sufficient */ if (d.logT1 < b && b < d.logT2) -> procedure_2(x - (1.0 : @f), d) ;; /* Reduce x to 2^m * (F + f), with (F + f) in [1, 2), so procedure_2's tables work. We also require that F have only 8 significant bits. */ var m : @i, Y : @f, F : @f, f : @f if e < d.emin /* Normalize significand */ var first_1 = find_first1_64((s : uint64), (d.precision : int64)) var offset = (d.precision : @u) - 1 - (first_1 : @u) s = s << offset e = d.emin - offset ;; m = e Y = d.assem(false, 0, s) if need_round_away(0, (s : uint64), (d.sig8last : int64)) F = d.frombits((d.tobits(Y) & d.sig8mask) + (1 << d.sig8last)) else F = d.frombits(d.tobits(Y) & d.sig8mask) ;; f = Y - F -> procedure_1(m, F, f, Y, d) } const log1p32 = {x : flt32 -> log1pgen(x, desc32) } const log1p64 = {x : flt64 -> log1pgen(x, desc64) } generic log1pgen = {x : @f, d : fltdesc(@f, @u, @i) :: numeric,floating @f, numeric,integral @u, numeric,integral @i, roundable @f -> @i var b = d.tobits(x) var n, e, s (n, e, s) = d.explode(x) /* Special cases for NaN, +/- 0, < 0, inf, and 1. There are certain exceptions (inexact, division by 0, &c) that should be flagged in these cases, which we do not honor currently. See [Tan90]. */ if std.isnan(x) -> d.frombits(d.nan) elif (b & ~d.sgnmask == 0) -> x elif std.eq(x, (-1.0 : @f)) -> d.frombits(d.nan | d.sgnmask) elif x < (-1.0 : @f) -> d.frombits(d.nan) elif (b == d.inf) -> x ;; /* If x is small enough that 1 + x rounds to 1, return x */ if e < (-d.precision : @i) -> x ;; /* If x is close to 0, use polynomial */ if (n && b < d.log1pT1) || (!n && b < d.log1pT2) -> procedure_2(x, d) ;; /* Reduce x m, F, f as in log case. However, since we're approximating 1 + x, more care has to be taken (for example: 1 + x might be infinity). */ var Y, m, F, f if e > d.T3exp Y = x else Y = (1.0 : @f) + x ;; /* y must be normal, otherwise x would have been -1 + (subnormal), but that would round to -1. */ var ny, ey, sy (ny, ey, sy) = d.explode(Y) m = ey Y = d.assem(ny, 0, sy) if need_round_away(0, (sy : uint64), (d.sig8last : int64)) F = d.frombits((d.tobits(Y) & d.sig8mask) + (1 << d.sig8last)) else F = d.frombits(d.tobits(Y) & d.sig8mask) ;; /* f is trickier to compute than in the exp case, because the scale of the 1 is unknown near x. */ if m <= -2 f = Y - F elif m <= d.precision - 1 f = (d.assem(false, -m, 0) - F) + scale2(x, -m) else f = (scale2(x, -m) - F) + d.assem(false, -m, 0) ;; -> procedure_1(m, F, f, Y, d) } /* Approximate log(2^m * (F + f)) by tables */ generic procedure_1 = {m : @i, F : @f, f : @f, Y : @f, d : fltdesc(@f, @u, @i) :: numeric,floating @f, numeric,integral @u, numeric,integral @i, roundable @f -> @i /* We must compute log(2^m * (F + f)) = m log(2) + log(F) + log(1 + f/F). Only this last term need be approximated, since log(2) and log(F) may be precomputed. For computing log(1 + f/F), [Tan90] gives two alternatives. We choose step 3', which requires floating-point division, but allows us to save approximately 2.5 KiB of precomputed values. F is some 1 + j2^(-7), so first we compute j. Note that j could actually be 128 (Ex: x = 0x4effac00.) */ var j var nF, eF, sF (nF, eF, sF) = d.explode(F) if eF != 0 j = 128 else j = 0x7f & (((d.sig8mask & sF) >> d.sig8last) - 0x80) ;; var Cu_hi, Cu_lo, log2_hi, log2_lo (Cu_hi, Cu_lo) = d.C[j] (log2_hi, log2_lo) = d.C[128] var L_hi = (m : @f) * d.frombits(log2_hi) + d.frombits(Cu_hi) var L_lo = (m : @f) * d.frombits(log2_lo) + d.frombits(Cu_lo) var u = ((2.0 : @f) * f)/(Y + F) var v = u * u var q = u * v * d.horner(v, d.Ai) -> L_hi + (u + (q + L_lo)) } /* Approximate log1p by polynomial */ generic procedure_2 = {f : @f, d : fltdesc(@f, @u, @i) :: numeric,floating @f, numeric,integral @u, numeric,integral @i, roundable @f -> @i var g = (1.0 : @f)/((2.0 : @f) + f) var u = (2.0 : @f) * f * g var v = u * u var q = u * v * d.horner(v, d.Bi) /* 1 / (2 + f) in working precision was good enough for the polynomial evaluation, but to complete the approximation we need to add 2f/(2 + f) with higher precision than working. So we go back and compute better, split u. */ var u1 = d.frombits(d.Mtruncmask & d.tobits(u)) var f1 = d.frombits(d.Mtruncmask & d.tobits(f)) var f2 = f - f1 var u2 = (((2.0 : @f) * (f - u1) - u1 * f1) - u1 * f2) * g -> u1 + (u2 + q) }