[libc][math] Implement double precision log function correctly rounded to all rounding modes.

Implement double precision log function correctly rounded to all
rounding modes.

See https://reviews.llvm.org/D150014 for a more detail description of the algorithm.

**Performance**

  - For `0.5 <= x <= 2`, the fast pass hitting rate is about 99.93%.

  - Reciprocal throughput from CORE-MATH's perf tool on Ryzen 5900X:
```
$ ./perf.sh log
GNU libc version: 2.35
GNU libc release: stable

-- CORE-MATH reciprocal throughput -- with FMA
[####################] 100 %
Ntrial = 20 ; Min = 17.465 + 0.596 clc/call; Median-Min = 0.602 clc/call; Max = 18.389 clc/call;

-- CORE-MATH reciprocal throughput -- without FMA (-march=x86-64-v2)
[####################] 100 %
Ntrial = 20 ; Min = 54.961 + 2.606 clc/call; Median-Min = 2.180 clc/call; Max = 59.583 clc/call;

-- System LIBC reciprocal throughput --
[####################] 100 %
Ntrial = 20 ; Min = 12.608 + 0.276 clc/call; Median-Min = 0.359 clc/call; Max = 13.147 clc/call;

-- LIBC reciprocal throughput -- with FMA
[####################] 100 %
Ntrial = 20 ; Min = 20.952 + 0.468 clc/call; Median-Min = 0.602 clc/call; Max = 21.881 clc/call;

-- LIBC reciprocal throughput -- without FMA
[####################] 100 %
Ntrial = 20 ; Min = 18.569 + 0.552 clc/call; Median-Min = 0.601 clc/call; Max = 19.259 clc/call;

```
  - Latency from CORE-MATH's perf tool on Ryzen 5900X:
```
$ ./perf.sh log --latency
GNU libc version: 2.35
GNU libc release: stable

-- CORE-MATH latency -- with FMA
[####################] 100 %
Ntrial = 20 ; Min = 48.431 + 0.699 clc/call; Median-Min = 0.073 clc/call; Max = 51.269 clc/call;

-- CORE-MATH latency -- without FMA (-march=x86-64-v2)
[####################] 100 %
Ntrial = 20 ; Min = 64.865 + 3.235 clc/call; Median-Min = 3.475 clc/call; Max = 71.788 clc/call;

-- System LIBC latency --
[####################] 100 %
Ntrial = 20 ; Min = 42.151 + 2.090 clc/call; Median-Min = 2.270 clc/call; Max = 44.773 clc/call;

-- LIBC latency -- with FMA
[####################] 100 %
Ntrial = 20 ; Min = 35.266 + 0.479 clc/call; Median-Min = 0.373 clc/call; Max = 36.798 clc/call;

-- LIBC latency -- without FMA
[####################] 100 %
Ntrial = 20 ; Min = 48.518 + 0.484 clc/call; Median-Min = 0.500 clc/call; Max = 49.896 clc/call;
```
  - Accurate pass latency:
```
$ ./perf.sh log --latency --simple_stat
GNU libc version: 2.35
GNU libc release: stable

-- CORE-MATH latency -- with FMA
598.306

-- CORE-MATH latency -- without FMA (-march=x86-64-v2)
632.925

-- LIBC latency -- with FMA
455.632

-- LIBC latency -- without FMA
488.564
```

Reviewed By: zimmermann6

Differential Revision: https://reviews.llvm.org/D150131
This commit is contained in:
Tue Ly 2023-05-08 14:03:52 -04:00
parent cc6a6c48d4
commit a68bbf42fa
15 changed files with 1866 additions and 777 deletions

View File

@ -178,6 +178,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.log10f
libc.src.math.log1pf
libc.src.math.log2f
libc.src.math.log
libc.src.math.logf
libc.src.math.logb
libc.src.math.logbf

View File

@ -289,6 +289,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.log10f
libc.src.math.log1pf
libc.src.math.log2f
libc.src.math.log
libc.src.math.logf
libc.src.math.logb
libc.src.math.logbf

View File

@ -294,6 +294,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.log10f
libc.src.math.log1pf
libc.src.math.log2f
libc.src.math.log
libc.src.math.logf
libc.src.math.logb
libc.src.math.logbf

View File

@ -171,6 +171,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.log10f
libc.src.math.log1pf
libc.src.math.log2f
libc.src.math.log
libc.src.math.logf
libc.src.math.logb
libc.src.math.logbf

View File

@ -412,6 +412,7 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"log2f", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"log", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
FunctionSpec<"logf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"logb", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,

View File

@ -118,6 +118,7 @@ add_math_entrypoint_object(log1pf)
add_math_entrypoint_object(log2f)
add_math_entrypoint_object(log)
add_math_entrypoint_object(logf)
add_math_entrypoint_object(logb)

View File

@ -768,6 +768,15 @@ add_object_library(
libc.src.__support.number_pair
)
add_header_library(
log_range_reduction
HDRS
log_range_reduction.h
DEPENDS
.common_constants
libc.src.__support.FPUtil.dyadic_float
)
add_entrypoint_object(
log10
SRCS
@ -776,6 +785,7 @@ add_entrypoint_object(
../log10.h
DEPENDS
.common_constants
.log_range_reduction
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.multiply_add
@ -840,6 +850,26 @@ add_entrypoint_object(
-O3
)
add_entrypoint_object(
log
SRCS
log.cpp
HDRS
../log.h
DEPENDS
.common_constants
.log_range_reduction
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.multiply_add
libc.src.__support.FPUtil.polyeval
libc.src.__support.FPUtil.double_double
libc.src.__support.FPUtil.dyadic_float
libc.src.__support.macros.optimization
COMPILE_OPTIONS
-O3
)
add_entrypoint_object(
logf
SRCS

View File

@ -365,6 +365,78 @@ alignas(64) const NumberPair<double> LOG_R_DD[128] = {
{0.0, 0.0},
};
// Logarithm range reduction - Step 2:
// r(k) = 2^-16 round(2^16 / (1 + k*2^-14)) for k = -2^6 .. 2^7.
// Output range:
// [-0x1.3ffcp-15, 0x1.3e3dp-15]
// We store S2[i] = 2^16 (r(i - 2^6) - 1).
alignas(64) const int S2[193] = {
0x101, 0xfd, 0xf9, 0xf5, 0xf1, 0xed, 0xe9, 0xe5, 0xe1,
0xdd, 0xd9, 0xd5, 0xd1, 0xcd, 0xc9, 0xc5, 0xc1, 0xbd,
0xb9, 0xb4, 0xb0, 0xac, 0xa8, 0xa4, 0xa0, 0x9c, 0x98,
0x94, 0x90, 0x8c, 0x88, 0x84, 0x80, 0x7c, 0x78, 0x74,
0x70, 0x6c, 0x68, 0x64, 0x60, 0x5c, 0x58, 0x54, 0x50,
0x4c, 0x48, 0x44, 0x40, 0x3c, 0x38, 0x34, 0x30, 0x2c,
0x28, 0x24, 0x20, 0x1c, 0x18, 0x14, 0x10, 0xc, 0x8,
0x4, 0x0, -0x4, -0x8, -0xc, -0x10, -0x14, -0x18, -0x1c,
-0x20, -0x24, -0x28, -0x2c, -0x30, -0x34, -0x38, -0x3c, -0x40,
-0x44, -0x48, -0x4c, -0x50, -0x54, -0x58, -0x5c, -0x60, -0x64,
-0x68, -0x6c, -0x70, -0x74, -0x78, -0x7c, -0x80, -0x84, -0x88,
-0x8c, -0x90, -0x94, -0x98, -0x9c, -0xa0, -0xa4, -0xa8, -0xac,
-0xb0, -0xb4, -0xb7, -0xbb, -0xbf, -0xc3, -0xc7, -0xcb, -0xcf,
-0xd3, -0xd7, -0xdb, -0xdf, -0xe3, -0xe7, -0xeb, -0xef, -0xf3,
-0xf7, -0xfb, -0xff, -0x103, -0x107, -0x10b, -0x10f, -0x113, -0x117,
-0x11b, -0x11f, -0x123, -0x127, -0x12b, -0x12f, -0x133, -0x137, -0x13a,
-0x13e, -0x142, -0x146, -0x14a, -0x14e, -0x152, -0x156, -0x15a, -0x15e,
-0x162, -0x166, -0x16a, -0x16e, -0x172, -0x176, -0x17a, -0x17e, -0x182,
-0x186, -0x18a, -0x18e, -0x192, -0x195, -0x199, -0x19d, -0x1a1, -0x1a5,
-0x1a9, -0x1ad, -0x1b1, -0x1b5, -0x1b9, -0x1bd, -0x1c1, -0x1c5, -0x1c9,
-0x1cd, -0x1d1, -0x1d5, -0x1d9, -0x1dd, -0x1e0, -0x1e4, -0x1e8, -0x1ec,
-0x1f0, -0x1f4, -0x1f8, -0x1fc};
// Logarithm range reduction - Step 3:
// r(k) = 2^-21 round(2^21 / (1 + k*2^-21)) for k = -80 .. 80.
// Output range:
// [-0x1.01928p-22 , 0x1p-22]
// We store S[i] = 2^21 (r(i - 80) - 1).
alignas(64) const int S3[161] = {
0x50, 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46,
0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b,
0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25,
0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a,
0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0xf,
0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4,
0x3, 0x2, 0x1, 0x0, -0x1, -0x2, -0x3, -0x4, -0x5, -0x6, -0x7,
-0x8, -0x9, -0xa, -0xb, -0xc, -0xd, -0xe, -0xf, -0x10, -0x11, -0x12,
-0x13, -0x14, -0x15, -0x16, -0x17, -0x18, -0x19, -0x1a, -0x1b, -0x1c, -0x1d,
-0x1e, -0x1f, -0x20, -0x21, -0x22, -0x23, -0x24, -0x25, -0x26, -0x27, -0x28,
-0x29, -0x2a, -0x2b, -0x2c, -0x2d, -0x2e, -0x2f, -0x30, -0x31, -0x32, -0x33,
-0x34, -0x35, -0x36, -0x37, -0x38, -0x39, -0x3a, -0x3b, -0x3c, -0x3d, -0x3e,
-0x3f, -0x40, -0x41, -0x42, -0x43, -0x44, -0x45, -0x46, -0x47, -0x48, -0x49,
-0x4a, -0x4b, -0x4c, -0x4d, -0x4e, -0x4f, -0x50,
};
// Logarithm range reduction - Step 4
// r(k) = 2^-28 round(2^28 / (1 + k*2^-28)) for k = -65 .. 64.
// Output range:
// [-0x1.0002143p-29 , 0x1p-29]
// We store S[i] = 2^28 (r(i - 65) - 1).
alignas(64) const int S4[130] = {
0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37,
0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c,
0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21,
0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0xf, 0xe, 0xd, 0xc, 0xb,
0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0,
-0x1, -0x2, -0x3, -0x4, -0x5, -0x6, -0x7, -0x8, -0x9, -0xa, -0xb,
-0xc, -0xd, -0xe, -0xf, -0x10, -0x11, -0x12, -0x13, -0x14, -0x15, -0x16,
-0x17, -0x18, -0x19, -0x1a, -0x1b, -0x1c, -0x1d, -0x1e, -0x1f, -0x20, -0x21,
-0x22, -0x23, -0x24, -0x25, -0x26, -0x27, -0x28, -0x29, -0x2a, -0x2b, -0x2c,
-0x2d, -0x2e, -0x2f, -0x30, -0x31, -0x32, -0x33, -0x34, -0x35, -0x36, -0x37,
-0x38, -0x39, -0x3a, -0x3b, -0x3c, -0x3d, -0x3e, -0x3f, -0x40,
};
// Lookup table for exp(m) with m = -104, ..., 89.
// -104 = floor(log(single precision's min denormal))
// 89 = ceil(log(single precision's max normal))

View File

@ -39,6 +39,11 @@ constexpr double LOG_COEFFS[6] = {-0x1.fffffffffffffp-2, 0x1.5555555554a9bp-2,
-0x1.0000000094567p-2, 0x1.99999dcc9823cp-3,
-0x1.55550ac2e537ap-3, 0x1.21a02c4e624d7p-3};
// Logarithm Range Reduction - Step 2, 3, and 4.
extern const int S2[193];
extern const int S3[161];
extern const int S4[130];
// log(2) generated by Sollya with:
// > a = 2^-43 * nearestint(2^43*log(2));
// LSB = 2^-43 is chosen so that e_x * LOG_2_HI is exact for -1075 < e_x < 1024.

View File

@ -0,0 +1,835 @@
//===-- Double-precision log(x) function ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "src/math/log.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/double_double.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/common.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "common_constants.h"
#include "log_range_reduction.h"
namespace __llvm_libc {
// 128-bit precision dyadic floating point numbers.
using Float128 = typename fputil::DyadicFloat<128>;
using MType = typename Float128::MantissaType;
namespace {
// A simple upper bound for the error of e_x * log(2) - log(r).
constexpr double HI_ERR = 0x1.0p-85;
// Extra errors from P is from using x^2 to reduce evaluation latency.
constexpr double P_ERR = 0x1.0p-50;
// log(2) with 128-bit prepcision generated by SageMath with:
// sage: (s, m, e) = RealField(128)(2).log().sign_mantissa_exponent();
// sage: print("MType({", hex(m % 2^64), ",", hex((m >> 64) % 2^64), "})");
const Float128 LOG_2(/*sign=*/false, /*exponent=*/-128, /*mantissa=*/
MType({0xc9e3b39803f2f6af, 0xb17217f7d1cf79ab}));
alignas(64) const LogRR LOG_TABLE = {
// -log(r) with 128-bit precision generated by SageMath with:
//
// for i in range(128):
// r = 2^-8 * ceil( 2^8 * (1 - 2^(-8)) / (1 + i*2^(-7)) );
// s, m, e = RealField(128)(r).log().sign_mantissa_exponent();
// print("{false,", e, ", MType({", hex(m % 2^64), ",", hex((m >> 64) %
// 2^64),
// "})},");
/* .step_1= */ {
{false, 0, MType(0)},
{false, -134, MType({0x662d417ced007a46, 0x8080abac46f38946})},
{false, -133, MType({0x91d082dce3ddcd38, 0x8102b2c49ac23a4f})},
{false, -133, MType({0xda5f3cc0b3251dbd, 0xc24929464655f45c})},
{false, -132, MType({0xb9e3aea6c444ef07, 0x820aec4f3a222380})},
{false, -132, MType({0x521016bd904dc968, 0xa33576a16f1f4c64})},
{false, -132, MType({0xbe97660a23cc540d, 0xc4a550a4fd9a19a8})},
{false, -132, MType({0xe09f5fe2058d6006, 0xe65b9e6eed965c36})},
{false, -131, MType({0x1fecdfa819b96098, 0x842cc5acf1d03445})},
{false, -131, MType({0xa7c9859530a45153, 0x8cb9de8a32ab368a})},
{false, -131, MType({0x976d3b5b45f6ca0b, 0x9defad3e8f73217a})},
{false, -131, MType({0xe8b8b88a14ff0ce, 0xaf4ad26cbc8e5be7})},
{false, -131, MType({0x6a677b4c8bec22e1, 0xb8069857560707a3})},
{false, -131, MType({0xeaf51f66692844ba, 0xc99af2eaca4c4570})},
{false, -131, MType({0xa8112e35a60e6375, 0xdb56446d6ad8deff})},
{false, -131, MType({0x196ab34ce0bccd12, 0xe442c00de2591b47})},
{false, -131, MType({0x4066e87f2c0f7340, 0xf639cc185088fe5d})},
{false, -131, MType({0xc17bd40d8d9291ec, 0xff4489cedeab2ca6})},
{false, -130, MType({0x9c5a0fe396f40f1e, 0x88bc74113f23def1})},
{false, -130, MType({0x88713268840cbcc0, 0x8d515bf11fb94f1c})},
{false, -130, MType({0x65c0da506a088484, 0x968b08643409ceb6})},
{false, -130, MType({0x411a5b944aca8708, 0x9b2fe580ac80b17d})},
{false, -130, MType({0xa9fb6cf0ecb411b7, 0xa489ec199dab06f2})},
{false, -130, MType({0xcad2fb8d48054ae0, 0xa93f2f250dac67d1})},
{false, -130, MType({0x2c3c2e77904afa78, 0xb2ba75f46099cf8b})},
{false, -130, MType({0x34c7bc3d32750fde, 0xb780945bab55dce4})},
{false, -130, MType({0x9a631e830fd30904, 0xc11e0b2a8d1e0ddb})},
{false, -130, MType({0xaa8b6997a402bf30, 0xc5f57f59c7f46155})},
{false, -130, MType({0x2c507fb7a3d0bf6a, 0xcad2d6e7b80bf914})},
{false, -130, MType({0x5f53bd2e406e66e7, 0xd49f69e456cf1b79})},
{false, -130, MType({0x58a98f2ad65bee9b, 0xd98ec2bade71e539})},
{false, -130, MType({0x4d57da945b5d0aaa, 0xde8439c1dec56877})},
{false, -130, MType({0xc524848e3443e040, 0xe881bf932af3dac0})},
{false, -130, MType({0x11d49f96cb88317b, 0xed89ed86a44a01aa})},
{false, -130, MType({0x3b020fa1820c9492, 0xf29877ff38809091})},
{false, -130, MType({0x54d2238f75f969b1, 0xf7ad6f26e7ff2ef7})},
{false, -130, MType({0xca0cdf301431b60f, 0xfcc8e3659d9bcbec})},
{false, -129, MType({0x62dda9d2270fa1f4, 0x8389c3026ac3139b})},
{false, -129, MType({0x163ceae88f720f1e, 0x86216b3b0b17188b})},
{false, -129, MType({0x9c5a0fe396f40f1e, 0x88bc74113f23def1})},
{false, -129, MType({0xf7a5168126a58b9a, 0x8b5ae65d67db9acd})},
{false, -129, MType({0x5147bdb6ddcaf59c, 0x8dfccb1ad35ca6ed})},
{false, -129, MType({0xdf5bb3b60554e152, 0x934b1089a6dc93c1})},
{false, -129, MType({0x4a5004f3ef063313, 0x95f783e6e49a9cfa})},
{false, -129, MType({0x2cdec34784707839, 0x98a78f0e9ae71d85})},
{false, -129, MType({0xd878bbe3d392be25, 0x9b5b3bb5f088b766})},
{false, -129, MType({0x5b035eae273a855f, 0x9e1293b9998c1daa})},
{false, -129, MType({0xbb2438273918db7e, 0xa0cda11eaf46390d})},
{false, -129, MType({0xf698298adddd7f32, 0xa38c6e138e20d831})},
{false, -129, MType({0xe4f5275c2d15c21f, 0xa64f04f0b961df76})},
{false, -129, MType({0x8164c759686a2209, 0xa9157039c51ebe70})},
{false, -129, MType({0xf72ea07749ce6bd3, 0xabdfba9e468fd6f6})},
{false, -129, MType({0x7dd6e688ebb13b03, 0xaeadeefacaf97d35})},
{false, -129, MType({0x18ce51fff99479cd, 0xb1801859d56249dc})},
{false, -129, MType({0x2756eba00bc33978, 0xb45641f4e350a0d3})},
{false, -129, MType({0xbe1116c3466beb6d, 0xb730773578cb90b2})},
{false, -129, MType({0x49dc60b2b059a60b, 0xba0ec3b633dd8b09})},
{false, -129, MType({0x2efd17781bb3afec, 0xbcf13343e7d9ec7d})},
{false, -129, MType({0x37eda996244bccb0, 0xbfd7d1dec0a8df6f})},
{false, -129, MType({0x33337789d592e296, 0xc2c2abbb6e5fd56f})},
{false, -129, MType({0x1a18fb8f9f9ef280, 0xc5b1cd44596fa51e})},
{false, -129, MType({0x688ce7c1a75e341a, 0xc8a5431adfb44ca5})},
{false, -129, MType({0x2d7e9307c70c0668, 0xcb9d1a189ab56e76})},
{false, -129, MType({0xef2f3f4f861ad6a9, 0xce995f50af69d861})},
{false, -129, MType({0x7f9d79f51dcc7301, 0xd19a201127d3c645})},
{false, -129, MType({0x7f9d79f51dcc7301, 0xd19a201127d3c645})},
{false, -129, MType({0x5f53bd2e406e66e7, 0xd49f69e456cf1b79})},
{false, -129, MType({0xad88bba7d0cee8e0, 0xd7a94a92466e833a})},
{false, -129, MType({0x96c20cca6efe2ac5, 0xdab7d02231484a92})},
{false, -129, MType({0xf40a666c87842843, 0xddcb08dc0717d85b})},
{false, -129, MType({0x7fe8e1802aba24d6, 0xe0e30349fd1cec80})},
{false, -129, MType({0x7fe8e1802aba24d6, 0xe0e30349fd1cec80})},
{false, -129, MType({0x3eadb651b49ac53a, 0xe3ffce3a2aa64922})},
{false, -129, MType({0x304e1653e71d9973, 0xe72178c0323a1a0f})},
{false, -129, MType({0xe9a767a80d6d97e8, 0xea481236f7d35baf})},
{false, -129, MType({0x4f91cf4b33e42998, 0xed73aa4264b0ade9})},
{false, -129, MType({0xfc66eb6408ff6433, 0xf0a450d139366ca6})},
{false, -129, MType({0xfc66eb6408ff6433, 0xf0a450d139366ca6})},
{false, -129, MType({0xac8d42f78d3e65d3, 0xf3da161eed6b9aaf})},
{false, -129, MType({0x5a470250d40ebe90, 0xf7150ab5a09f27f4})},
{false, -129, MType({0xb780a545a1b54dcf, 0xfa553f7018c966f2})},
{false, -129, MType({0xb780a545a1b54dcf, 0xfa553f7018c966f2})},
{false, -129, MType({0x8f05924d258c14c5, 0xfd9ac57bd244217e})},
{false, -128, MType({0x89d1b09c70c4010a, 0x8072d72d903d588b})},
{false, -128, MType({0x30d58c3f7e2ea1f, 0x821b05f3b01d6774})},
{false, -128, MType({0x30d58c3f7e2ea1f, 0x821b05f3b01d6774})},
{false, -128, MType({0x20f6fafe8fbb68b9, 0x83c5f8299e2b4091})},
{false, -128, MType({0xe21f9f89c1ab80b2, 0x8573b71682a7d21a})},
{false, -128, MType({0xe21f9f89c1ab80b2, 0x8573b71682a7d21a})},
{false, -128, MType({0x1e005d06dbfa8f8, 0x87244c308e670a66})},
{false, -128, MType({0x223111a707b6de2c, 0x88d7c11e3ad53cdc})},
{false, -128, MType({0x223111a707b6de2c, 0x88d7c11e3ad53cdc})},
{false, -128, MType({0x2eb628dba173c82d, 0x8a8e1fb794b09134})},
{false, -128, MType({0xbe2ad19415fe25a5, 0x8c47720791e53313})},
{false, -128, MType({0xbe2ad19415fe25a5, 0x8c47720791e53313})},
{false, -128, MType({0xbddae1ccce247838, 0x8e03c24d73003959})},
{false, -128, MType({0x9b00bf167e95da67, 0x8fc31afe30b2c6de})},
{false, -128, MType({0x9b00bf167e95da67, 0x8fc31afe30b2c6de})},
{false, -128, MType({0x9b92199ed1a4bab1, 0x918586c5f5e4bf01})},
{false, -128, MType({0xdf5bb3b60554e152, 0x934b1089a6dc93c1})},
{false, -128, MType({0xdf5bb3b60554e152, 0x934b1089a6dc93c1})},
{false, -128, MType({0xf3cbc416a2418012, 0x9513c36876083695})},
{false, -128, MType({0xbe1188fbc94e2f15, 0x96dfaabd86fa1646})},
{false, -128, MType({0xbe1188fbc94e2f15, 0x96dfaabd86fa1646})},
{false, -128, MType({0x1d2f89321647b358, 0x98aed221a03458b6})},
{false, -128, MType({0x1d2f89321647b358, 0x98aed221a03458b6})},
{false, -128, MType({0xe549f9aaea3cb5e1, 0x9a81456cec642e0f})},
{false, -128, MType({0xa2554b2dd4619e63, 0x9c5710b8cbb73a42})},
{false, -128, MType({0xa2554b2dd4619e63, 0x9c5710b8cbb73a42})},
{false, -128, MType({0x30603d87b6df81ad, 0x9e304061b5fda919})},
{false, -128, MType({0x30603d87b6df81ad, 0x9e304061b5fda919})},
{false, -128, MType({0x67879c5a30cd1242, 0xa00ce1092e5498c3})},
{false, -128, MType({0xb7efae08e597e16, 0xa1ecff97c91e267b})},
{false, -128, MType({0xb7efae08e597e16, 0xa1ecff97c91e267b})},
{false, -128, MType({0x83594fab088c0d65, 0xa3d0a93f45169a4a})},
{false, -128, MType({0x83594fab088c0d65, 0xa3d0a93f45169a4a})},
{false, -128, MType({0xaf6a62a0dec6e073, 0xa5b7eb7cb860fb88})},
{false, -128, MType({0xaf6a62a0dec6e073, 0xa5b7eb7cb860fb88})},
{false, -128, MType({0x49362382a768847a, 0xa7a2d41ad270c9d7})},
{false, -128, MType({0x49362382a768847a, 0xa7a2d41ad270c9d7})},
{false, -128, MType({0x8ba4aea614d05701, 0xa991713433c2b998})},
{false, -128, MType({0x8ba4aea614d05701, 0xa991713433c2b998})},
{false, -128, MType({0x7fe6607ba902ef3c, 0xab83d135dc633301})},
{false, -128, MType({0x7fe6607ba902ef3c, 0xab83d135dc633301})},
{false, -128, MType({0xd60864fd949b4bd3, 0xad7a02e1b24efd31})},
{false, -128, MType({0xd60864fd949b4bd3, 0xad7a02e1b24efd31})},
{false, -128, MType({0x66d235ee63073dd, 0xaf74155120c9011c})},
{false, 0, MType(0)},
},
// -log(r) for the second step, generated by SageMath with:
//
// for i in range(-2^6, 2^7 + 1):
// r = 2^-16 * round( 2^16 / (1 + i*2^(-14)) );
// s, m, e = RealField(128)(r).log().sign_mantissa_exponent();
// print("{false," if s == -1 else "{true,", e, ",
// MType({", hex(m % 2^64), ",", hex((m >> 64) % 2^64), "})},");
/* .step_2 = */
{
{true, -135, MType({0xa1c6f3fc242ef8d0, 0x803faacac419abf2})},
{true, -136, MType({0xa225ebc02e6d9dd4, 0xfc834da16f0d9f57})},
{true, -136, MType({0xc33f6ad340ae18a9, 0xf88735ccc7433381})},
{true, -136, MType({0x70b2a4d38a242244, 0xf48b0e171249b6bc})},
{true, -136, MType({0x1d54819048b811b0, 0xf08ed67fd190e280})},
{true, -136, MType({0xaee5983701d2a02b, 0xec928f0686828706})},
{true, -136, MType({0x40abb8ab72afa2d2, 0xe89637aab2828aed})},
{true, -136, MType({0xdeb547a0d4a26ef9, 0xe499d06bd6eeead5})},
{true, -136, MType({0x39c5bdfbcf6087a0, 0xe09d5949751fb909})},
{true, -136, MType({0x53ea9bf152de635f, 0xdca0d2430e671d18})},
{true, -136, MType({0x25b820436f5f4352, 0xd8a43b582411537e})},
{true, -136, MType({0x3c2d13ea1d0be058, 0xd4a794883764ad41})},
{true, -136, MType({0x4f3cfa62bcb3ce3a, 0xd0aaddd2c9a18f95})},
{true, -136, MType({0xd0fff6cdf14a86c7, 0xccae17375c02737c})},
{true, -136, MType({0x7587b5f0453ac3d2, 0xc8b140b56fbbe56a})},
{true, -136, MType({0xb358ad16dfd0d085, 0xc4b45a4c85fc84e2})},
{true, -136, MType({0x3c86fdce5dbe7314, 0xc0b763fc1fed041d})},
{true, -136, MType({0x70764e46ac18a96d, 0xbcba5dc3beb027a6})},
{true, -136, MType({0xc63be62b8f285882, 0xb8bd47a2e362c600})},
{true, -136, MType({0x72e7b5a386e5e31b, 0xb3c0d59a244325a4})},
{true, -136, MType({0xc3ea2cd93f316b34, 0xafc39bac66434f27})},
{true, -136, MType({0x1dfb11a7cc892843, 0xabc651d491a7b438})},
{true, -136, MType({0xfc679a28e9d9f212, 0xa7c8f8122773f38d})},
{true, -136, MType({0xe7bc977eeec42254, 0xa3cb8e64a8a5bbe6})},
{true, -136, MType({0xb20f215bd3b58c61, 0x9fce14cb9634cba6})},
{true, -136, MType({0xabe2862508d67a98, 0x9bd08b467112f078})},
{true, -136, MType({0xd1aacedcefe9d377, 0x97d2f1d4ba2c06f0})},
{true, -136, MType({0xf1eb25e77d05f58d, 0x93d54875f265fa2c})},
{true, -136, MType({0xcbef6fac33691e95, 0x8fd78f299aa0c375})},
{true, -136, MType({0x2720640462a0f8ad, 0x8bd9c5ef33b669e0})},
{true, -136, MType({0xe2f1775134c8da75, 0x87dbecc63e7b01ed})},
{true, -136, MType({0xff67e201c8c50d67, 0x83de03ae3bbcad2e})},
{true, -137, MType({0x3c742a7c76356396, 0xffc0154d588733c5})},
{true, -137, MType({0xf90dd6b24aa686ec, 0xf7c4035e21a4052f})},
{true, -137, MType({0xca47c52b7d7ffce2, 0xefc7d18dd4485b9e})},
{true, -137, MType({0x3703617ad3d8311f, 0xe7cb7fdb71e0db36})},
{true, -137, MType({0x7e4cfbd830393b88, 0xdfcf0e45fbce3e80})},
{true, -137, MType({0x4f7a29cf0fc2c38e, 0xd7d27ccc736555af})},
{true, -137, MType({0x7370ae83f9e72748, 0xcfd5cb6dd9ef05dd})},
{true, -137, MType({0x671486eb4cd76f65, 0xc7d8fa2930a84850})},
{true, -137, MType({0xe6dbb624f9739782, 0xbfdc08fd78c229b9})},
{true, -137, MType({0x6b866e09e57d9079, 0xb7def7e9b361c979})},
{true, -137, MType({0x97fa2fd0c9dc723e, 0xafe1c6ece1a058dd})},
{true, -137, MType({0x983e80897cf1e60f, 0xa7e47606048b1a65})},
{true, -137, MType({0x7199cd06ae5d39b3, 0x9fe705341d236102})},
{true, -137, MType({0x43cd18a72a051a96, 0x97e974762c5e8f58})},
{true, -137, MType({0x7b6d1248c3e1fd40, 0x8febc3cb332616ff})},
{true, -137, MType({0xf5572a8814c703af, 0x87edf332325777c5})},
{true, -138, MType({0x26828c92649a3a39, 0xffe0055455887de0})},
{true, -138, MType({0x82c550bd1216d82a, 0xefe3e4643a640cf3})},
{true, -138, MType({0xda6959f7f0e01bf0, 0xdfe7839214b4e8ae})},
{true, -138, MType({0xda93e2fa85a8f214, 0xcfeae2dbe5d6736d})},
{true, -138, MType({0xb47505bfa5a03b06, 0xbfee023faf0c2480})},
{true, -138, MType({0xb1475a5180a43520, 0xaff0e1bb718186ad})},
{true, -138, MType({0xa8740b91c95df537, 0x9ff3814d2e4a36b2})},
{true, -138, MType({0x57d895d35921b59c, 0x8ff5e0f2e661e1c6})},
{true, -139, MType({0x3c56c598c659c2a3, 0xfff0015535588833})},
{true, -139, MType({0x2ef8ec33ed9d782a, 0xdff3c0e497ea4eb1})},
{true, -139, MType({0x379eba7e6465ff63, 0xbff7008ff5e0c257})},
{true, -139, MType({0x3f972b783fcab757, 0x9ff9c0535073a370})},
{true, -140, MType({0xde026e271ee0549d, 0xfff8005551558885})},
{true, -140, MType({0xeceb47ea01f6c632, 0xbffb8023febc0c25})},
{true, -141, MType({0x7333c57857e1ed52, 0xfffc001554d55888})},
{true, -142, MType({0x87dde026fa704374, 0xfffe000555455588})},
{true, 0, MType({0x0, 0x0})},
{false, -141, MType({0x44999abe2fe2cc65, 0x80010002aab2aac4})},
{false, -140, MType({0x4eef381581464ccb, 0x8002000aaaeaac44})},
{false, -140, MType({0xdfeb485085f6f454, 0xc004802401440c26})},
{false, -139, MType({0x99abe3be3a1c6e93, 0x8004002aacaac445})},
{false, -139, MType({0x6bc1e20eac8448b4, 0xa00640535a37a37a})},
{false, -139, MType({0x979eedc064c242fd, 0xc00900900a20c275})},
{false, -139, MType({0xc72446cc1bf728bd, 0xe00c40e4bd6e4efd})},
{false, -138, MType({0xf381b821bbb569e5, 0x800800aabaac446e})},
{false, -138, MType({0x569b26aaa485ea5c, 0x900a20f319a3e273})},
{false, -138, MType({0x2dcf56c83c80b028, 0xa00c814d7c6a37f8})},
{false, -138, MType({0x5f69768284463b9b, 0xb00f21bbe3e388ee})},
{false, -138, MType({0xb48ea6c05e2773a1, 0xc0120240510c284c})},
{false, -138, MType({0x14d9d76196d8043a, 0xd01522dcc4f87991})},
{false, -138, MType({0xe016a611a4415d72, 0xe018839340d4f241})},
{false, -138, MType({0x661e135f49a47c40, 0xf01c2465c5e61b6f})},
{false, -137, MType({0xbe6bf0fa435e8383, 0x801002ab2ac4499a})},
{false, -137, MType({0x9a31ba0cbc030353, 0x881213337898871e})},
{false, -137, MType({0x54b57dfe0c4c840f, 0x901443cccd362c9f})},
{false, -137, MType({0x7ad1e9c315328f7e, 0x98169478296fad41})},
{false, -137, MType({0x1f3f686cf3d6be22, 0xa01905368e2389b3})},
{false, -137, MType({0xf105b66ec4703ede, 0xa81b9608fc3c50ec})},
{false, -137, MType({0x610848c68df4d233, 0xb01e46f074b0a0f3})},
{false, -137, MType({0xd6aef30cd312169a, 0xb82117edf8832797})},
{false, -137, MType({0xf3ac379608053d9d, 0xc024090288c2a339})},
{false, -137, MType({0xe6e2acf8f4d4c24a, 0xc8271a2f2689e388})},
{false, -137, MType({0xce6ae474d860359f, 0xd02a4b74d2ffca44})},
{false, -137, MType({0x28bb3cd9f2a65fb5, 0xd82d9cd48f574c00})},
{false, -137, MType({0x54f30dbef38a8066, 0xe0310e4f5ccf70e1})},
{false, -137, MType({0x224a96f5a7471c46, 0xe8349fe63cb35564})},
{false, -137, MType({0x6ea920591aa02e1b, 0xf038519a305a2b1b})},
{false, -137, MType({0xd462b63756c87e80, 0xf83c236c39273972})},
{false, -136, MType({0x338f77605fe77f2a, 0x80200aaeac44ef38})},
{false, -136, MType({0x3ff51287882500ed, 0x842213b747fec7bb})},
{false, -136, MType({0xcc394b3ef0ebeb12, 0x88242cd07084ed02})},
{false, -136, MType({0x1ab9679b55f78a6b, 0x8c2655faa6a1323f})},
{false, -136, MType({0x7025697d10af0436, 0x90288f366b237771})},
{false, -136, MType({0x17e4b7ac6c600cb4, 0x942ad8843ee1a9cd})},
{false, -136, MType({0x7013925a9a8da7f3, 0x982d31e4a2b7c418})},
{false, -136, MType({0xfd1a09c848e3950e, 0x9c2f9b581787cf0d})},
{false, -136, MType({0x84dd2de6e3d90a37, 0xa03214df1e39e1bd})},
{false, -136, MType({0x318b2ddd9d0a33b4, 0xa4349e7a37bc21ed})},
{false, -136, MType({0xbc031e6f5acfd4a8, 0xa8373829e502c47a})},
{false, -136, MType({0x9dd91e52c79fd070, 0xac39e1eea7080dbc})},
{false, -136, MType({0x4af78fa1cb48a12d, 0xb03c9bc8fecc51e3})},
{false, -136, MType({0x72de1d99ce252efd, 0xb43f65b96d55f55a})},
{false, -136, MType({0xefb1dbe721934877, 0xb74187bc8ccffa84})},
{false, -136, MType({0xb4b080f230c87598, 0xbb446dd4d9bca499})},
{false, -136, MType({0xda6a7cd19c7fa4f2, 0xbf476404a05f88f2})},
{false, -136, MType({0xdf00e3783b50ecfb, 0xc34a6a4c61d5cc3c})},
{false, -136, MType({0xda2e5e02ab4e183c, 0xc74d80ac9f42a52d})},
{false, -136, MType({0xea5f6ee99d30c626, 0xcb50a725d9cf5ce6})},
{false, -136, MType({0xa96d5956531d7d8b, 0xcf53ddb892ab4f55})},
{false, -136, MType({0xa8fc636eb36afa75, 0xd35724654b0beb95})},
{false, -136, MType({0xf67e2b827bfc4421, 0xd75a7b2c842cb451})},
{false, -136, MType({0xa6d8c817516303e6, 0xdb5de20ebf4f4026})},
{false, -136, MType({0x69b36ae5962e85f4, 0xdf61590c7dbb3a02})},
{false, -136, MType({0x24693eec2a831cc3, 0xe364e02640be6188})},
{false, -136, MType({0x94a339d56a55ab4a, 0xe768775c89ac8b70})},
{false, -136, MType({0xfa9998fbf9703bf4, 0xeb6c1eafd9dfa1eb})},
{false, -136, MType({0xcafdc27227b71eaa, 0xef6fd620b2b7a503})},
{false, -136, MType({0x688d4282f6026aa3, 0xf3739daf959aaafc})},
{false, -136, MType({0xe54e9e3804464cdd, 0xf777755d03f4e0b6})},
{false, -136, MType({0xcb78b383f4b59dce, 0xfb7b5d297f388a12})},
{false, -136, MType({0xee055fc515062c04, 0xff7f551588de024f})},
{false, -135, MType({0x207812b43382acdd, 0x81c1ae90d131de38})},
{false, -135, MType({0xdc90c4c4b61f3a87, 0x83c3baa726a721cc})},
{false, -135, MType({0x1a03f13fb2c978b1, 0x85c5cece05941dbc})},
{false, -135, MType({0xb36f282e83a7dc36, 0x87c7eb05aec1304f})},
{false, -135, MType({0x6ad14c3dfa414391, 0x89ca0f4e62f9c476})},
{false, -135, MType({0xe8dd4ea0d48b88e5, 0x8bcc3ba8630c51f4})},
{false, -135, MType({0xc02515afe8caeb90, 0x8dce7013efca5d96})},
{false, -135, MType({0x741ceaf3349f3cf1, 0x8fd0ac914a08795f})},
{false, -135, MType({0x83f7cd4929d2c28c, 0x91d2f120b29e44bb})},
{false, -135, MType({0x795d03ebc2fd03fa, 0x93d53dc26a666cb1})},
{false, -135, MType({0xfaf74f1d1ad16acc, 0x95d79276b23eac12})},
{false, -135, MType({0xe2de134f72fee429, 0x97d9ef3dcb07cbad})},
{false, -135, MType({0x58d8dba6cadac5d5, 0x99dc5417f5a5a27d})},
{false, -135, MType({0xf07d90bc5aae40a4, 0x9bdec10572ff15da})},
{false, -135, MType({0x1deaf79d9fc40374, 0x9d6098046659ea6b})},
{false, -135, MType({0x7ba63e6769b81999, 0x9f63131450b07988})},
{false, -135, MType({0x59ebfc9335094e59, 0xa1659638404d5f92})},
{false, -135, MType({0x16aae012b5026f71, 0xa36821707622f97a})},
{false, -135, MType({0xff5d4f2c0e4b9cae, 0xa56ab4bd3326b378})},
{false, -135, MType({0x855838b5119dcb28, 0xa76d501eb8510941})},
{false, -135, MType({0x75f70cbbe9cf1603, 0xa96ff395469d8630})},
{false, -135, MType({0x36a53ad4d5541cc9, 0xab729f211f0ac57e})},
{false, -135, MType({0x4c5934ec32d20d9, 0xad7552c2829a7270})},
{false, -135, MType({0x3977e89aec59bfa2, 0xaf780e79b2514889})},
{false, -135, MType({0x913d4e3dc55c3e6e, 0xb17ad246ef3713bc})},
{false, -135, MType({0x777b52a9e70d8bcc, 0xb37d9e2a7a56b09d})},
{false, -135, MType({0x55de916fd30591de, 0xb580722494be0c91})},
{false, -135, MType({0xe79cfb37be2861e4, 0xb7834e357f7e2600})},
{false, -135, MType({0x90983104d3805389, 0xb986325d7bab0c89})},
{false, -135, MType({0xb860504baa6f984d, 0xbb891e9cca5be12e})},
{false, -135, MType({0x29178d6ff5712b96, 0xbd8c12f3acaad68b})},
{false, -135, MType({0x7236fa47ba19a198, 0xbf8f0f6263b53102})},
{false, -135, MType({0x4f34d64cafcc50e3, 0xc19213e9309b46f2})},
{false, -135, MType({0x120cc62eb0a8db3e, 0xc3952088548080e4})},
{false, -135, MType({0x11aa5084779060e3, 0xc5983540108b59be})},
{false, -135, MType({0x1c35fd6236c8dcf1, 0xc79b5210a5e55ef5})},
{false, -135, MType({0xed4576a7e4b878fe, 0xc99e76fa55bb30bd})},
{false, -135, MType({0x6caf4bb8fd2c1131, 0xcb20d7fa3a336081})},
{false, -135, MType({0x3f24a6cbb09c654f, 0xcd240b10753e78de})},
{false, -135, MType({0x78bc003bb81e40f3, 0xcf2746407e0ff09f})},
{false, -135, MType({0x56647301edfd8e8b, 0xd12a898a95dff002})},
{false, -135, MType({0x28fe1c4d04ca4ed9, 0xd32dd4eefde9b2ef})},
{false, -135, MType({0xe1ea9ea6cbf57379, 0xd531286df76b892a})},
{false, -135, MType({0xa3832028141a5cc2, 0xd7348407c3a6d688})},
{false, -135, MType({0x557421dd379d3ead, 0xd937e7bca3e0131b})},
{false, -135, MType({0x3cff8e87a99bcaf0, 0xdb3b538cd95ecb67})},
{false, -135, MType({0x99255ef34bd0801f, 0xdd3ec778a56da093})},
{false, -135, MType({0x42b33220abfa15cd, 0xdf424380495a489c})},
{false, -135, MType({0x503b378faa97dbc0, 0xe145c7a406758e83})},
{false, -135, MType({0xbdf2ca006f59b544, 0xe34953e41e135282})},
{false, -135, MType({0x1979190af37ed16f, 0xe54ce840d18a8a3e})},
{false, -135, MType({0x31863ff7cf898c9c, 0xe75084ba623540f4})},
{false, -135, MType({0xc983284f60293647, 0xe9542951117097b0})},
{false, -135, MType({0x510a969ebe03f804, 0xeb57d605209cc57e})},
{false, -135, MType({0x9f53bffc6d23fe30, 0xed5b8ad6d11d1797})},
{false, -135, MType({0xb286c6e113337886, 0xef5f47c66457f199})},
{false, -135, MType({0xb6ed80852ae6fd63, 0xf0e21acdd6e7d412})},
{false, -135, MType({0xdf437fb0f616082d, 0xf2e5e5f25450c5a2})},
{false, -135, MType({0xf237cff1acb306b3, 0xf4e9b935685dbe0b})},
{false, -135, MType({0x52dbfafb4121a092, 0xf6ed94975480b696})},
{false, -135, MType({0xd81648249cece4c, 0xf8f178185a2ebfd9})},
{false, -135, MType({0xad95e6b0b96903d3, 0xfaf563b8bae001eb})},
{false, -135, MType({0x176cd56887ac7fe9, 0xfcf95778b80fbc98})},
{false, -135, MType({0x65f4c7397f1f478d, 0xfefd5358933c478c})},
},
// -log(r) for the third step, generated by SageMath with:
//
// for i in range(-80, 81):
// r = 2^-21 * round( 2^21 / (1 + i*2^(-21)) );
// s, m, e = RealField(128)(r).log().sign_mantissa_exponent();
// print("{false," if (s == -1) else "{true,", e, ",
// MType({", hex(m % 2^64), ",", hex((m >> 64) % 2^64), "})},");
/* .step_3 = */
{
{true, -142, MType({0x374b294076d669c3, 0x9fff38014d52e45a})},
{true, -142, MType({0x7f6f05dcdbeb776e, 0x9dff3cf940fad85a})},
{true, -142, MType({0x3d55e21d41bbadf9, 0x9bff41e134f1cb36})},
{true, -142, MType({0xccdba2d54aadbc5c, 0x99ff46b92936bcf4})},
{true, -142, MType({0x71dd16d3073f79b2, 0x97ff4b811dc8ad9d})},
{true, -142, MType({0x5837f3df1a58dd48, 0x95ff503912a69d37})},
{true, -142, MType({0x93cad3bcdd26fd6d, 0x93ff54e107cf8bc9})},
{true, -142, MType({0x2075312a827f14fa, 0x91ff5978fd42795b})},
{true, -142, MType({0xe21764e139c98f60, 0x8fff5e00f2fe65f2})},
{true, -142, MType({0xa492a29551751b4c, 0x8dff6278e9025197})},
{true, -142, MType({0x1bc8f5f658f1c3a2, 0x8bff66e0df4d3c50})},
{true, -142, MType({0xe39d3faf42340ed7, 0x89ff6b38d5de2622})},
{true, -142, MType({0x7ff3326682c02485, 0x87ff6f80ccb40f16})},
{true, -142, MType({0x5caf4fbe343cf928, 0x85ff73b8c3cdf731})},
{true, -142, MType({0xcdb6e554348f7fe8, 0x83ff77e0bb2ade79})},
{true, -142, MType({0xef009c2457de25d, 0x81ff7bf8b2c9c4f6})},
{true, -143, MType({0x8883333c57b57c74, 0xffff000155535558})},
{true, -143, MType({0xf32668f39c70d183, 0xfbff07f145931f44})},
{true, -143, MType({0x459a73c6a6486fe3, 0xf7ff0fc13650e7bd})},
{true, -143, MType({0x37b18cca7dd3a29f, 0xf3ff1771278aaecd})},
{true, -143, MType({0x513f610d21bcfc78, 0xefff1f01193e7480})},
{true, -143, MType({0xea190b95c0690b7b, 0xebff26710b6a38e1})},
{true, -143, MType({0x2a150f64f0ad1743, 0xe7ff2dc0fe0bfbfd})},
{true, -143, MType({0x90b5174e995e9d1, 0xe3ff34f0f121bddd})},
{true, -143, MType({0x4ed512b9b93ea2bf, 0xdfff3c00e4a97e8c})},
{true, -143, MType({0x934cea217ab794a2, 0xdbff42f0d8a13e15})},
{true, -143, MType({0x3e4ebe948afd2c76, 0xd7ff49c0cd06fc83})},
{true, -143, MType({0x87b7c0f5bcfee2e1, 0xd3ff5070c1d8b9df})},
{true, -143, MType({0x776666228cb6371b, 0xcfff5700b7147634})},
{true, -143, MType({0xe53a60f3514db358, 0xcbff5d70acb8318b})},
{true, -143, MType({0x79149c3b6e57fa86, 0xc7ff63c0a2c1ebef})},
{true, -143, MType({0xaad734c98416df2a, 0xc3ff69f0992fa568})},
{true, -143, MType({0xc26573679ed28334, 0xbfff70008fff5e00})},
{true, -143, MType({0xd7a3c6db6540809f, 0xbbff75f0872f15c0})},
{true, -143, MType({0xd277bde645fb1aad, 0xb7ff7bc07ebcccb1})},
{true, -143, MType({0x6ac80145a4087793, 0xb3ff817076a682dc})},
{true, -143, MType({0x287c4db30271e265, 0xafff87006eea3849})},
{true, -143, MType({0x637d6de42eeb151e, 0xabff8c706785ed00})},
{true, -143, MType({0x43b5348b6b898a8c, 0xa7ff91c06077a10a})},
{true, -143, MType({0xc10e7657978bd7f6, 0xa3ff96f059bd546e})},
{true, -143, MType({0xa37503f457310e59, 0x9fff9c0053550735})},
{true, -143, MType({0x82d5a40a3aa022ff, 0x9bffa0f04d3cb966})},
{true, -143, MType({0xc71e0d3ee3df5f4d, 0x97ffa5c047726b08})},
{true, -143, MType({0xa83ce0352bdbd79b, 0x93ffaa7041f41c23})},
{true, -143, MType({0x2e21a18d4680e8e4, 0x8fffaf003cbfccbe})},
{true, -143, MType({0x30bcb3e4e5dfbd28, 0x8bffb37037d37cdf})},
{true, -143, MType({0x57ff51d75c66d64a, 0x87ffb7c0332d2c8d})},
{true, -143, MType({0x1bdb87fdbe299f43, 0x83ffbbf02ecadbcf})},
{true, -144, MType({0x88885dde02700703, 0xffff800055551555})},
{true, -144, MType({0xd259ca803a0c1870, 0xf7ff87e04d94724c})},
{true, -144, MType({0xe514130851c7070a, 0xefff8f80464fce8f})},
{true, -144, MType({0x30a16898f3073a64, 0xe7ff96e03f832a2a})},
{true, -144, MType({0xc4ed64517b2949ce, 0xdfff9e00392a8526})},
{true, -144, MType({0x51e4fb4e32cf6350, 0xd7ffa4e03341df90})},
{true, -144, MType({0x277672a88350bcce, 0xcfffab802dc53971})},
{true, -144, MType({0x359153772a490f06, 0xc7ffb1e028b092d3})},
{true, -144, MType({0xc265ece6b481a0e, 0xbfffb80023ffebc0})},
{true, -144, MType({0xdb2781c03fa132f6, 0xb7ffbde01faf4440})},
{true, -144, MType({0x7287c95c845ada33, 0xafffc3801bba9c5e})},
{true, -144, MType({0x423b56b1263e5a77, 0xa7ffc8e0181df421})},
{true, -144, MType({0x5a3752ca4c076fa3, 0x9fffce0014d54b91})},
{true, -144, MType({0x6a71e2b27eb3f573, 0x97ffd2e011dca2b6})},
{true, -144, MType({0xc2e21b72cff39d8f, 0x8fffd7800f2ff997})},
{true, -144, MType({0x537ff612feb7ac9e, 0x87ffdbe00ccb503c})},
{true, -145, MType({0x5888873333c57c18, 0xffffc00015554d55})},
{true, -145, MType({0xfa51421842311c42, 0xefffc7c01193f9d1})},
{true, -145, MType({0x2c4ed6de475b942c, 0xdfffcf000e4aa5fa})},
{true, -145, MType({0xce77678cbb6fcb88, 0xcfffd5c00b7151d8})},
{true, -145, MType({0xc26629a679ed3b, 0xbfffdc0008fffd78})},
{true, -145, MType({0x23287cb9d3072728, 0xafffe1c006eea8e1})},
{true, -145, MType({0xd5a37540fd057315, 0x9fffe7000535541c})},
{true, -145, MType({0xf82e21c1fce36810, 0x8fffebc003cbff32})},
{true, -146, MType({0x5588887ddde02702, 0xffffe00005555455})},
{true, -146, MType({0x9ac4ed72adf5b295, 0xdfffe7800392aa14})},
{true, -146, MType({0xc26648066b482, 0xbfffee00023fffaf})},
{true, -146, MType({0x455a3754b292c077, 0x9ffff380014d552e})},
{true, -147, MType({0x5558888833333c58, 0xfffff00001555535})},
{true, -147, MType({0xe000c2665736679f, 0xbffff700008ffff5})},
{true, -148, MType({0x5555888885ddde02, 0xfffff80000555551})},
{true, -149, MType({0xd555588888733334, 0xfffffc0000155554})},
{false, 0, MType({0x0, 0x0})},
{false, -148, MType({0xeaaaac44444eeeef, 0x80000200000aaaaa})},
{false, -147, MType({0xaaaac444459999ac, 0x80000400002aaaac})},
{false, -147, MType({0x2000c2667596679f, 0xc00009000090000a})},
{false, -146, MType({0xaaac44446eeef381, 0x8000080000aaaaba})},
{false, -146, MType({0x655a3755f81815cc, 0xa0000c80014d557c})},
{false, -146, MType({0xc26684c66b482, 0xc000120002400051})},
{false, -146, MType({0xbac4ed7c40fb07eb, 0xe00018800392ab40})},
{false, -145, MType({0xaac44449999abe2c, 0x8000100002aaab2a})},
{false, -145, MType({0x82e21d79cbb6812, 0x9000144003cc00cd})},
{false, -145, MType({0xd5a37569adb01dc3, 0xa00019000535568d})},
{false, -145, MType({0x33287d01e8c9d1d9, 0xb0001e4006eeac74})},
{false, -145, MType({0xc266a32679ed48, 0xc000240009000288})},
{false, -145, MType({0xde77685122b2764b, 0xd0002a400b7158d1})},
{false, -145, MType({0x2c4ed810a8063f03, 0xe00031000e4aaf5b})},
{false, -145, MType({0xa5143e7be891c8f, 0xf00038401194062e})},
{false, -144, MType({0xac4444eeef3813a1, 0x800020000aaaaeaa})},
{false, -144, MType({0x5b7ff7fe1339025b, 0x880024200ccb5a6e})},
{false, -144, MType({0x42e21e26caf39e33, 0x900028800f300668})},
{false, -144, MType({0xf271e66fa5554bc6, 0x98002d2011dcb29e})},
{false, -144, MType({0x5a3757e0615cc676, 0xa000320014d55f19})},
{false, -144, MType({0xca3b5d8210ca5cab, 0xa8003720181e0bde})},
{false, -144, MType({0xf287d25f3cb032bb, 0xb0003c801bbab8f6})},
{false, -144, MType({0xe3278d840be28cdb, 0xb80042201faf6669})},
{false, -144, MType({0xc266dfe6b482076, 0xc000480024001440})},
{false, -144, MType({0x3d9166de380a6d3d, 0xc8004e2028b0c282})},
{false, -144, MType({0xa7768b356ba61e4b, 0xd00054802dc57139})},
{false, -144, MType({0xd9e51a1849db73c1, 0xd8005b203342206f})},
{false, -144, MType({0xc4ed8a9d907eb521, 0xe0006200392ad02e})},
{false, -144, MType({0xb8a197dea928acd7, 0xe80069203f838080})},
{false, -144, MType({0x65144cf7dcc72d3b, 0xf000708046503170})},
{false, -144, MType({0xda5a1108890d9f6a, 0xf80078204d94e308})},
{false, -143, MType({0xc4445999abe2ce2c, 0x800040002aaacaaa})},
{false, -143, MType({0x1fdbbb4f3bffc832, 0x840044102ecb2431})},
{false, -143, MType({0x97ff8f39ec91b4ee, 0x88004840332d7e1d})},
{false, -143, MType({0x74bcfcf0b3f0a95d, 0x8c004c9037d3d876})},
{false, -143, MType({0x2e21f80ca6813aff, 0x900051003cc03342})},
{false, -143, MType({0x6c3d4629170ce87f, 0x9400559041f48e87})},
{false, -143, MType({0x71e84e3b80a8881, 0x98005a404772ea4d})},
{false, -143, MType({0x6d62fdcbdd6bec3, 0x9c005f104d3d469a})},
{false, -143, MType({0xa375a6b701dc77c0, 0xa00064005355a375})},
{false, -143, MType({0x450f331826ad6b05, 0xa400691059be00e7})},
{false, -143, MType({0x83b60ea8bd0aa459, 0xa8006e4060785ef6})},
{false, -143, MType({0x277e691469dd13f5, 0xac0073906786bdab})},
{false, -143, MType({0x287d6e0a0d1e25eb, 0xb00079006eeb1d0d})},
{false, -143, MType({0xaec94b3be9b060f5, 0xb4007e9076a77d24})},
{false, -143, MType({0x1279365fce280cce, 0xb80084407ebdddfa})},
{false, -143, MType({0xdba5732f3e83e04a, 0xbc008a1087303f95})},
{false, -143, MType({0xc26759679ed5b754, 0xc00090009000a200})},
{false, -143, MType({0xaed95aca5edb5109, 0xc400961099310543})},
{false, -143, MType({0xb917091d2687160f, 0xc8009c40a2c36967})},
{false, -143, MType({0x293d1c2a0378e75d, 0xcc00a290acb9ce76})},
{false, -143, MType({0x776977bf9766f5a7, 0xd000a900b7163478})},
{false, -143, MType({0x4bbb31b14776a18b, 0xd400af90c1da9b78})},
{false, -143, MType({0x7e5297d76c8564ba, 0xd800b640cd09037f})},
{false, -143, MType({0x1751360f8461c447, 0xdc00bd10d8a36c98})},
{false, -143, MType({0x4ed9dc3c63f44c41, 0xe000c400e4abd6cc})},
{false, -143, MType({0x8d10a4466a5894d5, 0xe400cb10f1244226})},
{false, -143, MType({0x6a1af81bb4e6510e, 0xe800d240fe0eaeb1})},
{false, -143, MType({0xae1f97b0542a677a, 0xec00d9910b6d1c77})},
{false, -143, MType({0x51469efe81d014cc, 0xf000e10119418b84})},
{false, -143, MType({0x7bb98c06d77a18b4, 0xf400e891278dfbe2})},
{false, -143, MType({0x85a344d0868bed17, 0xf800f04136546d9d})},
{false, -143, MType({0xf7301d6990e307cc, 0xfc00f8114596e0c0})},
{false, -142, MType({0x4446eef38140138f, 0x80008000aaabaaac})},
{false, -142, MType({0x10f5e43296105497, 0x82008408b2cbe5b8})},
{false, -142, MType({0xedbd4f83ef63f730, 0x84008820bb2d2189})},
{false, -142, MType({0xfeb654fd541c638e, 0x86008c48c3d05e27})},
{false, -142, MType({0x7ffadeb8882f7674, 0x88009080ccb69b98})},
{false, -142, MType({0xc5a59fd36bd44397, 0x8a0094c8d5e0d9e1})},
{false, -142, MType({0x3bd217701b27dddb, 0x8c009920df50190a})},
{false, -142, MType({0x669c93b50e4a2595, 0x8e009d88e9055918})},
{false, -142, MType({0xe22234cd39f29cd4, 0x9000a200f3019a12})},
{false, -142, MType({0x6280efe8307d41d9, 0x9200a688fd45dc00})},
{false, -142, MType({0xb3d7923a436f6fc4, 0x9400ab2107d31ee7})},
{false, -142, MType({0xba45c3fca574c5a0, 0x9600afc912aa62cf})},
{false, -142, MType({0x71ec0b6d8cd413d1, 0x9800b4811dcca7bf})},
{false, -142, MType({0xeeebcfd0565c5006, 0x9a00b949293aedbd})},
{false, -142, MType({0x5d675c6da8c98fc3, 0x9c00be2134f634d2})},
{false, -142, MType({0x181e39398a2099a, 0x9e00c30940ff7d04})},
{false, -142, MType({0x375f8195cc8b1d29, 0xa000c8014d57c65a})},
},
// -log(r) for the fourth step, generated by SageMath with:
//
// for i in range(-65, 65):
// r = 2^-28 * round( 2^28 / (1 + i*2^(-28)) );
// s, m, e = RealField(128)(r).log().sign_mantissa_exponent();
// print("{false," if (s == -1) else "{true,", e, ",
// MType({", hex(m % 2^64), ",", hex((m >> 64) % 2^64), "})},");
/* .step_4 = */
{
{true, -149, MType({0x4cd24d68ff2f11ae, 0x81fffef7f002cb2b})},
{true, -150, MType({0x455555888887ddde, 0xfffffe0000055555})},
{true, -150, MType({0xf0fa101f52b3971f, 0xfbfffe0fe0051653})},
{true, -150, MType({0x9c9329d659ed3734, 0xf7fffe1f8004d94a})},
{true, -150, MType({0x4821006d9b58462e, 0xf3fffe2ee0049e31})},
{true, -150, MType({0xf3a3f025142f8c21, 0xeffffe3e000464ff})},
{true, -150, MType({0x9f1c53bcc1c4b11c, 0xebfffe4ce0042dae})},
{true, -150, MType({0x4a8a8474a17fdd30, 0xe7fffe5b8003f835})},
{true, -150, MType({0xf5eeda0cb0df586d, 0xe3fffe69e003c48b})},
{true, -150, MType({0xa149aac4ed772adf, 0xdffffe78000392aa})},
{true, -150, MType({0x4c9b4b5d54f0bc96, 0xdbfffe85e0036289})},
{true, -150, MType({0xf7e40f15e50a759f, 0xd7fffe938003341f})},
{true, -150, MType({0xa32447ae9b975e05, 0xd3fffea0e0030766})},
{true, -150, MType({0x4e5c4567767ebdd5, 0xcffffeae0002dc55})},
{true, -150, MType({0xf98c570073bbbd19, 0xcbfffebae002b2e3})},
{true, -150, MType({0xa4b4c9b9915d03dd, 0xc7fffec780028b0a})},
{true, -150, MType({0x4fd5e952cd845a28, 0xc3fffed3e00264c1})},
{true, -150, MType({0xfaf0000c26664806, 0xbffffee000023fff})},
{true, -150, MType({0xa60356a59a49b57f, 0xbbfffeebe0021cbe})},
{true, -150, MType({0x5110345f27878a9b, 0xb7fffef78001faf5})},
{true, -150, MType({0xfc16def8cc8a4f61, 0xb3ffff02e001da9b})},
{true, -150, MType({0xa7179ab287cdcbd8, 0xafffff0e0001bbaa})},
{true, -150, MType({0x5212aa4c57dea809, 0xabffff18e0019e19})},
{true, -150, MType({0xfd084f063b5a0bf8, 0xa7ffff23800181df})},
{true, -150, MType({0xa7f8c8a030ed3fab, 0xa3ffff2de00166f6})},
{true, -150, MType({0x52e4555a37554b29, 0x9fffff3800014d55})},
{true, -150, MType({0xfdcb31f44d5e9676, 0x9bffff41e00134f3})},
{true, -150, MType({0xa8ad99ae71e48997, 0x97ffff4b80011dca})},
{true, -150, MType({0x538bc648a3d12c90, 0x93ffff54e00107d1})},
{true, -150, MType({0xfe65f002e21cc765, 0x8fffff5e0000f2ff})},
{true, -150, MType({0xa93c4d9d2bcd821a, 0x8bffff66e000df4e})},
{true, -150, MType({0x540f14577ff704b2, 0x87ffff6f8000ccb5})},
{true, -150, MType({0xfede77f1ddba1731, 0x83ffff77e000bb2b})},
{true, -151, MType({0x5355555888888333, 0xffffff0000015555})},
{true, -151, MType({0xa8e7ba8d659ed7dc, 0xf7ffff0fc0013652})},
{true, -151, MType({0xfe747e025142fc61, 0xefffff1f0001193f})},
{true, -151, MType({0x53fbfb374a1800c7, 0xe7ffff2dc000fe0d})},
{true, -151, MType({0xa97e8aac4ed77513, 0xdfffff3c0000e4aa})},
{true, -151, MType({0xfefc81e15e50a947, 0xd7ffff49c000cd07})},
{true, -151, MType({0x547633567767ed66, 0xcfffff570000b715})},
{true, -151, MType({0xa9ebee8b9915d174, 0xc7ffff63c000a2c2})},
{true, -151, MType({0xff5e0000c2666573, 0xbfffff7000008fff})},
{true, -151, MType({0x54ccb135f2787966, 0xb7ffff7bc0007ebd})},
{true, -151, MType({0xaa3848ab287cdd4e, 0xafffff8700006eea})},
{true, -151, MType({0xffa109e063b5a12d, 0xa7ffff91c0006077})},
{true, -151, MType({0x55073555a3755504, 0x9fffff9c00005355})},
{true, -151, MType({0xaa6b088ae71e48d5, 0x97ffffa5c0004772})},
{true, -151, MType({0xffccbe002e21cca2, 0x8fffffaf00003cbf})},
{true, -151, MType({0x552c8d3577ff706a, 0x87ffffb7c000332d})},
{true, -152, MType({0x551555558888885e, 0xffffff8000005555})},
{true, -152, MType({0xffce8fc025142fe3, 0xefffff8f8000464f})},
{true, -152, MType({0xaa8526aac4ed7764, 0xdfffff9e0000392a})},
{true, -152, MType({0x5539711567767ee3, 0xcfffffab80002dc5})},
{true, -152, MType({0xffebc0000c26665f, 0xbfffffb8000023ff})},
{true, -152, MType({0xaa9c5e6ab287cdd9, 0xafffffc380001bba})},
{true, -152, MType({0x554b91555a375553, 0x9fffffce000014d5})},
{true, -152, MType({0xfff997c002e21ccb, 0x8fffffd780000f2f})},
{true, -153, MType({0x554d555558888887, 0xffffffc000001555})},
{true, -153, MType({0xaaa5fa2aac4ed777, 0xdfffffcf00000e4a})},
{true, -153, MType({0xfffd780000c26666, 0xbfffffdc000008ff})},
{true, -153, MType({0x55541cd555a37555, 0x9fffffe700000535})},
{true, -154, MType({0x5554555555888888, 0xffffffe000000555})},
{true, -154, MType({0xffffaf00000c2666, 0xbfffffee0000023f})},
{true, -155, MType({0x5555355555588889, 0xfffffff000000155})},
{true, -156, MType({0x5555515555558889, 0xfffffff800000055})},
{false, 0, MType({0x0, 0x0})},
{false, -155, MType({0xaaaaacaaaaaac444, 0x800000040000002a})},
{false, -154, MType({0xaaaabaaaaaac4444, 0x80000008000000aa})},
{false, -154, MType({0x5100000c2666, 0xc000001200000240})},
{false, -153, MType({0xaaab2aaaaac44444, 0x80000010000002aa})},
{false, -153, MType({0x55568dd555a37555, 0xa000001900000535})},
{false, -153, MType({0x2880000c26667, 0xc000002400000900})},
{false, -153, MType({0xaaaf5b2aac4ed778, 0xe000003100000e4a})},
{false, -152, MType({0xaaaeaaaaac444445, 0x8000002000000aaa})},
{false, -152, MType({0x6684002e21cce, 0x9000002880000f30})},
{false, -152, MType({0x555f19555a375558, 0xa0000032000014d5})},
{false, -152, MType({0xaab8f6eab287cde2, 0xb000003c80001bba})},
{false, -152, MType({0x1440000c26666e, 0xc000004800002400})},
{false, -152, MType({0x5571399567767efb, 0xd000005480002dc5})},
{false, -152, MType({0xaad02eaac4ed778b, 0xe00000620000392a})},
{false, -152, MType({0x3170402514301d, 0xf000007080004650})},
{false, -151, MType({0xaacaaaaac444445a, 0x8000004000002aaa})},
{false, -151, MType({0x557e1d7577ff70a7, 0x880000484000332d})},
{false, -151, MType({0x3342002e21ccf8, 0x9000005100003cc0})},
{false, -151, MType({0xaaea4ccae71e494d, 0x9800005a40004772})},
{false, -151, MType({0x55a37555a37555a7, 0xa000006400005355})},
{false, -151, MType({0x5ef62063b5a207, 0xa800006e40006078})},
{false, -151, MType({0xab1d0cab287cde6e, 0xb000007900006eea})},
{false, -151, MType({0x55ddf975f2787ade, 0xb800008440007ebd})},
{false, -151, MType({0xa20000c2666759, 0xc000009000009000})},
{false, -151, MType({0xab6966cb9915d3e1, 0xc800009c4000a2c2})},
{false, -151, MType({0x563477567767f078, 0xd00000a90000b715})},
{false, -151, MType({0x1037e215e50ad20, 0xd80000b64000cd08})},
{false, -151, MType({0xabd6caac4ed779dc, 0xe00000c40000e4aa})},
{false, -151, MType({0x56aeaf774a1806b0, 0xe80000d24000fe0d})},
{false, -151, MType({0x18b82025143039f, 0xf00000e100011940})},
{false, -151, MType({0xac6d9acd659ee0ad, 0xf80000f040013652})},
{false, -150, MType({0xabaaaaac444446ef, 0x800000800000aaaa})},
{false, -150, MType({0x1218811ddba1d9b, 0x840000882000bb2c})},
{false, -150, MType({0x569b96577ff70c5f, 0x880000908000ccb5})},
{false, -150, MType({0xac1907bd2bcd8b3b, 0x8c0000992000df4e})},
{false, -150, MType({0x19a1002e21cd235, 0x900000a20000f300})},
{false, -150, MType({0x571ee468a3d1394e, 0x940000ab200107d1})},
{false, -150, MType({0xaca7bbae71e4988b, 0x980000b480011dca})},
{false, -150, MType({0x234ce144d5ea7f0, 0x9c0000be200134f4})},
{false, -150, MType({0x57c6555a37555f82, 0xa00000c800014d55})},
{false, -150, MType({0xad5c8cc030ed5744, 0xa40000d2200166f6})},
{false, -150, MType({0x2f7b1063b5a273b, 0xa80000dc800181e0})},
{false, -150, MType({0x5898006c57dec76f, 0xac0000e720019e19})},
{false, -150, MType({0xae3dbab287cdefe3, 0xb00000f20001bbaa})},
{false, -150, MType({0x3e92118cc8a789f, 0xb40000fd2001da9c})},
{false, -150, MType({0x599a765f2787b9aa, 0xb80001088001faf5})},
{false, -150, MType({0xaf51fec59a49eb0a, 0xbc00011420021cbe})},
{false, -150, MType({0x510000c266684c6, 0xc000012000024000})},
{false, -150, MType({0x5ad4c172cd849ee9, 0xc400012c200264c1})},
{false, -150, MType({0xb0a08bb9915d5179, 0xc800013880028b0a})},
{false, -150, MType({0x673a92073bc1480, 0xcc0001452002b2e4})},
{false, -150, MType({0x5c4e6567767f2009, 0xd00001520002dc55})},
{false, -150, MType({0xb2310dce9b97cc1d, 0xd400015f20030766})},
{false, -150, MType({0x81bf115e50af0c7, 0xd800016c80033420})},
{false, -150, MType({0x5e0f5f7d54f14614, 0xdc00017a20036289})},
{false, -150, MType({0xb40baac4ed77c410, 0xe0000188000392aa})},
{false, -150, MType({0xa11262cb0e002c7, 0xe40001962003c48c})},
{false, -150, MType({0x60202674a1809a47, 0xe80001a48003f835})},
{false, -150, MType({0xb63901dcc1c582a0, 0xec0001b320042dae})},
{false, -150, MType({0xc5c1025143073df, 0xf00001c200046500})},
{false, -150, MType({0x6289aa8d9b594616, 0xf40001d120049e31})},
{false, -150, MType({0xb8c22bd659ee5155, 0xf80001e08004d94a})},
{false, -150, MType({0xf05f03f52b4cdae, 0xfc0001f020051654})},
{false, -149, MType({0xb2aaaac44444999a, 0x800001000002aaaa})},
}};
// > P = fpminimax((log(1 + x) - x)/x^2, 2, [|1, 128...|],
// [-0x1.0002143p-29 , 0x1p-29]);
// > P;
// > dirtyinfnorm(log(1 + x)/x - x*P, [-0x1.0002143p-29 , 0x1p-29]);
// 0x1.99a3...p-121
const Float128 BIG_COEFFS[3]{
{true, -129, MType({0xb59c58e5554d581c, 0x800000000006a710})},
{false, -129, MType({0xde05c7c94ae9cbae, 0xaaaaaaaaaaaaaabd})},
{true, -128, MType({0x0, 0x8000000000000000})},
};
// Reuse the output of the fast pass range reduction.
// -2^-8 <= m_x < 2^-7
double log_accurate(int e_x, int index, double m_x) {
Float128 e_x_f128(static_cast<float>(e_x));
Float128 sum = fputil::quick_mul(LOG_2, e_x_f128);
sum = fputil::quick_add(sum, LOG_TABLE.step_1[index]);
Float128 v_f128 = log_range_reduction(m_x, LOG_TABLE, sum);
sum = fputil::quick_add(sum, v_f128);
// Polynomial approximation
Float128 p = fputil::quick_mul(v_f128, BIG_COEFFS[0]);
p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[1]));
p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[2]));
p = fputil::quick_mul(v_f128, p);
Float128 r = fputil::quick_add(sum, p);
return static_cast<double>(r);
}
} // namespace
LLVM_LIBC_FUNCTION(double, log, (double x)) {
using FPBits_t = typename fputil::FPBits<double>;
FPBits_t xbits(x);
uint64_t x_u = xbits.uintval();
int x_e = -FPBits_t::EXPONENT_BIAS;
if (LIBC_UNLIKELY(x_u == 0x3FF0'0000'0000'0000ULL)) {
// log(1.0) = +0.0
return 0.0;
}
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::MIN_NORMAL ||
xbits.uintval() > FPBits_t::MAX_NORMAL)) {
if (xbits.is_zero()) {
// return -Inf and raise FE_DIVBYZERO.
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<double>(FPBits_t::neg_inf());
}
if (xbits.get_sign() && !xbits.is_nan()) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
return FPBits_t::build_quiet_nan(0);
}
if (xbits.is_inf_or_nan()) {
return x;
}
// Normalize denormal inputs.
xbits.set_val(x * 0x1.0p52);
x_e -= 52;
x_u = xbits.uintval();
}
// log(x) = log(2^x_e * x_m)
// = x_e * log(2) + log(x_m)
// Range reduction for log(x_m):
// For each x_m, we would like to find r such that:
// -2^-8 <= r * x_m - 1 < 2^-7
int shifted = x_u >> 45;
int index = shifted & 0x7F;
double r = RD[index];
// Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are
// all 1's.
x_e += static_cast<int>((x_u + (1ULL << 45)) >> 52);
double e_x = static_cast<double>(x_e);
// hi is exact
double hi = fputil::multiply_add(e_x, LOG_2_HI, LOG_R_DD[index].hi);
// lo errors ~ e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo) + rounding err
// <= 2 * (e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo))
double lo = fputil::multiply_add(e_x, LOG_2_LO, LOG_R_DD[index].lo);
// Set m = 1.mantissa.
uint64_t x_m = (x_u & 0x000F'FFFF'FFFF'FFFFULL) | 0x3FF0'0000'0000'0000ULL;
double m = FPBits_t(x_m).get_val();
double u, u_sq, err;
fputil::DoubleDouble r1;
// Perform exact range reduction
#ifdef LIBC_TARGET_CPU_HAS_FMA
u = fputil::multiply_add(r, m, -1.0); // exact
#else
uint64_t c_m = x_m & 0x3FFF'E000'0000'0000ULL;
double c = FPBits_t(c_m).get_val();
u = fputil::multiply_add(r, m - c, CD[index]); // exact
#endif // LIBC_TARGET_CPU_HAS_FMA
// Exact sum:
// r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u
r1 = fputil::exact_add(hi, u);
// Error of u_sq = ulp(u^2);
u_sq = u * u;
// Total error is bounded by ~ C * ulp(u^2).
// Degree-7 minimax polynomial
double p0 = fputil::multiply_add(u, LOG_COEFFS[1], LOG_COEFFS[0]);
double p1 = fputil::multiply_add(u, LOG_COEFFS[3], LOG_COEFFS[2]);
double p2 = fputil::multiply_add(u, LOG_COEFFS[5], LOG_COEFFS[4]);
double p = fputil::polyeval(u_sq, lo + r1.lo, p0, p1, p2);
// Technicallly error of r1.lo is bounded by:
// hi*ulp(log(2)_lo) + C*ulp(u^2)
// To simplify the error computation a bit, we replace |hi|*ulp(log(2)_lo)
// with the upper bound: 2^11 * ulp(log(2)_lo) = 2^-85.
// Total error is bounded by ~ C * ulp(u^2) + 2^-85.
err = fputil::multiply_add(u_sq, P_ERR, HI_ERR);
// Lower bound from the result
double left = r1.hi + (p - err);
// Upper bound from the result
double right = r1.hi + (p + err);
// Ziv's test if fast pass is accurate enough.
if (left == right)
return left;
return log_accurate(x_e, index, u);
}
} // namespace __llvm_libc

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
//===-- Extra range reduction steps for accurate pass of logarithms -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_MATH_GENERIC_LOG_RANGE_REDUCTION_H
#define LLVM_LIBC_SRC_MATH_GENERIC_LOG_RANGE_REDUCTION_H
#include "common_constants.h"
#include "src/__support/FPUtil/dyadic_float.h"
namespace __llvm_libc {
// Struct to store -log*(r) for 4 range reduction steps.
struct LogRR {
fputil::DyadicFloat<128> step_1[128];
fputil::DyadicFloat<128> step_2[193];
fputil::DyadicFloat<128> step_3[161];
fputil::DyadicFloat<128> step_4[130];
};
// Perform logarithm range reduction steps 2-4.
// Inputs from the first step of range reduction:
// m_x : the reduced argument after the first step of range reduction
// satisfying -2^-8 <= m_x < 2^-7 and ulp(m_x) >= 2^-60.
// idx1: index of the -log(r1) table from the first step.
// Outputs of the extra range reduction steps:
// sum: adding -log(r1) - log(r2) - log(r3) - log(r4) to the resulted sum.
// return value: the reduced argument v satisfying:
// -0x1.0002143p-29 <= v < 0x1p-29, and ulp(v) >= 2^(-125).
LIBC_INLINE fputil::DyadicFloat<128>
log_range_reduction(double m_x, const LogRR &log_table,
fputil::DyadicFloat<128> &sum) {
using Float128 = typename fputil::DyadicFloat<128>;
using MType = typename Float128::MantissaType;
int64_t v = static_cast<int64_t>(m_x * 0x1.0p60); // ulp = 2^-60
// Range reduction - Step 2
// Output range: vv2 in [-0x1.3ffcp-15, 0x1.3e3dp-15].
// idx2 = trunc(2^14 * (v + 2^-8 + 2^-15))
size_t idx2 = static_cast<size_t>((v + 0x10'2000'0000'0000) >> 46);
sum = fputil::quick_add(sum, log_table.step_2[idx2]);
int64_t s2 = static_cast<int64_t>(S2[idx2]); // |s| <= 2^-7, ulp = 2^-16
int64_t sv2 = s2 * v; // |s*v| < 2^-14, ulp = 2^(-60-16) = 2^-76
int64_t spv2 = (s2 << 44) + v; // |s + v| < 2^-14, ulp = 2^-60
int64_t vv2 = (spv2 << 16) + sv2; // |vv2| < 2^-14, ulp = 2^-76
// Range reduction - Step 3
// Output range: vv3 in [-0x1.01928p-22 , 0x1p-22]
// idx3 = trunc(2^21 * (v + 80*2^-21 + 2^-22))
size_t idx3 = static_cast<size_t>((vv2 + 0x2840'0000'0000'0000) >> 55);
sum = fputil::quick_add(sum, log_table.step_3[idx3]);
int64_t s3 = static_cast<int64_t>(S3[idx3]); // |s| < 2^-13, ulp = 2^-21
int64_t spv3 = (s3 << 55) + vv2; // |s + v| < 2^-21, ulp = 2^-76
// |s*v| < 2^-27, ulp = 2^(-76-21) = 2^-97
__int128_t sv3 = static_cast<__int128_t>(s3) * static_cast<__int128_t>(vv2);
// |vv3| < 2^-21, ulp = 2^-97
__int128_t vv3 = (static_cast<__int128_t>(spv3) << 21) + sv3;
// Range reduction - Step 4
// Output range: vv4 in [-0x1.0002143p-29 , 0x1p-29]
// idx4 = trunc(2^21 * (v + 65*2^-28 + 2^-29))
size_t idx4 = static_cast<size_t>((static_cast<int>(vv3 >> 68) + 131) >> 1);
sum = fputil::quick_add(sum, log_table.step_4[idx4]);
__int128_t s4 = static_cast<__int128_t>(S4[idx4]); // |s| < 2^-21, ulp = 2^-28
// |s + v| < 2^-28, ulp = 2^-97
__int128_t spv4 = (s4 << 69) + vv3;
// |s*v| < 2^-42, ulp = 2^(-97-28) = 2^-125
__int128_t sv4 = s4 * vv3;
// |vv4| < 2^-28, ulp = 2^-125
__int128_t vv4 = (spv4 << 28) + sv4;
return (vv4 < 0) ? Float128(true, -125,
MType({static_cast<uint64_t>(-vv4),
static_cast<uint64_t>((-vv4) >> 64)}))
: Float128(false, -125,
MType({static_cast<uint64_t>(vv4),
static_cast<uint64_t>(vv4 >> 64)}));
}
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_GENERIC_LOG_RANGE_REDUCTION_H

18
libc/src/math/log.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for log ---------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_MATH_LOG_H
#define LLVM_LIBC_SRC_MATH_LOG_H
namespace __llvm_libc {
double log(double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_LOG_H

View File

@ -1267,6 +1267,20 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
add_fp_unittest(
log_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
log_test.cpp
DEPENDS
libc.src.errno.errno
libc.include.math
libc.src.math.log
libc.src.__support.FPUtil.fp_bits
)
add_fp_unittest(
logf_test
NEED_MPFR

View File

@ -0,0 +1,138 @@
//===-- Unittests for log -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "src/__support/FPUtil/FPBits.h"
#include "src/errno/libc_errno.h"
#include "src/math/log.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
#include <math.h>
#include <errno.h>
#include <stdint.h>
namespace mpfr = __llvm_libc::testing::mpfr;
using __llvm_libc::testing::tlog;
DECLARE_SPECIAL_CONSTANTS(double)
TEST(LlvmLibcLogTest, SpecialNumbers) {
EXPECT_FP_EQ(aNaN, __llvm_libc::log(aNaN));
EXPECT_FP_EQ(inf, __llvm_libc::log(inf));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(__llvm_libc::log(neg_inf), FE_INVALID);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, __llvm_libc::log(0.0), FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, __llvm_libc::log(-0.0), FE_DIVBYZERO);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(__llvm_libc::log(-1.0), FE_INVALID);
EXPECT_FP_EQ_ALL_ROUNDING(zero, __llvm_libc::log(1.0));
}
TEST(LlvmLibcLogTest, TrickyInputs) {
constexpr int N = 30;
constexpr uint64_t INPUTS[N] = {
0x3ff0000000000000, // x = 1.0
0x4024000000000000, // x = 10.0
0x4059000000000000, // x = 10^2
0x408f400000000000, // x = 10^3
0x40c3880000000000, // x = 10^4
0x40f86a0000000000, // x = 10^5
0x412e848000000000, // x = 10^6
0x416312d000000000, // x = 10^7
0x4197d78400000000, // x = 10^8
0x41cdcd6500000000, // x = 10^9
0x4202a05f20000000, // x = 10^10
0x42374876e8000000, // x = 10^11
0x426d1a94a2000000, // x = 10^12
0x42a2309ce5400000, // x = 10^13
0x42d6bcc41e900000, // x = 10^14
0x430c6bf526340000, // x = 10^15
0x4341c37937e08000, // x = 10^16
0x4376345785d8a000, // x = 10^17
0x43abc16d674ec800, // x = 10^18
0x43e158e460913d00, // x = 10^19
0x4415af1d78b58c40, // x = 10^20
0x444b1ae4d6e2ef50, // x = 10^21
0x4480f0cf064dd592, // x = 10^22
0x3fefffffffef06ad, 0x3fefde0f22c7d0eb, 0x225e7812faadb32f,
0x3fee1076964c2903, 0x3fdfe93fff7fceb0, 0x3ff012631ad8df10,
0x3fefbfdaa448ed98,
};
for (int i = 0; i < N; ++i) {
double x = double(FPBits(INPUTS[i]));
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log, x, __llvm_libc::log(x),
0.5);
}
}
TEST(LlvmLibcLogTest, AllExponents) {
double x = 0x1.0p-1074;
for (int i = -1074; i < 1024; ++i, x *= 2.0) {
ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log, x, __llvm_libc::log(x),
0.5);
}
}
TEST(LlvmLibcLogTest, InDoubleRange) {
constexpr uint64_t COUNT = 1234561;
constexpr uint64_t START = 0x3FD0'0000'0000'0000ULL; // 0.25
constexpr uint64_t STOP = 0x4010'0000'0000'0000ULL; // 4.0
// constexpr uint64_t START = 0x3FF0'0000'0000'0000ULL; // 1.0
// constexpr uint64_t STOP = 0x4000'0000'0000'0000ULL; // 2.0
constexpr uint64_t STEP = (STOP - START) / COUNT;
auto test = [&](mpfr::RoundingMode rounding_mode) {
mpfr::ForceRoundingMode __r(rounding_mode);
uint64_t fails = 0;
uint64_t count = 0;
uint64_t cc = 0;
double mx, mr = 0.0;
double tol = 0.5;
for (uint64_t i = 0, v = START; i <= COUNT; ++i, v += STEP) {
double x = FPBits(v).get_val();
if (isnan(x) || isinf(x) || x < 0.0)
continue;
libc_errno = 0;
double result = __llvm_libc::log(x);
++cc;
if (isnan(result) || isinf(result))
continue;
++count;
// ASSERT_MPFR_MATCH(mpfr::Operation::Log, x, result, 0.5);
if (!EXPECT_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Log, x, result,
0.5, rounding_mode)) {
++fails;
while (!EXPECT_MPFR_MATCH_ROUNDING_SILENTLY(
mpfr::Operation::Log, x, result, tol, rounding_mode)) {
mx = x;
mr = result;
tol *= 2.0;
}
}
}
tlog << " Log failed: " << fails << "/" << count << "/" << cc
<< " tests.\n";
tlog << " Max ULPs is at most: " << static_cast<uint64_t>(tol) << ".\n";
if (fails) {
EXPECT_MPFR_MATCH(mpfr::Operation::Log, mx, mr, 0.5, rounding_mode);
}
};
tlog << " Test Rounding To Nearest...\n";
test(mpfr::RoundingMode::Nearest);
tlog << " Test Rounding Downward...\n";
test(mpfr::RoundingMode::Downward);
tlog << " Test Rounding Upward...\n";
test(mpfr::RoundingMode::Upward);
tlog << " Test Rounding Toward Zero...\n";
test(mpfr::RoundingMode::TowardZero);
}