diff mbox series

[RFC] libstdc++: Replace Ryu with Teju Jagua for float.

Message ID 20240805202904.14254-1-cassio.neri@gmail.com
State New
Headers show
Series [RFC] libstdc++: Replace Ryu with Teju Jagua for float. | expand

Commit Message

Cassio Neri Aug. 5, 2024, 8:29 p.m. UTC
Implement the template function teju_jagua which finds the shortest
representation of a floating-point number. The floating-point type is a
template parameter and the implementation is generic enough to handle all
floating-point types of interest, namely, IEEE 754, std::bfloat16_t,
x86 80-bit and IBM128.

The function uses a few helpers and traits classes to handle the
different floating-point types. This patch only provides those required
for float and shows the pattern to be followed by subsequent patches
that will handle the remaining floating-point types.

Add new static data to the existent struct floating_type_traits<float>
which are required by teju_jagua. Some of these duplicate information
that is already there and used by Ryu. A subsequent clean-up patch will
remove duplications once the shortest representation for all types is
found by teju_jagua.

libstdc++-v3/ChangeLog:

	* src/c++17/floating_to_chars.cc: implement teju_jagua and
		helpers (for float).
	* src/c++17/floating_to_chars_tables.h: tables with constants
		required at runtime.
---
 libstdc++-v3/src/c++17/floating_to_chars.cc   | 321 +++++++-
 .../src/c++17/floating_to_chars_tables.h      | 716 ++++++++++++++++++
 2 files changed, 1027 insertions(+), 10 deletions(-)
 create mode 100644 libstdc++-v3/src/c++17/floating_to_chars_tables.h

--
2.43.0

Comments

Andi Kleen Aug. 6, 2024, 3:27 p.m. UTC | #1
Cassio Neri <cassio.neri@gmail.com> writes:

> Implement the template function teju_jagua which finds the shortest
> representation of a floating-point number. The floating-point type is a
> template parameter and the implementation is generic enough to handle all
> floating-point types of interest, namely, IEEE 754, std::bfloat16_t,
> x86 80-bit and IBM128.

So the only benefit is performance, right? So the patch
should come with some performance numbers how it is better 
than the old code. Also how did you validate that it works
correctly?

-Andi
Jonathan Wakely Aug. 6, 2024, 5:10 p.m. UTC | #2
On Tue, 6 Aug 2024, 17:28 Andi Kleen, <ak@linux.intel.com> wrote:

> Cassio Neri <cassio.neri@gmail.com> writes:
>
> > Implement the template function teju_jagua which finds the shortest
> > representation of a floating-point number. The floating-point type is a
> > template parameter and the implementation is generic enough to handle all
> > floating-point types of interest, namely, IEEE 754, std::bfloat16_t,
> > x86 80-bit and IBM128.
>
> So the only benefit is performance, right?


The functions should be as fast as possible.

The algorithm is also simpler though.

So the patch
> should come with some performance numbers how it is better
> than the old code. Also how did you validate that it works
> correctly?
>

See the talks linked to in
https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659362.html



> -Andi
>
Cassio Neri Aug. 7, 2024, 7:14 p.m. UTC | #3
On top of what Jonathan said, Teju Jagua yields a smaller binary size since
it needs fewer look-up tables.

Regarding performance and correctness:

1) My patch passes all the tests.

2) The GitHub project of the reference implementation (*) scans all floats
and the results of Teju Jagua, Ryu and Dragonbox match.

3) The project (*) benchmarks ran on my PC show performance improvements.
For doubles, Teju Jagua 98% faster than Ryu. For floats the speed up is
about 50%.

I'll provide easier to run benchmark programs for, potentially, being added
to gcc's repo.

4) I have notes proving the mathematical correctness of the algorithm which
I will turn into a paper to be uploaded to the arxiv and submitted to a
peer-reviewed journal.
(*) I'll soon document the project for others to run tests and benchmarks.

Best regards,
Cassio.

On Tue, 6 Aug 2024, 18:10 Jonathan Wakely, <jwakely.gcc@gmail.com> wrote:

>
>
> On Tue, 6 Aug 2024, 17:28 Andi Kleen, <ak@linux.intel.com> wrote:
>
>> Cassio Neri <cassio.neri@gmail.com> writes:
>>
>> > Implement the template function teju_jagua which finds the shortest
>> > representation of a floating-point number. The floating-point type is a
>> > template parameter and the implementation is generic enough to handle
>> all
>> > floating-point types of interest, namely, IEEE 754, std::bfloat16_t,
>> > x86 80-bit and IBM128.
>>
>> So the only benefit is performance, right?
>
>
> The functions should be as fast as possible.
>
> The algorithm is also simpler though.
>
> So the patch
>> should come with some performance numbers how it is better
>> than the old code. Also how did you validate that it works
>> correctly?
>>
>
> See the talks linked to in
> https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659362.html
>
>
>
>> -Andi
>>
>>
Patrick Palka Aug. 14, 2024, 10:26 p.m. UTC | #4
On Mon, 5 Aug 2024, Cassio Neri wrote:

> Implement the template function teju_jagua which finds the shortest
> representation of a floating-point number. The floating-point type is a
> template parameter and the implementation is generic enough to handle all
> floating-point types of interest, namely, IEEE 754, std::bfloat16_t,
> x86 80-bit and IBM128.
> 
> The function uses a few helpers and traits classes to handle the
> different floating-point types. This patch only provides those required
> for float and shows the pattern to be followed by subsequent patches
> that will handle the remaining floating-point types.
> 
> Add new static data to the existent struct floating_type_traits<float>
> which are required by teju_jagua. Some of these duplicate information
> that is already there and used by Ryu. A subsequent clean-up patch will
> remove duplications once the shortest representation for all types is
> found by teju_jagua.

Sounds great, thanks very much for this patch!

At a high level, I wonder if we want to make standalone and isolate the
implementation of this algorithm into a separate namespace / source
file, like we do for Ryu?  The main dependency currently is on
floating_type_traits which is used as a template argument to some
functions, but I guess that can be removed by parameterizing instead
on the inidividual properties of the floating point type.  I don't
feel strongly either way, but I guess it'd be good to have consistency
with how integrate Ryu.  I wonder what others think?

> 
> libstdc++-v3/ChangeLog:
> 
> 	* src/c++17/floating_to_chars.cc: implement teju_jagua and
> 		helpers (for float).
> 	* src/c++17/floating_to_chars_tables.h: tables with constants
> 		required at runtime.
> ---
>  libstdc++-v3/src/c++17/floating_to_chars.cc   | 321 +++++++-
>  .../src/c++17/floating_to_chars_tables.h      | 716 ++++++++++++++++++
>  2 files changed, 1027 insertions(+), 10 deletions(-)
>  create mode 100644 libstdc++-v3/src/c++17/floating_to_chars_tables.h
> 
> diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc b/libstdc++-v3/src/c++17/floating_to_chars.cc
> index 2c9da977cd9..b6adbf9cf5f 100644
> --- a/libstdc++-v3/src/c++17/floating_to_chars.cc
> +++ b/libstdc++-v3/src/c++17/floating_to_chars.cc
> @@ -96,6 +96,8 @@ using F128_type = void;
> 
>  #include <stdint.h>
> 
> +#include "floating_to_chars_tables.h"
> +
>  namespace
>  {
>  #if defined __SIZEOF_INT128__
> @@ -132,6 +134,26 @@ namespace
>      { return generic128::generic_to_chars(v, result); }
>    } // namespace ryu
> 
> +  // Binary or decimal field representation of a positive floating-point number.
> +  // The base is implicitly given by the context and the represented number is:
> +  //   mantissa * base ^ exponent.
> +  template <typename Mantissa>
> +  struct fields {
> +    Mantissa mantissa;
> +    int32_t  exponent;
> +  };
> +
> +  // Binary or decimal field representation of a floating-point number.
> +  // The base is implicitly given by the context and the represented number is:
> +  //   (sign ? -1 : 1) * mantissa * base ^ exponent.
> +  template <typename Mantissa>
> +  struct signed_fields;
> +
> +  // TODO (CN): Remove.
> +  template <>
> +    struct signed_fields<uint32_t> : ryu::floating_decimal_32
> +    { };
> +
>    // A traits class that contains pertinent information about the binary
>    // format of each of the floating-point types we support.
>    template<typename T>
> @@ -149,6 +171,12 @@ namespace
> 
>        static constexpr uint64_t pow10_adjustment_tab[]
>  	= { 0b0000000000011101011100110101100101101110000000000000000000000000 };
> +
> +      using fields_t = signed_fields<mantissa_t>;
> +
> +      static constexpr uint32_t mantissa_size    =   23;
> +      static constexpr uint32_t exponent_size    =    8;
> +      static constexpr int32_t  exponent_minimum = -149;

IIUC exponent_minimum is fully determined by mantissa_size,
exponent_size and has_implicit_leading_bit right?  If so it might
be more illustrative to have a constexpr function to compute
it instead of hardcoding it for each floating point format.

>      };
> 
>    template<>
> @@ -430,6 +458,276 @@ namespace
>        bool sign;
>      };
> 
> +  // Return 2^k.
> +  template <typename T>
> +    constexpr T
> +    pow2(const uint32_t k)
> +    {
> +      return T(1) << k;
> +    }
> +
> +  // Return the k least significant bits of n (i.e., e % 2^k.)
> +  template <typename T>
> +    T
> +    lsb(const T n, const uint32_t k)
> +    {
> +      return n % pow2<T>(k);
> +    }
> +
> +  // Return the binary field representation of an IEEE Float value.
> +  template <typename Float, typename Traits = floating_type_traits<Float>>
> +    typename Traits::fields_t
> +    to_binary_ieee(const Float value)
> +    {
> +      using mantissa_t = typename Traits::mantissa_t;
> +
> +      mantissa_t bits;
> +      memcpy(&bits, &value, sizeof(value));
> +
> +      const mantissa_t mantissa_bits = lsb(bits, Traits::mantissa_size);
> +      bits >>= Traits::mantissa_size;
> +
> +      const int32_t exponent_bits = lsb(bits, Traits::exponent_size);
> +      bits >>= Traits::exponent_size;
> +
> +      const bool negative = bits != 0;
> +
> +      int32_t    exponent = int32_t(exponent_bits) + Traits::exponent_minimum;
> +      mantissa_t mantissa = mantissa_bits;
> +
> +      if (exponent_bits != 0)
> +      {
> +	// Number is normal.
> +	exponent -= 1;from
> +	mantissa += pow2<mantissa_t>(Traits::mantissa_size);
> +      }
> +
> +      return { mantissa, exponent, negative } ;
> +    }

It might be convenient to somehow use get_ieee_repr here since that
already handles decomposition of the more exotic binary formats.

> +
> +  // Return the binary field representation of a float value.
> +  typename floating_type_traits<float>::fields_t
> +  to_binary(const float value)
> +  {
> +    return to_binary_ieee(value);
> +  }
> +
> +  // Check whether m is multiple of 2^k.
> +  template <typename Mantissa>
> +    bool
> +    is_multiple_of_pow2(const Mantissa m, const uint32_t k)
> +    {
> +      return lsb(m, k) == 0;
> +    }
> +
> +  // Check whether the binary field representation of a number is that of a
> +  // small integer.
> +  template <typename Traits, typename Mantissa = typename Traits::mantissa_t>
> +    bool
> +    is_small_integer(const Mantissa m, const int32_t e)
> +    {
> +      return -static_cast<int32_t>(Traits::mantissa_size) <= e && e <= 0 &&
> +	is_multiple_of_pow2(m, -e);
> +    }
> +
> +  // Return the quotient n / 10.
> +  uint32_t
> +  div10(const uint32_t n)
> +  {
> +    __glibcxx_assert(n < 1'073'741'829);
> +    constexpr uint64_t M = 429'496'730; // M ~= 2^32 / 10.
> +    return static_cast<uint32_t>(M * n >> 32);
> +  }
> +
> +  // Return the largest exponent f such that 10^f <= 2^e, i.e., f is the integer
> +  // part of e * log_10(2).
> +  int32_t
> +  log10_pow2(const int32_t e)
> +  {
> +    __glibcxx_assert(-112'815 <= e && e <= 112'815);
> +    constexpr uint64_t M = 1'292'913'987; // M ~= 2^32 * log_10(2)
> +    return static_cast<int32_t>(M * e >> 32);
> +  }
> +
> +  // Return the residual r = e - e_0, where e_0 is the smallest exponent such
> +  // that log10_pow2(e_0) = log10_pow2(e).
> +  uint32_t
> +  log10_pow2_residual(const int32_t e)
> +  {
> +    __glibcxx_assert(-112'815 <= e && e <= 112'815);
> +    constexpr uint64_t M = 1'292'913'987;
> +    return static_cast<uint32_t>(M * e) / M;
> +  }
> +
> +  // Shorten the decimal field representation of a given number by removing
> +  // mantissa's trailing zeros and increasing the exponent accordingly.
> +  template <typename Mantissa>
> +    fields<Mantissa>
> +    remove_trailing_zeros(Mantissa m, int32_t e)
> +    {
> +      while (true)
> +      {
> +	const Mantissa q = div10(m);
> +	if (m != 10 * q)
> +	  return { m, e };
> +	++e;
> +	m = q;
> +      }
> +    }
> +
> +  // Return N * m / 2^64 (multiply and shift), where N is a 64-bits number split
> +  // in two 32-bits parts.
> +  uint32_t
> +  mshift(const uint32_t m, const parts<uint32_t> N)
> +  {
> +    const uint64_t s0 = static_cast<uint64_t>(N.lower) * m;
> +    const uint64_t s1 = static_cast<uint64_t>(N.upper) * m;
> +    return (s1 + (s0 >> 32)) >> 32;
> +  }
> +
> +  // Return N * 2^k / 2^64 (multiply and shift for power of 2), where N is a
> +  // 64-bits number split in two 32-bits parts.
> +  uint32_t
> +  mshift_pow2(const uint32_t k, const parts<uint32_t> N)
> +  {
> +    const int32_t s = int32_t(k) - 32;
> +    if (s <= 0)
> +      return N.upper >> -s;
> +    return (N.upper << s) | (N.lower >> (32 - s));
> +  }
> +
> +  // Check whether m is multiple of 5^f.
> +  // pre: 0 <= f && f < static_cast<int32_t>(size(minverse<Mantissa>::data))
> +  template <typename Mantissa>
> +    bool
> +    is_multiple_of_pow5(const Mantissa m, const int32_t f)
> +    {
> +      const auto [multiplier, bound] = minverse<Mantissa>::data[f];
> +      return m * multiplier <= bound;
> +    }
> +
> +  // Check whether m, for m in { m_a, m_b, c_ 2 }, yields a tie.
> +  template <typename Mantissa>
> +    bool
> +    is_tie(const Mantissa m, const int32_t f)
> +    {
> +      return 0 <= f
> +	&& f < static_cast<int32_t>(std::size(minverse<Mantissa>::data))
> +	&& is_multiple_of_pow5(m, f);
> +    }
> +
> +  // Check whether the mantissa of an uncentred value (whose decimal exponent is
> +  // f) yields a tie.
> +  template <typename Traits>
> +  bool
> +  is_tie_uncentred(const int32_t f)
> +  {
> +    return f > 0 && Traits::mantissa_size % 4 == 2;
> +  }
> +
> +  // Return the shortest decimal field representation of a positive
> +  // floating-point number whose binary field representation is given.
> +  // Implementation based on: https://github.com/cassioneri/teju_jagua.
> +  template <typename Traits, typename Mantissa = typename Traits::mantissa_t>
> +    fields<Mantissa>
> +    teju_jagua(const fields<Mantissa> binary)
> +    {
> +      const auto [m , e] = binary;
> +
> +      if (is_small_integer<Traits>(m, e))
> +	return remove_trailing_zeros(m >> -e, 0);
> +
> +      const int32_t  f = log10_pow2(e);
> +      const uint32_t r = log10_pow2_residual(e);
> +      const auto     N = to_chars_table::get_multiplier(Mantissa{}, f);
> +
> +      constexpr uint32_t mantissa_size = Traits::mantissa_size;
> +      constexpr Mantissa m_0 = pow2<Mantissa>(mantissa_size);
> +      if (m != m_0 || e == Traits::exponent_minimum)
> +      {
> +	const Mantissa m_a = (2 * m - 1) << r;
> +	const Mantissa a   = mshift(m_a, N);
> +	const Mantissa m_b = (2 * m + 1) << r;
> +	const Mantissa b   = mshift(m_b, N);
> +	const Mantissa q   = div10(b);
> +	const Mantissa s   = 10 * q;

Thinking ahead a bit, would overflow/narrowing within these operations
be an issue with float80, whose mantissa is 64 bits and mantissa_t is
uint64_t?

> +
> +	if (s >= a)
> +	{
> +	  if (s == b)
> +	  {
> +	    if (m % 2 == 0 || !is_tie(m_b, f))
> +	      return remove_trailing_zeros(q, f + 1);
> +	  }
> +	  else if (s > a || (m % 2 == 0 && is_tie(m_a, f)))
> +	    return remove_trailing_zeros(q, f + 1);
> +	}
> +
> +	if ((a + b) % 2 == 1)
> +	  return { (a + b) / 2 + 1, f };
> +
> +	const Mantissa m_c = (2 * 2 * m) << r;
> +	const Mantissa c_2 = mshift(m_c, N);
> +	const Mantissa c   = c_2 / 2;
> +
> +	if (c_2 % 2 == 0 || (c % 2 == 0 && is_tie(c_2, -f)))
> +	  return { c, f };
> +
> +	return { c + 1, f };
> +      }
> +
> +      const Mantissa m_b = 2 * m_0 + 1;
> +      const Mantissa b   = mshift(m_b << r, N);
> +
> +      const Mantissa m_a = 4 * m_0 - 1;
> +      const Mantissa a   = mshift(m_a << r, N) / 2;
> +
> +      if (b > a)
> +      {
> +	const Mantissa q = div10(b);
> +	const Mantissa s = 10 * q;
> +
> +	if (s > a || (s == a && is_tie_uncentred<Traits>(f)))
> +	  return remove_trailing_zeros(q, f + 1);
> +
> +	// m_c = 2 * 2 * m_0 = 2 * 2 * 2^{mantissa_size}
> +	// c_2 = mshift(m_c << r, N);
> +	const uint32_t log2_m_c = mantissa_size + 2;
> +	const Mantissa c_2      = mshift_pow2(log2_m_c + r, N);
> +	const Mantissa c	= c_2 / 2;
> +
> +	if (c == a && !is_tie_uncentred<Traits>(f))
> +	  return { c + 1, f };
> +
> +	if (c_2 % 2 == 0 || (c % 2 == 0 && is_tie(c_2, -f)))
> +	  return { c, f };
> +
> +	return { c + 1, f };
> +      }
> +
> +      else if (is_tie_uncentred<Traits>(f))
> +	return remove_trailing_zeros(a, f);
> +
> +      const Mantissa m_c = 10 * 2 * 2 * m_0;
> +      const Mantissa c_2 = mshift(m_c << r, N);
> +      const Mantissa c   = c_2 / 2;
> +
> +      if (c_2 % 2 == 0 || (c % 2 == 0 && is_tie(c_2, -f)))
> +	return { c, f - 1 };
> +
> +      return { c + 1, f - 1 };
> +    }
> +
> +  // Return the shortest decimal field representation of a Float value.
> +  template <typename Float, typename Traits = floating_type_traits<Float>>
> +    typename Traits::fields_t
> +    teju_jagua(const Float value)
> +    {
> +      auto const [m, e, sign] = to_binary(value);
> +      auto const abs = teju_jagua<Traits>({ m, e });
> +      return { abs.mantissa, abs.exponent, sign };
> +    }
> +
>    // Decompose the floating-point value into its IEEE components.
>    template<typename T>
>      ieee_t<T>
> @@ -454,12 +752,12 @@ namespace
> 
>        ieee_t<T> ieee_repr;
>        ieee_repr.mantissa
> -	= static_cast<mantissa_t>(value_bits & ((uint_t{1} << mantissa_bits) - 1u));
> +	= static_cast<mantissa_t>(lsb(value_bits, mantissa_bits));
>        value_bits >>= mantissa_bits;
>        ieee_repr.biased_exponent
> -	= static_cast<uint32_t>(value_bits & ((uint_t{1} << exponent_bits) - 1u));
> +	= static_cast<uint32_t>(lsb(value_bits, exponent_bits));
>        value_bits >>= exponent_bits;
> -      ieee_repr.sign = (value_bits & 1) != 0;
> +      ieee_repr.sign = lsb(value_bits, 1) != 0;
>        return ieee_repr;
>      }
> 
> @@ -542,12 +840,12 @@ namespace
> 
>        ieee_t<floating_type_float16_t> ieee_repr;
>        ieee_repr.mantissa
> -	= static_cast<mantissa_t>(value_bits & ((uint32_t{1} << mantissa_bits) - 1u));
> +	= static_cast<mantissa_t>(lsb(value_bits, mantissa_bits));
>        value_bits >>= mantissa_bits;
>        ieee_repr.biased_exponent
> -	= static_cast<uint32_t>(value_bits & ((uint32_t{1} << exponent_bits) - 1u));
> +	= static_cast<uint32_t>(lsb(value_bits, exponent_bits));
>        value_bits >>= exponent_bits;
> -      ieee_repr.sign = (value_bits & 1) != 0;
> +      ieee_repr.sign = lsb(value_bits, 1) != 0;
>        // We have mantissa and biased_exponent from the float (originally
>        // float16_t converted to float).
>        // Transform that to float16_t mantissa and biased_exponent.
> @@ -589,12 +887,12 @@ namespace
> 
>        ieee_t<floating_type_bfloat16_t> ieee_repr;
>        ieee_repr.mantissa
> -	= static_cast<mantissa_t>(value_bits & ((uint32_t{1} << mantissa_bits) - 1u));
> +	= static_cast<mantissa_t>(lsb(value_bits, mantissa_bits));
>        value_bits >>= mantissa_bits;
>        ieee_repr.biased_exponent
> -	= static_cast<uint32_t>(value_bits & ((uint32_t{1} << exponent_bits) - 1u));
> +	= static_cast<uint32_t>(lsb(value_bits, exponent_bits));
>        value_bits >>= exponent_bits;
> -      ieee_repr.sign = (value_bits & 1) != 0;
> +      ieee_repr.sign = lsb(value_bits, 1) != 0;
>        // We have mantissa and biased_exponent from the float (originally
>        // bfloat16_t converted to float).
>        // Transform that to bfloat16_t mantissa and biased_exponent.
> @@ -609,7 +907,10 @@ namespace
>      floating_to_shortest_scientific(const T value)
>      {
>        if constexpr (std::is_same_v<T, float>)
> -	return ryu::floating_to_fd32(value);
> +      {
> +	(void) &ryu::floating_to_fd32; // TODO (CN): remove.
> +	return teju_jagua(value);
> +      }
>        else if constexpr (std::is_same_v<T, double>)
>  	return ryu::floating_to_fd64(value);
>        else if constexpr (std::is_same_v<T, long double>
> diff --git a/libstdc++-v3/src/c++17/floating_to_chars_tables.h b/libstdc++-v3/src/c++17/floating_to_chars_tables.h
> new file mode 100644
> index 00000000000..5cb648713b7
> --- /dev/null
> +++ b/libstdc++-v3/src/c++17/floating_to_chars_tables.h
> @@ -0,0 +1,716 @@
> +// Tables used by std::to_chars implementation for floating-point types -*- C++ -*-
> +
> +// Copyright (C) 2020-2024 Free Software Foundation, Inc.
> +//
> +// This file is part of the GNU ISO C++ Library.  This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +
> +// Under Section 7 of GPL version 3, you are granted additional
> +// permissions described in the GCC Runtime Library Exception, version
> +// 3.1, as published by the Free Software Foundation.
> +
> +// You should have received a copy of the GNU General Public License and
> +// a copy of the GCC Runtime Library Exception along with this program;
> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> +// <http://www.gnu.org/licenses/>.
> +
> +#ifndef _GLIBCXX_FLOATING_TO_CHARS_TABLES_H
> +#define _GLIBCXX_FLOATING_TO_CHARS_TABLES_H
> +
> +#include <cstdint>
> +
> +namespace {
> +
> +// Upper and lower parts of mantissa multipliers.
> +template <typename Mantissa>
> +struct parts {
> +  const Mantissa upper;
> +  const Mantissa lower;
> +};
> +
> +// Taken from: https://github.com/cassioneri/teju_jagua.
> +struct to_chars_table {
> +
> +  // Get the multiplier for mantissas of type uint32_t at index f.
> +  // Suits IEEE Binary32.
> +  static parts<uint32_t>
> +  get_multiplier(uint32_t /*tag_dispatch*/, const int32_t f) {
> +    const uint64_t N = _get_multiplier(f).upper + 1;
> +    return { static_cast<uint32_t>(N >> 32), static_cast<uint32_t>(N) };
> +  }
> +
> +private:
> +
> +  static constexpr int32_t _index_minimum = -324;
> +  static constexpr int32_t _index_maximum =  292;
> +
> +  static const parts<uint64_t>&
> +  _get_multiplier(const int32_t f)
> +  {
> +    __glibcxx_assert(_index_minimum <= f && f <= _index_maximum);
> +    return _entry[f - _index_minimum];
> +  }
> +
> +  // Multipliers for mantissas of type uint64_t.
> +  // Suits IEEE Binary64.
> +  static constexpr parts<uint64_t> _entry[] =
> +  {
> +    { 0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2 }, // -324
> +    { 0xfcf62c1dee382c42, 0x46729e03dd9ed7b6 }, // -323
> +    { 0xca5e89b18b602368, 0x385bb19cb14bdfc5 }, // -322
> +    { 0xa1e53af46f801c53, 0x60495ae3c1097fd1 }, // -321
> +    { 0x81842f29f2cce375, 0xe6a1158300d46641 }, // -320
> +    { 0xcf39e50feae16bef, 0xd768226b34870a01 }, // -319
> +    { 0xa5c7ea73224deff3, 0x12b9b522906c0801 }, // -318
> +    { 0x849feec281d7f328, 0xdbc7c41ba6bcd334 }, // -317
> +    { 0xd433179d9c8cb841, 0x5fa60692a46151ec }, // -316
> +    { 0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23 }, // -315
> +    { 0x87cec76f1c830548, 0x8f2293910d0b15b6 }, // -314
> +    { 0xd94ad8b1c7380874, 0x18375281ae7822bd }, // -313
> +    { 0xadd57a27d29339f6, 0x79c5db9af1f9b564 }, // -312
> +    { 0x8b112e86420f6191, 0xfb04afaf27faf783 }, // -311
> +    { 0xde81e40a034bcf4f, 0xf8077f7ea65e58d2 }, // -310
> +    { 0xb201833b35d63f73, 0x2cd2cc6551e513db }, // -309
> +    { 0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649 }, // -308
> +    { 0xe3d8f9e563a198e5, 0x58180fddd97723a7 }, // -307
> +    { 0xb6472e511c81471d, 0xe0133fe4adf8e953 }, // -306
> +    { 0x91d28b7416cdd27e, 0x4cdc331d57fa5442 }, // -305
> +    { 0xe950df20247c83fd, 0x47c6b82ef32a206a }, // -304
> +    { 0xbaa718e68396cffd, 0xd30560258f54e6bb }, // -303
> +    { 0x95527a5202df0ccb, 0x0f37801e0c43ebc9 }, // -302
> +    { 0xeeea5d5004981478, 0x1858ccfce06cac75 }, // -301
> +    { 0xbf21e44003acdd2c, 0xe0470a63e6bd56c4 }, // -300
> +    { 0x98e7e9cccfbd7dbd, 0x8038d51cb897789d }, // -299
> +    { 0xf4a642e14c6262c8, 0xcd27bb612758c0fb }, // -298
> +    { 0xc3b8358109e84f07, 0x0a862f80ec4700c9 }, // -297
> +    { 0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4 }, // -296
> +    { 0xfa856334878fc150, 0xb14f98f6f0feb952 }, // -295
> +    { 0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8 }, // -294
> +    { 0xa0555e361951c366, 0xd7e105bcc3326220 }, // -293
> +    { 0x80444b5e7aa7cf85, 0x7980d163cf5b81b4 }, // -292
> +    { 0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec }, // -291
> +    { 0xa42e74f3d032f525, 0xba3e7ca8b77f5e56 }, // -290
> +    { 0x83585d8fd9c25db7, 0xc831fd53c5ff7eac }, // -289
> +    { 0xd226fc195c6a2f8c, 0x73832eec6fff3112 }, // -288
> +    { 0xa81f301449ee8c70, 0x5c68f256bfff5a75 }, // -287
> +    { 0x867f59a9d4bed6c0, 0x49ed8eabcccc485e }, // -286
> +    { 0xd732290fbacaf133, 0xa97c177947ad4096 }, // -285
> +    { 0xac2820d9623bf429, 0x546345fa9fbdcd45 }, // -284
> +    { 0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e }, // -283
> +    { 0xdc5c5301c56b75f7, 0x7641a140cc7810fc }, // -282
> +    { 0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63 }, // -281
> +    { 0x8d07e33455637eb2, 0xdb0b487b6423e1e9 }, // -280
> +    { 0xe1a63853bbd26451, 0x5e7873f8a0396974 }, // -279
> +    { 0xb484f9dc9641e9da, 0xb1f9f660802dedf7 }, // -278
> +    { 0x906a617d450187e2, 0x27fb2b80668b24c6 }, // -277
> +    { 0xe7109bfba19c0c9d, 0x0cc512670a783ad5 }, // -276
> +    { 0xb8da1662e7b00a17, 0x3d6a751f3b936244 }, // -275
> +    { 0x93e1ab8252f33b45, 0xcabb90e5c942b504 }, // -274
> +    { 0xec9c459d51852ba2, 0xddf8e7d60ed1219f }, // -273
> +    { 0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19 }, // -272
> +    { 0x976e41088617ca01, 0xd5be0503e085d814 }, // -271
> +    { 0xf24a01a73cf2dccf, 0xbc633b39673c8ced }, // -270
> +    { 0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1 }, // -269
> +    { 0x9b10a4e5e9913128, 0xca7cf2b4191c8327 }, // -268
> +    { 0xf81aa16fdc1b81da, 0xdd94b7868e94050b }, // -267
> +    { 0xc67bb4597ce2ce48, 0xb143c6053edcd0d6 }, // -266
> +    { 0x9ec95d1463e8a506, 0xf4363804324a40ab }, // -265
> +    { 0xfe0efb53d30dd4d7, 0xed238cd383aa0111 }, // -264
> +    { 0xcb3f2f7642717713, 0x241c70a936219a74 }, // -263
> +    { 0xa298f2c501f45f42, 0x8349f3ba91b47b90 }, // -262
> +    { 0x8213f56a67f6b29b, 0x9c3b29620e29fc74 }, // -261
> +    { 0xd01fef10a657842c, 0x2d2b7569b0432d86 }, // -260
> +    { 0xa67ff273b8460356, 0x8a892abaf368f138 }, // -259
> +    { 0x8533285c936b35de, 0xd53a88958f872760 }, // -258
> +    { 0xd51ea6fa85785631, 0x552a74227f3ea566 }, // -257
> +    { 0xaa7eebfb9df9de8d, 0xddbb901b98feeab8 }, // -256
> +    { 0x8865899617fb1871, 0x7e2fa67c7a658893 }, // -255
> +    { 0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f }, // -254
> +    { 0xae9672aba3d0c320, 0xa184ac2473b529b2 }, // -253
> +    { 0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f }, // -252
> +    { 0xdf78e4b2bd342cf6, 0x914da9246b255417 }, // -251
> +    { 0xb2c71d5bca9023f8, 0x743e20e9ef511013 }, // -250
> +    { 0x8f05b1163ba6832d, 0x29cb4d87f2a7400f }, // -249
> +    { 0xe4d5e82392a40515, 0x0fabaf3feaa5334b }, // -248
> +    { 0xb7118682dbb66a77, 0x3fbc8c33221dc2a2 }, // -247
> +    { 0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5 }, // -246
> +    { 0xea53df5fd18d5513, 0x84c86189216dc5ee }, // -245
> +    { 0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2 }, // -244
> +    { 0x95f83d0a1fb69cd9, 0x4abdaf101564f98f }, // -243
> +    { 0xeff394dcff8a948e, 0xddfc4b4cef07f5b1 }, // -242
> +    { 0xbff610b0cc6edd3f, 0x17fd090a58d32af4 }, // -241
> +    { 0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a }, // -240
> +    { 0xf5b5d7ec8acb58a2, 0xae10af696774b1dc }, // -239
> +    { 0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3 }, // -238
> +    { 0x9d412e0806e88aa5, 0x8e1f289560ee864f }, // -237
> +    { 0xfb9b7cd9a4a7443c, 0x169840ef017da3b2 }, // -236
> +    { 0xc94930ae1d529cfc, 0xdee033f26797b628 }, // -235
> +    { 0xa1075a24e4421730, 0xb24cf65b8612f820 }, // -234
> +    { 0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a }, // -233
> +    { 0xce1de40642e3f4b9, 0x36251260ab9d668f }, // -232
> +    { 0xa4e4b66b68b65d60, 0xf81da84d56178540 }, // -231
> +    { 0x83ea2b892091e44d, 0x934aed0aab460433 }, // -230
> +    { 0xd31045a8341ca07c, 0x1ede48111209a051 }, // -229
> +    { 0xa8d9d1535ce3b396, 0x7f1839a741a14d0e }, // -228
> +    { 0x8714a775e3e95c78, 0x65acfaec34810a72 }, // -227
> +    { 0xd8210befd30efa5a, 0x3c47f7e05401aa4f }, // -226
> +    { 0xace73cbfdc0bfb7b, 0x636cc64d1001550c }, // -225
> +    { 0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70 }, // -224
> +    { 0xdd50f1996b947518, 0xd12f124e28f7771a }, // -223
> +    { 0xb10d8e1456105dad, 0x7425a83e872c5f48 }, // -222
> +    { 0x8da471a9de737e24, 0x5ceaecfed289e5d3 }, // -221
> +    { 0xe2a0b5dc971f303a, 0x2e44ae64840fd61e }, // -220
> +    { 0xb54d5e4a127f59c8, 0x2503beb6d00cab4c }, // -219
> +    { 0x910ab1d4db9914a0, 0x1d9c9892400a22a3 }, // -218
> +    { 0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438 }, // -217
> +    { 0xb9a74a0637ce2ee1, 0x6d953e2bd7173693 }, // -216
> +    { 0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9 }, // -215
> +    { 0xeda2ee1c7064130c, 0x1162def06f79df74 }, // -214
> +    { 0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d }, // -213
> +    { 0x98165af37b2153de, 0xc3727a337a8b704b }, // -212
> +    { 0xf356f7ebf83552fe, 0x0583f6b8c4124d44 }, // -211
> +    { 0xc2abf989935ddbfe, 0x6acff893d00ea436 }, // -210
> +    { 0x9bbcc7a142b17ccb, 0x88a66076400bb692 }, // -209
> +    { 0xf92e0c3537826145, 0xa7709a56ccdf8a83 }, // -208
> +    { 0xc75809c42c684dd1, 0x52c07b78a3e60869 }, // -207
> +    { 0x9f79a169bd203e41, 0x0f0062c6e984d387 }, // -206
> +    { 0xff290242c83396ce, 0x7e67047175a15272 }, // -205
> +    { 0xcc20ce9bd35c78a5, 0x31ec038df7b441f5 }, // -204
> +    { 0xa34d721642b06084, 0x27f002d7f95d0191 }, // -203
> +    { 0x82a45b450226b39c, 0xecc0024661173474 }, // -202
> +    { 0xd106f86e69d785c7, 0xe13336d701beba53 }, // -201
> +    { 0xa738c6bebb12d16c, 0xb428f8ac016561dc }, // -200
> +    { 0x85c7056562757456, 0xf6872d5667844e4a }, // -199
> +    { 0xd60b3bd56a5586f1, 0x8a71e223d8d3b075 }, // -198
> +    { 0xab3c2fddeeaad25a, 0xd527e81cad7626c4 }, // -197
> +    { 0x88fcf317f22241e2, 0x441fece3bdf81f04 }, // -196
> +    { 0xdb2e51bfe9d0696a, 0x06997b05fcc0319f }, // -195
> +    { 0xaf58416654a6babb, 0x387ac8d1970027b3 }, // -194
> +    { 0x8c469ab843b89562, 0x93956d7478ccec8f }, // -193
> +    { 0xe070f78d3927556a, 0x85bbe253f47b1418 }, // -192
> +    { 0xb38d92d760ec4455, 0x37c981dcc395a9ad }, // -191
> +    { 0x8fa475791a569d10, 0xf96e017d694487bd }, // -190
> +    { 0xe5d3ef282a242e81, 0x8f1668c8a86da5fb }, // -189
> +    { 0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30 }, // -188
> +    { 0x9316ff75dd87cbd8, 0x09a7f12442d588f3 }, // -187
> +    { 0xeb57ff22fc0c7959, 0xa90cb506d155a7eb }, // -186
> +    { 0xbc4665b596706114, 0x873d5d9f0dde1fef }, // -185
> +    { 0x969eb7c47859e743, 0x9f644ae5a4b1b326 }, // -184
> +    { 0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6 }, // -183
> +    { 0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de }, // -182
> +    { 0x9a3c2087a63f6399, 0x36ac54e2f678864c }, // -181
> +    { 0xf6c69a72a3989f5b, 0x8aad549e57273d46 }, // -180
> +    { 0xc56baec21c7a1916, 0x088aaa1845b8fdd1 }, // -179
> +    { 0x9defbf01b061adab, 0x3a0888136afa64a8 }, // -178
> +    { 0xfcb2cb35e702af78, 0x5cda735244c3d43f }, // -177
> +    { 0xca28a291859bbf93, 0x7d7b8f7503cfdcff }, // -176
> +    { 0xa1ba1ba79e1632dc, 0x6462d92a69731733 }, // -175
> +    { 0x8161afb94b44f57d, 0x1d1be0eebac278f6 }, // -174
> +    { 0xcf02b2c21207ef2e, 0x94f967e45e03f4bc }, // -173
> +    { 0xa59bc234db398c25, 0x43fab9837e699096 }, // -172
> +    { 0x847c9b5d7c2e09b7, 0x69956135febada12 }, // -171
> +    { 0xd3fa922f2d1675f2, 0x42889b8997915ce9 }, // -170
> +    { 0xa99541bf57452b28, 0x353a1607ac744a54 }, // -169
> +    { 0x87aa9aff79042286, 0x90fb44d2f05d0843 }, // -168
> +    { 0xd910f7ff28069da4, 0x1b2ba1518094da05 }, // -167
> +    { 0xada72ccc20054ae9, 0xaf561aa79a10ae6b }, // -166
> +    { 0x8aec23d680043bee, 0x25de7bb9480d5855 }, // -165
> +    { 0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc }, // -164
> +    { 0xb1d219647ae6b31c, 0x596eb2d8ae258fc9 }, // -163
> +    { 0x8e41ade9fbebc27d, 0x14588f13be847308 }, // -162
> +    { 0xe39c49765fdf9d94, 0xed5a7e85fda0b80c }, // -161
> +    { 0xb616a12b7fe617aa, 0x577b986b314d600a }, // -160
> +    { 0x91abb422ccb812ee, 0xac62e055c10ab33b }, // -159
> +    { 0xe912b9d1478ceb17, 0x7a37cd5601aab85e }, // -158
> +    { 0xba756174393d88df, 0x94f971119aeef9e5 }, // -157
> +    { 0x952ab45cfa97a0b2, 0xdd945a747bf26184 }, // -156
> +    { 0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39 }, // -155
> +    { 0xbeeefb584aff8603, 0xaafb550ffacfd8fb }, // -154
> +    { 0x98bf2f79d5993802, 0xef2f773ffbd97a62 }, // -153
> +    { 0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a }, // -152
> +    { 0xc38413cf25e2d70d, 0xfef5138519684abb }, // -151
> +    { 0x9c69a97284b578d7, 0xff2a760414536efc }, // -150
> +    { 0xfa42a8b73abbf48c, 0xcb772339ba1f17fa }, // -149
> +    { 0xc83553c5c8965d3d, 0x6f92829494e5acc8 }, // -148
> +    { 0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d }, // -147
> +    { 0x802221226be55a64, 0xc2494954da2c978a }, // -146
> +    { 0xcd036837130890a1, 0x36dba887c37a8c10 }, // -145
> +    { 0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7 }, // -144
> +    { 0x8335616aed761f1f, 0x7f44e6bd49e807b9 }, // -143
> +    { 0xd1ef0244af2364ff, 0x3207d795430cd927 }, // -142
> +    { 0xa7f26836f282b732, 0x8e6cac7768d7141f }, // -141
> +    { 0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3 }, // -140
> +    { 0xd6f8d7509292d603, 0x45a9d2845d3c42b7 }, // -139
> +    { 0xabfa45da0edbde69, 0x0487db9d17636893 }, // -138
> +    { 0x899504ae72497eba, 0x6a06494a791c53a9 }, // -137
> +    { 0xdc21a1171d42645d, 0x76707543f4fa1f74 }, // -136
> +    { 0xb01ae745b101e9e4, 0x5ec05dcff72e7f90 }, // -135
> +    { 0x8ce2529e2734bb1d, 0x1899e4a65f58660d }, // -134
> +    { 0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b }, // -133
> +    { 0xb454e4a179dd1877, 0x29babe4598c311fc }, // -132
> +    { 0x9043ea1ac7e41392, 0x87c89837ad68db30 }, // -131
> +    { 0xe6d3102ad96cec1d, 0xa60dc059157491e6 }, // -130
> +    { 0xb8a8d9bbe123f017, 0xb80b0047445d4185 }, // -129
> +    { 0x93ba47c980e98cdf, 0xc66f336c36b10138 }, // -128
> +    { 0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf }, // -127
> +    { 0xbd176620a501fbff, 0xb650e5a93bc3d899 }, // -126
> +    { 0x9745eb4d50ce6332, 0xf840b7ba963646e1 }, // -125
> +    { 0xf209787bb47d6b84, 0xc0678c5dbd23a49b }, // -124
> +    { 0xc1a12d2fc3978937, 0x0052d6b1641c83af }, // -123
> +    { 0x9ae757596946075f, 0x3375788de9b06959 }, // -122
> +    { 0xf7d88bc24209a565, 0x1f225a7ca91a4227 }, // -121
> +    { 0xc646d63501a1511d, 0xb281e1fd541501b9 }, // -120
> +    { 0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb }, // -119
> +    { 0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7 }, // -118
> +    { 0xcb090c8001ab551c, 0x5cadf5bfd3072cc6 }, // -117
> +    { 0xa26da3999aef7749, 0xe3be5e330f38f09e }, // -116
> +    { 0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f }, // -115
> +    { 0xcfe87f7cef46ff16, 0xe612641865679a64 }, // -114
> +    { 0xa6539930bf6bff45, 0x84db8346b786151d }, // -113
> +    { 0x850fadc09923329e, 0x03e2cf6bc604ddb1 }, // -112
> +    { 0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b }, // -111
> +    { 0xaa51823e34a7eede, 0xbd4b46f0599fd416 }, // -110
> +    { 0x884134fe908658b2, 0x3109058d147fdcde }, // -109
> +    { 0xda01ee641a708de9, 0xe80e6f4820cc9496 }, // -108
> +    { 0xae67f1e9aec07187, 0xecd8590680a3aa12 }, // -107
> +    { 0x8b865b215899f46c, 0xbd79e0d20082ee75 }, // -106
> +    { 0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee }, // -105
> +    { 0xb2977ee300c50fe7, 0x58edec91ec2cb658 }, // -104
> +    { 0x8edf98b59a373fec, 0x4724bd4189bd5ead }, // -103
> +    { 0xe498f455c38b997a, 0x0b6dfb9c0f956448 }, // -102
> +    { 0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d }, // -101
> +    { 0x924d692ca61be758, 0x593c2626705f9c57 }, // -100
> +    { 0xea1575143cf97226, 0xf52d09d71a3293be }, // -99
> +    { 0xbb445da9ca61281f, 0x2a8a6e45ae8edc98 }, // -98
> +    { 0x95d04aee3b80ece5, 0xbba1f1d158724a13 }, // -97
> +    { 0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f }, // -96
> +    { 0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f }, // -95
> +    { 0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc }, // -94
> +    { 0xf5746577930d6500, 0xca8f44ec7ee3647a }, // -93
> +    { 0xc45d1df942711d9a, 0x3ba5d0bd324f8395 }, // -92
> +    { 0x9d174b2dcec0e47b, 0x62eb0d64283f9c77 }, // -91
> +    { 0xfb5878494ace3a5f, 0x04ab48a04065c724 }, // -90
> +    { 0xc913936dd571c84c, 0x03bc3a19cd1e38ea }, // -89
> +    { 0xa0dc75f1778e39d6, 0x696361ae3db1c722 }, // -88
> +    { 0x80b05e5ac60b6178, 0x544f8158315b05b5 }, // -87
> +    { 0xcde6fd5e09abcf26, 0xed4c0226b55e6f87 }, // -86
> +    { 0xa4b8cab1a1563f52, 0x577001b891185939 }, // -85
> +    { 0x83c7088e1aab65db, 0x792667c6da79e0fb }, // -84
> +    { 0xd2d80db02aabd62b, 0xf50a3fa490c30191 }, // -83
> +    { 0xa8acd7c0222311bc, 0xc40832ea0d68ce0d }, // -82
> +    { 0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4 }, // -81
> +    { 0xd7e77a8f87daf7fb, 0xdc33745ec97be907 }, // -80
> +    { 0xacb92ed9397bf996, 0x49c2c37f07965405 }, // -79
> +    { 0x8a2dbf142dfcc7ab, 0x6e3569326c784338 }, // -78
> +    { 0xdd15fe86affad912, 0x49ef0eb713f39ebf }, // -77
> +    { 0xb0de65388cc8ada8, 0x3b25a55f43294bcc }, // -76
> +    { 0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3 }, // -75
> +    { 0xe264589a4dcdab14, 0xc696963c7eed2dd2 }, // -74
> +    { 0xb51d13aea4a488dd, 0x6babab6398bdbe42 }, // -73
> +    { 0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce }, // -72
> +    { 0xe7d34c64a9c85d44, 0x60dbbca87196b617 }, // -71
> +    { 0xb975d6b6ee39e436, 0xb3e2fd538e122b45 }, // -70
> +    { 0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b }, // -69
> +    { 0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde }, // -68
> +    { 0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318 }, // -67
> +    { 0x97edd871cfda3a56, 0x97758bf0e3cbb5ad }, // -66
> +    { 0xf316271c7fc3908a, 0x8bef464e3945ef7b }, // -65
> +    { 0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc }, // -64
> +    { 0x9b934c3b330c8577, 0x63cc55f49f88eb30 }, // -63
> +    { 0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3 }, // -62
> +    { 0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6 }, // -61
> +    { 0x9f4f2726179a2245, 0x01d762422c946591 }, // -60
> +    { 0xfee50b7025c36a08, 0x02f236d04753d5b5 }, // -59
> +    { 0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491 }, // -58
> +    { 0xa321f2d7226895c7, 0xaff72d52192b6a0e }, // -57
> +    { 0x82818f1281ed449f, 0xbff8f10e7a8921a5 }, // -56
> +    { 0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6e }, // -55
> +    { 0xa70c3c40a64e6c51, 0x999090b65f67d925 }, // -54
> +    { 0x85a36366eb71f041, 0x47a6da2b7f864751 }, // -53
> +    { 0xd5d238a4abe98068, 0x72a4904598d6d881 }, // -52
> +    { 0xab0e93b6efee0053, 0x8eea0d047a457a01 }, // -51
> +    { 0x88d8762bf324cd0f, 0xa5880a69fb6ac801 }, // -50
> +    { 0xdaf3f04651d47b4c, 0x3c0cdd765f114001 }, // -49
> +    { 0xaf298d050e4395d6, 0x9670b12b7f410001 }, // -48
> +    { 0x8c213d9da502de45, 0x4526f422cc340001 }, // -47
> +    { 0xe0352f62a19e306e, 0xd50b2037ad200001 }, // -46
> +    { 0xb35dbf821ae4f38b, 0xdda2802c8a800001 }, // -45
> +    { 0x8f7e32ce7bea5c6f, 0xe4820023a2000001 }, // -44
> +    { 0xe596b7b0c643c719, 0x6d9ccd05d0000001 }, // -43
> +    { 0xb7abc627050305ad, 0xf14a3d9e40000001 }, // -42
> +    { 0x92efd1b8d0cf37be, 0x5aa1cae500000001 }, // -41
> +    { 0xeb194f8e1ae525fd, 0x5dcfab0800000001 }, // -40
> +    { 0xbc143fa4e250eb31, 0x17d955a000000001 }, // -39
> +    { 0x96769950b50d88f4, 0x1314448000000001 }, // -38
> +    { 0xf0bdc21abb48db20, 0x1e86d40000000001 }, // -37
> +    { 0xc097ce7bc90715b3, 0x4b9f100000000001 }, // -36
> +    { 0x9a130b963a6c115c, 0x3c7f400000000001 }, // -35
> +    { 0xf684df56c3e01bc6, 0xc732000000000001 }, // -34
> +    { 0xc5371912364ce305, 0x6c28000000000001 }, // -33
> +    { 0x9dc5ada82b70b59d, 0xf020000000000001 }, // -32
> +    { 0xfc6f7c4045812296, 0x4d00000000000001 }, // -31
> +    { 0xc9f2c9cd04674ede, 0xa400000000000001 }, // -30
> +    { 0xa18f07d736b90be5, 0x5000000000000001 }, // -29
> +    { 0x813f3978f8940984, 0x4000000000000001 }, // -28
> +    { 0xcecb8f27f4200f3a, 0x0000000000000001 }, // -27
> +    { 0xa56fa5b99019a5c8, 0x0000000000000001 }, // -26
> +    { 0x84595161401484a0, 0x0000000000000001 }, // -25
> +    { 0xd3c21bcecceda100, 0x0000000000000001 }, // -24
> +    { 0xa968163f0a57b400, 0x0000000000000001 }, // -23
> +    { 0x878678326eac9000, 0x0000000000000001 }, // -22
> +    { 0xd8d726b7177a8000, 0x0000000000000001 }, // -21
> +    { 0xad78ebc5ac620000, 0x0000000000000001 }, // -20
> +    { 0x8ac7230489e80000, 0x0000000000000001 }, // -19
> +    { 0xde0b6b3a76400000, 0x0000000000000001 }, // -18
> +    { 0xb1a2bc2ec5000000, 0x0000000000000001 }, // -17
> +    { 0x8e1bc9bf04000000, 0x0000000000000001 }, // -16
> +    { 0xe35fa931a0000000, 0x0000000000000001 }, // -15
> +    { 0xb5e620f480000000, 0x0000000000000001 }, // -14
> +    { 0x9184e72a00000000, 0x0000000000000001 }, // -13
> +    { 0xe8d4a51000000000, 0x0000000000000001 }, // -12
> +    { 0xba43b74000000000, 0x0000000000000001 }, // -11
> +    { 0x9502f90000000000, 0x0000000000000001 }, // -10
> +    { 0xee6b280000000000, 0x0000000000000001 }, // -9
> +    { 0xbebc200000000000, 0x0000000000000001 }, // -8
> +    { 0x9896800000000000, 0x0000000000000001 }, // -7
> +    { 0xf424000000000000, 0x0000000000000001 }, // -6
> +    { 0xc350000000000000, 0x0000000000000001 }, // -5
> +    { 0x9c40000000000000, 0x0000000000000001 }, // -4
> +    { 0xfa00000000000000, 0x0000000000000001 }, // -3
> +    { 0xc800000000000000, 0x0000000000000001 }, // -2
> +    { 0xa000000000000000, 0x0000000000000001 }, // -1
> +    { 0x8000000000000000, 0x0000000000000001 }, // 0
> +    { 0xcccccccccccccccc, 0xcccccccccccccccd }, // 1
> +    { 0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4 }, // 2
> +    { 0x83126e978d4fdf3b, 0x645a1cac083126ea }, // 3
> +    { 0xd1b71758e219652b, 0xd3c36113404ea4a9 }, // 4
> +    { 0xa7c5ac471b478423, 0x0fcf80dc33721d54 }, // 5
> +    { 0x8637bd05af6c69b5, 0xa63f9a49c2c1b110 }, // 6
> +    { 0xd6bf94d5e57a42bc, 0x3d32907604691b4d }, // 7
> +    { 0xabcc77118461cefc, 0xfdc20d2b36ba7c3e }, // 8
> +    { 0x89705f4136b4a597, 0x31680a88f8953031 }, // 9
> +    { 0xdbe6fecebdedd5be, 0xb573440e5a884d1c }, // 10
> +    { 0xafebff0bcb24aafe, 0xf78f69a51539d749 }, // 11
> +    { 0x8cbccc096f5088cb, 0xf93f87b7442e45d4 }, // 12
> +    { 0xe12e13424bb40e13, 0x2865a5f206b06fba }, // 13
> +    { 0xb424dc35095cd80f, 0x538484c19ef38c95 }, // 14
> +    { 0x901d7cf73ab0acd9, 0x0f9d37014bf60a11 }, // 15
> +    { 0xe69594bec44de15b, 0x4c2ebe687989a9b4 }, // 16
> +    { 0xb877aa3236a4b449, 0x09befeb9fad487c3 }, // 17
> +    { 0x9392ee8e921d5d07, 0x3aff322e62439fd0 }, // 18
> +    { 0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6 }, // 19
> +    { 0xbce5086492111aea, 0x88f4bb1ca6bcf585 }, // 20
> +    { 0x971da05074da7bee, 0xd3f6fc16ebca5e04 }, // 21
> +    { 0xf1c90080baf72cb1, 0x5324c68b12dd6339 }, // 22
> +    { 0xc16d9a0095928a27, 0x75b7053c0f178294 }, // 23
> +    { 0x9abe14cd44753b52, 0xc4926a9672793543 }, // 24
> +    { 0xf79687aed3eec551, 0x3a83ddbd83f52205 }, // 25
> +    { 0xc612062576589dda, 0x95364afe032a819e }, // 26
> +    { 0x9e74d1b791e07e48, 0x775ea264cf55347e }, // 27
> +    { 0xfd87b5f28300ca0d, 0x8bca9d6e188853fd }, // 28
> +    { 0xcad2f7f5359a3b3e, 0x096ee45813a04331 }, // 29
> +    { 0xa2425ff75e14fc31, 0xa1258379a94d028e }, // 30
> +    { 0x81ceb32c4b43fcf4, 0x80eacf948770ced8 }, // 31
> +    { 0xcfb11ead453994ba, 0x67de18eda5814af3 }, // 32
> +    { 0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f }, // 33
> +    { 0x84ec3c97da624ab4, 0xbd5af13bef0b113f }, // 34
> +    { 0xd4ad2dbfc3d07787, 0x955e4ec64b44e865 }, // 35
> +    { 0xaa242499697392d2, 0xdde50bd1d5d0b9ea }, // 36
> +    { 0x881cea14545c7575, 0x7e50d64177da2e55 }, // 37
> +    { 0xd9c7dced53c72255, 0x96e7bd358c904a22 }, // 38
> +    { 0xae397d8aa96c1b77, 0xabec975e0a0d081b }, // 39
> +    { 0x8b61313bbabce2c6, 0x2323ac4b3b3da016 }, // 40
> +    { 0xdf01e85f912e37a3, 0x6b6c46dec52f6689 }, // 41
> +    { 0xb267ed1940f1c61c, 0x55f038b237591ed4 }, // 42
> +    { 0x8eb98a7a9a5b04e3, 0x77f3608e92adb243 }, // 43
> +    { 0xe45c10c42a2b3b05, 0x8cb89a7db77c506b }, // 44
> +    { 0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23 }, // 45
> +    { 0x9226712162ab070d, 0xcab3961304ca70e9 }, // 46
> +    { 0xe9d71b689dde71af, 0xaab8f01e6e10b4a7 }, // 47
> +    { 0xbb127c53b17ec159, 0x5560c018580d5d53 }, // 48
> +    { 0x95a8637627989aad, 0xdde7001379a44aa9 }, // 49
> +    { 0xef73d256a5c0f77c, 0x963e66858f6d4441 }, // 50
> +    { 0xbf8fdb78849a5f96, 0xde98520472bdd034 }, // 51
> +    { 0x993fe2c6d07b7fab, 0xe546a8038efe402a }, // 52
> +    { 0xf53304714d9265df, 0xd53dd99f4b3066a9 }, // 53
> +    { 0xc428d05aa4751e4c, 0xaa97e14c3c26b887 }, // 54
> +    { 0x9ced737bb6c4183d, 0x55464dd69685606c }, // 55
> +    { 0xfb158592be068d2e, 0xeed6e2f0f0d56713 }, // 56
> +    { 0xc8de047564d20a8b, 0xf245825a5a445276 }, // 57
> +    { 0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5 }, // 58
> +    { 0x808e17555f3ebf11, 0xe2bbd88bbee40bd1 }, // 59
> +    { 0xcdb02555653131b6, 0x3792f412cb06794e }, // 60
> +    { 0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8 }, // 61
> +    { 0x83a3eeeef9153e89, 0x1953cf68300424ad }, // 62
> +    { 0xd29fe4b18e88640e, 0x8eec7f0d19a03aae }, // 63
> +    { 0xa87fea27a539e9a5, 0x3f2398d747b36225 }, // 64
> +    { 0x86ccbb52ea94baea, 0x98e947129fc2b4ea }, // 65
> +    { 0xd7adf884aa879177, 0x5b0ed81dcc6abb10 }, // 66
> +    { 0xac8b2d36eed2dac5, 0xe272467e3d222f40 }, // 67
> +    { 0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900 }, // 68
> +    { 0xdcdb1b2798182244, 0xf8e431456cf88e66 }, // 69
> +    { 0xb0af48ec79ace837, 0x2d835a9df0c6d852 }, // 70
> +    { 0x8d590723948a535f, 0x579c487e5a38ad0f }, // 71
> +    { 0xe2280b6c20dd5232, 0x25c6da63c38de1b1 }, // 72
> +    { 0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4 }, // 73
> +    { 0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3 }, // 74
> +    { 0xe7958cb87392c2c2, 0xb60b1d1230b20e05 }, // 75
> +    { 0xb94470938fa89bce, 0xf808e40e8d5b3e6a }, // 76
> +    { 0x9436c0760c86e30b, 0xf9a0b6720aaf6522 }, // 77
> +    { 0xed246723473e3813, 0x290123e9aab23b69 }, // 78
> +    { 0xbdb6b8e905cb600f, 0x5400e987bbc1c921 }, // 79
> +    { 0x97c560ba6b0919a5, 0xdccd879fc967d41b }, // 80
> +    { 0xf2d56790ab41c2a2, 0xfae27299423fb9c4 }, // 81
> +    { 0xc24452da229b021b, 0xfbe85badce996169 }, // 82
> +    { 0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb }, // 83
> +    { 0xf8a95fcf88747d94, 0x75a44c6397ce912b }, // 84
> +    { 0xc6ede63fa05d3143, 0x91503d1c79720dbc }, // 85
> +    { 0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca }, // 86
> +    { 0xfea126b7d78186bc, 0xe2f610c84987bfa9 }, // 87
> +    { 0xcbb41ef979346bca, 0x4f2b40a03ad2ffba }, // 88
> +    { 0xa2f67f2dfa90563b, 0x728900802f0f32fb }, // 89
> +    { 0x825ecc24c873782f, 0x8ed400668c0c28c9 }, // 90
> +    { 0xd097ad07a71f26b2, 0x7e2000a41346a7a8 }, // 91
> +    { 0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953 }, // 92
> +    { 0x857fcae62d8493a5, 0x6f70a4400c562ddc }, // 93
> +    { 0xd59944a37c0752a2, 0x4be76d3346f04960 }, // 94
> +    { 0xaae103b5fcd2a881, 0xd652bdc29f26a11a }, // 95
> +    { 0x88b402f7fd75539b, 0x11dbcb0218ebb415 }, // 96
> +    { 0xdab99e59958885c4, 0xe95fab368e45ecee }, // 97
> +    { 0xaefae51477a06b03, 0xede622920b6b23f2 }, // 98
> +    { 0x8bfbea76c619ef36, 0x57eb4edb3c55b65b }, // 99
> +    { 0xdff9772470297ebd, 0x59787e2b93bc56f8 }, // 100
> +    { 0xb32df8e9f3546564, 0x47939822dc96abfa }, // 101
> +    { 0x8f57fa54c2a9eab6, 0x9fa946824a12232e }, // 102
> +    { 0xe55990879ddcaabd, 0xcc420a6a101d0516 }, // 103
> +    { 0xb77ada0617e3bbcb, 0x09ce6ebb40173745 }, // 104
> +    { 0x92c8ae6b464fc96f, 0x3b0b8bc90012929e }, // 105
> +    { 0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f }, // 106
> +    { 0xbbe226efb628afea, 0x890489f70a55368c }, // 107
> +    { 0x964e858c91ba2655, 0x3a6a07f8d510f870 }, // 108
> +    { 0xf07da27a82c37088, 0x5d767327bb4e5a4d }, // 109
> +    { 0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7 }, // 110
> +    { 0x99ea0196163fa42e, 0x504bced1bf8e4e46 }, // 111
> +    { 0xf64335bcf065d37d, 0x4d4617b5ff4a16d6 }, // 112
> +    { 0xc5029163f384a931, 0x0a9e795e65d4df12 }, // 113
> +    { 0x9d9ba7832936edc0, 0xd54b944b84aa4c0e }, // 114
> +    { 0xfc2c3f3841f17c67, 0xbbac2078d443ace3 }, // 115
> +    { 0xc9bcff6034c13052, 0xfc89b393dd02f0b6 }, // 116
> +    { 0xa163ff802a3426a8, 0xca07c2dcb0cf26f8 }, // 117
> +    { 0x811ccc668829b887, 0x0806357d5a3f5260 }, // 118
> +    { 0xce947a3da6a9273e, 0x733d226229feea33 }, // 119
> +    { 0xa54394fe1eedb8fe, 0xc2974eb4ee658829 }, // 120
> +    { 0x843610cb4bf160cb, 0xcedf722a585139bb }, // 121
> +    { 0xd389b47879823479, 0x4aff1d108d4ec2c4 }, // 122
> +    { 0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0 }, // 123
> +    { 0x87625f056c7c4a8b, 0x11471cd764ad4973 }, // 124
> +    { 0xd89d64d57a607744, 0xe871c7bf077ba8b8 }, // 125
> +    { 0xad4ab7112eb3929d, 0x86c16c98d2c953c7 }, // 126
> +    { 0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c }, // 127
> +    { 0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf }, // 128
> +    { 0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3 }, // 129
> +    { 0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2 }, // 130
> +    { 0xe3231912d5bf60e6, 0x10e1fff697ed6c6a }, // 131
> +    { 0xb5b5ada8aaff80b8, 0x0d819992132456bb }, // 132
> +    { 0x915e2486ef32cd60, 0x0ace1474dc1d122f }, // 133
> +    { 0xe896a0d7e51e1566, 0x77b020baf9c81d18 }, // 134
> +    { 0xba121a4650e4ddeb, 0x92f34d62616ce414 }, // 135
> +    { 0x94db483840b717ef, 0xa8c2a44eb4571cdd }, // 136
> +    { 0xee2ba6c0678b597f, 0x746aa07ded582e2d }, // 137
> +    { 0xbe89523386091465, 0xf6bbb397f1135824 }, // 138
> +    { 0x986ddb5c6b3a76b7, 0xf89629465a75e01d }, // 139
> +    { 0xf3e2f893dec3f126, 0x5a89dba3c3efccfb }, // 140
> +    { 0xc31bfa0fe5698db8, 0x486e494fcff30a63 }, // 141
> +    { 0x9c1661a651213e2d, 0x06bea10ca65c084f }, // 142
> +    { 0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1 }, // 143
> +    { 0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1 }, // 144
> +    { 0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634 }, // 145
> +    { 0xffbbcfe994e5c61f, 0xfdf17746497f7053 }, // 146
> +    { 0xcc963fee10b7d1b3, 0x318df905079926a9 }, // 147
> +    { 0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb }, // 148
> +    { 0x82ef85133de648c4, 0x9a984d73dbe722fc }, // 149
> +    { 0xd17f3b51fca3a7a0, 0xf75a15862ca504c6 }, // 150
> +    { 0xa798fc4196e952e7, 0x2c48113823b73705 }, // 151
> +    { 0x8613fd0145877585, 0xbd06742ce95f5f37 }, // 152
> +    { 0xd686619ba27255a2, 0xc80a537b0efefebe }, // 153
> +    { 0xab9eb47c81f5114f, 0x066ea92f3f326565 }, // 154
> +    { 0x894bc396ce5da772, 0x6b8bba8c328eb784 }, // 155
> +    { 0xdbac6c247d62a583, 0xdf45f746b74abf3a }, // 156
> +    { 0xafbd2350644eeacf, 0xe5d1929ef90898fb }, // 157
> +    { 0x8c974f7383725573, 0x1e414218c73a13fc }, // 158
> +    { 0xe0f218b8d25088b8, 0x306869c13ec3532d }, // 159
> +    { 0xb3f4e093db73a093, 0x59ed216765690f57 }, // 160
> +    { 0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac }, // 161
> +    { 0xe65829b3046b0afa, 0x0cb4a5a3112a5113 }, // 162
> +    { 0xb84687c269ef3bfb, 0x3d5d514f40eea743 }, // 163
> +    { 0x936b9fcebb25c995, 0xcab10dd900beec35 }, // 164
> +    { 0xebdf661791d60f56, 0x111b495b3464ad22 }, // 165
> +    { 0xbcb2b812db11a5de, 0x7415d448f6b6f0e8 }, // 166
> +    { 0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba }, // 167
> +    { 0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2 }, // 168
> +    { 0xc13a148e3032d6e7, 0xe36a52363c1faf02 }, // 169
> +    { 0x9a94dd3e8cf578b9, 0x82bb74f8301958cf }, // 170
> +    { 0xf7549530e188c128, 0xd12bee59e68ef47d }, // 171
> +    { 0xc5dd44271ad3cdba, 0x40eff1e1853f29fe }, // 172
> +    { 0x9e4a9cec15763e2e, 0x9a598e4e043287ff }, // 173
> +    { 0xfd442e4688bd304a, 0x908f4a166d1da664 }, // 174
> +    { 0xca9cf1d206fdc03b, 0xa6d90811f0e4851d }, // 175
> +    { 0xa21727db38cb002f, 0xb8ada00e5a506a7d }, // 176
> +    { 0x81ac1fe293d599bf, 0xc6f14cd848405531 }, // 177
> +    { 0xcf79cc9db955c2cc, 0x7182148d4066eeb5 }, // 178
> +    { 0xa5fb0a17c777cf09, 0xf468107100525891 }, // 179
> +    { 0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074 }, // 180
> +    { 0xd47487cc8470652b, 0x7647c32000696720 }, // 181
> +    { 0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d }, // 182
> +    { 0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7 }, // 183
> +    { 0xd98ddaee19068c76, 0x3badd624dd9b0958 }, // 184
> +    { 0xae0b158b4738705e, 0x9624ab50b148d446 }, // 185
> +    { 0x8b3c113c38f9f37e, 0xde83bc408dd3dd05 }, // 186
> +    { 0xdec681f9f4c31f31, 0x6405fa00e2ec94d5 }, // 187
> +    { 0xb23867fb2a35b28d, 0xe99e619a4f23aa44 }, // 188
> +    { 0x8e938662882af53e, 0x547eb47b7282ee9d }, // 189
> +    { 0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94 }, // 190
> +    { 0xb67f6455292cbf08, 0x1a3bc84c17b1d543 }, // 191
> +    { 0x91ff83775423cc06, 0x7b6306a34627ddd0 }, // 192
> +    { 0xe998d258869facd7, 0x2bd1a438703fc94c }, // 193
> +    { 0xbae0a846d2195712, 0x8974836059cca10a }, // 194
> +    { 0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1 }, // 195
> +    { 0xef340a98172aace4, 0x86fb897116c87c35 }, // 196
> +    { 0xbf5cd54678eef0b6, 0xd262d45a78a0635e }, // 197
> +    { 0x991711052d8bf3c5, 0x751bdd152d4d1c4b }, // 198
> +    { 0xf4f1b4d515acb93b, 0xee92fb5515482d45 }, // 199
> +    { 0xc3f490aa77bd60fc, 0xbedbfc4411068a9d }, // 200
> +    { 0x9cc3a6eec6311a63, 0xcbe3303674053bb1 }, // 201
> +    { 0xfad2a4b13d1b5d6c, 0x796b805720085f82 }, // 202
> +    { 0xc8a883c0fdaf7df0, 0x6122cd128006b2ce }, // 203
> +    { 0xa086cfcd97bf97f3, 0x80e8a40eccd228a5 }, // 204
> +    { 0x806bd9714632dff6, 0x00ba1cd8a3db53b7 }, // 205
> +    { 0xcd795be870516656, 0x67902e276c921f8c }, // 206
> +    { 0xa46116538d0deb78, 0x52d9be85f074e609 }, // 207
> +    { 0x8380dea93da4bc60, 0x4247cb9e59f71e6e }, // 208
> +    { 0xd267caa862a12d66, 0xd072df63c324fd7c }, // 209
> +    { 0xa8530886b54dbdeb, 0xd9f57f830283fdfd }, // 210
> +    { 0x86a8d39ef77164bc, 0xae5dff9c02033198 }, // 211
> +    { 0xd77485cb25823ac7, 0x7d633293366b828c }, // 212
> +    { 0xac5d37d5b79b6239, 0x311c2875c522ced6 }, // 213
> +    { 0x89e42caaf9491b60, 0xf41686c49db57245 }, // 214
> +    { 0xdca04777f541c567, 0xecf0d7a0fc5583a1 }, // 215
> +    { 0xb080392cc4349dec, 0xbd8d794d96aacfb4 }, // 216
> +    { 0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d }, // 217
> +    { 0xe1ebce4dc7f16dfb, 0xd3e8495912c62895 }, // 218
> +    { 0xb4bca50b065abe63, 0x0fed077a756b53aa }, // 219
> +    { 0x9096ea6f3848984f, 0x3ff0d2c85def7622 }, // 220
> +    { 0xe757dd7ec07426e5, 0x331aeada2fe589d0 }, // 221
> +    { 0xb913179899f68584, 0x28e2557b59846e40 }, // 222
> +    { 0x940f4613ae5ed136, 0x871b7795e136be9a }, // 223
> +    { 0xece53cec4a314ebd, 0xa4f8bf5635246429 }, // 224
> +    { 0xbd8430bd08277231, 0x50c6ff782a838354 }, // 225
> +    { 0x979cf3ca6cec5b5a, 0xa705992ceecf9c43 }, // 226
> +    { 0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e }, // 227
> +    { 0xc21094364dfb5636, 0x985915fc12f542e5 }, // 228
> +    { 0x9b407691d7fc44f8, 0x79e0de63425dcf1e }, // 229
> +    { 0xf867241c8cc6d4c0, 0xc30163d203c94b63 }, // 230
> +    { 0xc6b8e9b0709f109a, 0x359ab6419ca1091c }, // 231
> +    { 0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0 }, // 232
> +    { 0xfe5d54150b090b02, 0xd3f93b35435d7c4d }, // 233
> +    { 0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a }, // 234
> +    { 0xa2cb1717b52481ed, 0x54768c4b0c64ca6f }, // 235
> +    { 0x823c12795db6ce57, 0x76c53d08d6b70859 }, // 236
> +    { 0xd0601d8efc57b08b, 0xf13b94daf124da27 }, // 237
> +    { 0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f }, // 238
> +    { 0x855c3be0a17fcd26, 0x5cf2eea09a550680 }, // 239
> +    { 0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65 }, // 240
> +    { 0xaab37fd7d8f58178, 0xc8e5087ba6d33b84 }, // 241
> +    { 0x888f99797a5e012d, 0x6d8406c952429604 }, // 242
> +    { 0xda7f5bf590966848, 0xaf39a475506a899f }, // 243
> +    { 0xaecc49914078536d, 0x58fae9f773886e19 }, // 244
> +    { 0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1 }, // 245
> +    { 0xdfbdcece67006ac9, 0x67a791e093e1d49b }, // 246
> +    { 0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16 }, // 247
> +    { 0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811 }, // 248
> +    { 0xe51c79a85916f484, 0x82b7e12780e7401b }, // 249
> +    { 0xb749faed14125d36, 0xcef980ec671f667c }, // 250
> +    { 0x92a1958a7675175f, 0x0bfacd89ec191eca }, // 251
> +    { 0xea9c227723ee8bcb, 0x465e15a979c1cadd }, // 252
> +    { 0xbbb01b9283253ca2, 0x9eb1aaedfb016f17 }, // 253
> +    { 0x96267c7535b763b5, 0x4bc1558b2f3458df }, // 254
> +    { 0xf03d93eebc589f88, 0x793555ab7eba27cb }, // 255
> +    { 0xc0314325637a1939, 0xfa911155fefb5309 }, // 256
> +    { 0x99c102844f94e0fb, 0x2eda7444cbfc426e }, // 257
> +    { 0xf6019da07f549b2b, 0x7e2a53a146606a49 }, // 258
> +    { 0xc4ce17b399107c22, 0xcb550fb4384d21d4 }, // 259
> +    { 0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa }, // 260
> +    { 0xfbe9141915d7a922, 0x4bf1ff9f0062baa9 }, // 261
> +    { 0xc987434744ac874e, 0xa327ffb266b56221 }, // 262
> +    { 0xa139029f6a239f72, 0x1c1fffc1ebc44e81 }, // 263
> +    { 0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a }, // 264
> +    { 0xce5d73ff402d98e3, 0xfb0a3d212dc81290 }, // 265
> +    { 0xa5178fff668ae0b6, 0x626e974dbe39a873 }, // 266
> +    { 0x8412d9991ed58091, 0xe858790afe9486c3 }, // 267
> +    { 0xd3515c2831559a83, 0x0d5a5b44ca873e04 }, // 268
> +    { 0xa90de3535aaae202, 0x711515d0a205cb37 }, // 269
> +    { 0x873e4f75e2224e68, 0x5a7744a6e804a292 }, // 270
> +    { 0xd863b256369d4a40, 0x90bed43e40076a83 }, // 271
> +    { 0xad1c8eab5ee43b66, 0xda3243650005eed0 }, // 272
> +    { 0x8a7d3eef7f1cfc52, 0x482835ea666b2573 }, // 273
> +    { 0xdd95317f31c7fa1d, 0x40405643d711d584 }, // 274
> +    { 0xb1442798f49ffb4a, 0x99cd11cfdf41779d }, // 275
> +    { 0x8dd01fad907ffc3b, 0xae3da7d97f6792e4 }, // 276
> +    { 0xe2e69915b3fff9f9, 0x16c90c8f323f516d }, // 277
> +    { 0xb58547448ffffb2d, 0xabd40a0c2832a78b }, // 278
> +    { 0x91376c36d99995be, 0x23100809b9c21fa2 }, // 279
> +    { 0xe858ad248f5c22c9, 0xd1b3400f8f9cff69 }, // 280
> +    { 0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54 }, // 281
> +    { 0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa }, // 282
> +    { 0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9 }, // 283
> +    { 0xbe5691ef416bd60c, 0x23cc986bc656d554 }, // 284
> +    { 0x9845418c345644d6, 0x830a13896b78aaaa }, // 285
> +    { 0xf3a20279ed56d48a, 0x6b43527578c11110 }, // 286
> +    { 0xc2e801fb244576d5, 0x229c41f793cda740 }, // 287
> +    { 0x9becce62836ac577, 0x4ee367f9430aec33 }, // 288
> +    { 0xf97ae3d0d2446f25, 0x4b0573286b44ad1e }, // 289
> +    { 0xc795830d75038c1d, 0xd59df5b9ef6a2418 }, // 290
> +    { 0x9faacf3df73609b1, 0x77b191618c54e9ad }, // 291
> +    { 0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b }, // 292
> +  };
> +};
> +
> +template <typename>
> +struct minverse;
> +
> +// Taken from: https://github.com/cassioneri/teju_jagua.
> +template <>
> +struct minverse<uint32_t> {
> +  static struct {
> +    const uint32_t multiplier;
> +    const uint32_t bound;
> +  } constexpr data[] =
> +  {
> +    { 0x00000001, 0xffffffff },
> +    { 0xcccccccd, 0x33333333 },
> +    { 0xc28f5c29, 0x0a3d70a3 },
> +    { 0x26e978d5, 0x020c49ba },
> +    { 0x3afb7e91, 0x0068db8b },
> +    { 0x0bcbe61d, 0x0014f8b5 },
> +    { 0x68c26139, 0x000431bd },
> +    { 0xae8d46a5, 0x0000d6bf },
> +    { 0x22e90e21, 0x00002af3 },
> +    { 0x3a2e9c6d, 0x00000897 },
> +    { 0x3ed61f49, 0x000001b7 },
> +    { 0x0c913975, 0x00000057 },
> +    { 0xcf503eb1, 0x00000011 },
> +    { 0xf6433fbd, 0x00000003 },
> +  };
> +};
> +
> +} // namespace <anonymous>
> +
> +#endif // _GLIBCXX_FLOATING_TO_CHARS_TABLES_H
> --
> 2.43.0
> 
>
diff mbox series

Patch

diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc b/libstdc++-v3/src/c++17/floating_to_chars.cc
index 2c9da977cd9..b6adbf9cf5f 100644
--- a/libstdc++-v3/src/c++17/floating_to_chars.cc
+++ b/libstdc++-v3/src/c++17/floating_to_chars.cc
@@ -96,6 +96,8 @@  using F128_type = void;

 #include <stdint.h>

+#include "floating_to_chars_tables.h"
+
 namespace
 {
 #if defined __SIZEOF_INT128__
@@ -132,6 +134,26 @@  namespace
     { return generic128::generic_to_chars(v, result); }
   } // namespace ryu

+  // Binary or decimal field representation of a positive floating-point number.
+  // The base is implicitly given by the context and the represented number is:
+  //   mantissa * base ^ exponent.
+  template <typename Mantissa>
+  struct fields {
+    Mantissa mantissa;
+    int32_t  exponent;
+  };
+
+  // Binary or decimal field representation of a floating-point number.
+  // The base is implicitly given by the context and the represented number is:
+  //   (sign ? -1 : 1) * mantissa * base ^ exponent.
+  template <typename Mantissa>
+  struct signed_fields;
+
+  // TODO (CN): Remove.
+  template <>
+    struct signed_fields<uint32_t> : ryu::floating_decimal_32
+    { };
+
   // A traits class that contains pertinent information about the binary
   // format of each of the floating-point types we support.
   template<typename T>
@@ -149,6 +171,12 @@  namespace

       static constexpr uint64_t pow10_adjustment_tab[]
 	= { 0b0000000000011101011100110101100101101110000000000000000000000000 };
+
+      using fields_t = signed_fields<mantissa_t>;
+
+      static constexpr uint32_t mantissa_size    =   23;
+      static constexpr uint32_t exponent_size    =    8;
+      static constexpr int32_t  exponent_minimum = -149;
     };

   template<>
@@ -430,6 +458,276 @@  namespace
       bool sign;
     };

+  // Return 2^k.
+  template <typename T>
+    constexpr T
+    pow2(const uint32_t k)
+    {
+      return T(1) << k;
+    }
+
+  // Return the k least significant bits of n (i.e., e % 2^k.)
+  template <typename T>
+    T
+    lsb(const T n, const uint32_t k)
+    {
+      return n % pow2<T>(k);
+    }
+
+  // Return the binary field representation of an IEEE Float value.
+  template <typename Float, typename Traits = floating_type_traits<Float>>
+    typename Traits::fields_t
+    to_binary_ieee(const Float value)
+    {
+      using mantissa_t = typename Traits::mantissa_t;
+
+      mantissa_t bits;
+      memcpy(&bits, &value, sizeof(value));
+
+      const mantissa_t mantissa_bits = lsb(bits, Traits::mantissa_size);
+      bits >>= Traits::mantissa_size;
+
+      const int32_t exponent_bits = lsb(bits, Traits::exponent_size);
+      bits >>= Traits::exponent_size;
+
+      const bool negative = bits != 0;
+
+      int32_t    exponent = int32_t(exponent_bits) + Traits::exponent_minimum;
+      mantissa_t mantissa = mantissa_bits;
+
+      if (exponent_bits != 0)
+      {
+	// Number is normal.
+	exponent -= 1;
+	mantissa += pow2<mantissa_t>(Traits::mantissa_size);
+      }
+
+      return { mantissa, exponent, negative } ;
+    }
+
+  // Return the binary field representation of a float value.
+  typename floating_type_traits<float>::fields_t
+  to_binary(const float value)
+  {
+    return to_binary_ieee(value);
+  }
+
+  // Check whether m is multiple of 2^k.
+  template <typename Mantissa>
+    bool
+    is_multiple_of_pow2(const Mantissa m, const uint32_t k)
+    {
+      return lsb(m, k) == 0;
+    }
+
+  // Check whether the binary field representation of a number is that of a
+  // small integer.
+  template <typename Traits, typename Mantissa = typename Traits::mantissa_t>
+    bool
+    is_small_integer(const Mantissa m, const int32_t e)
+    {
+      return -static_cast<int32_t>(Traits::mantissa_size) <= e && e <= 0 &&
+	is_multiple_of_pow2(m, -e);
+    }
+
+  // Return the quotient n / 10.
+  uint32_t
+  div10(const uint32_t n)
+  {
+    __glibcxx_assert(n < 1'073'741'829);
+    constexpr uint64_t M = 429'496'730; // M ~= 2^32 / 10.
+    return static_cast<uint32_t>(M * n >> 32);
+  }
+
+  // Return the largest exponent f such that 10^f <= 2^e, i.e., f is the integer
+  // part of e * log_10(2).
+  int32_t
+  log10_pow2(const int32_t e)
+  {
+    __glibcxx_assert(-112'815 <= e && e <= 112'815);
+    constexpr uint64_t M = 1'292'913'987; // M ~= 2^32 * log_10(2)
+    return static_cast<int32_t>(M * e >> 32);
+  }
+
+  // Return the residual r = e - e_0, where e_0 is the smallest exponent such
+  // that log10_pow2(e_0) = log10_pow2(e).
+  uint32_t
+  log10_pow2_residual(const int32_t e)
+  {
+    __glibcxx_assert(-112'815 <= e && e <= 112'815);
+    constexpr uint64_t M = 1'292'913'987;
+    return static_cast<uint32_t>(M * e) / M;
+  }
+
+  // Shorten the decimal field representation of a given number by removing
+  // mantissa's trailing zeros and increasing the exponent accordingly.
+  template <typename Mantissa>
+    fields<Mantissa>
+    remove_trailing_zeros(Mantissa m, int32_t e)
+    {
+      while (true)
+      {
+	const Mantissa q = div10(m);
+	if (m != 10 * q)
+	  return { m, e };
+	++e;
+	m = q;
+      }
+    }
+
+  // Return N * m / 2^64 (multiply and shift), where N is a 64-bits number split
+  // in two 32-bits parts.
+  uint32_t
+  mshift(const uint32_t m, const parts<uint32_t> N)
+  {
+    const uint64_t s0 = static_cast<uint64_t>(N.lower) * m;
+    const uint64_t s1 = static_cast<uint64_t>(N.upper) * m;
+    return (s1 + (s0 >> 32)) >> 32;
+  }
+
+  // Return N * 2^k / 2^64 (multiply and shift for power of 2), where N is a
+  // 64-bits number split in two 32-bits parts.
+  uint32_t
+  mshift_pow2(const uint32_t k, const parts<uint32_t> N)
+  {
+    const int32_t s = int32_t(k) - 32;
+    if (s <= 0)
+      return N.upper >> -s;
+    return (N.upper << s) | (N.lower >> (32 - s));
+  }
+
+  // Check whether m is multiple of 5^f.
+  // pre: 0 <= f && f < static_cast<int32_t>(size(minverse<Mantissa>::data))
+  template <typename Mantissa>
+    bool
+    is_multiple_of_pow5(const Mantissa m, const int32_t f)
+    {
+      const auto [multiplier, bound] = minverse<Mantissa>::data[f];
+      return m * multiplier <= bound;
+    }
+
+  // Check whether m, for m in { m_a, m_b, c_ 2 }, yields a tie.
+  template <typename Mantissa>
+    bool
+    is_tie(const Mantissa m, const int32_t f)
+    {
+      return 0 <= f
+	&& f < static_cast<int32_t>(std::size(minverse<Mantissa>::data))
+	&& is_multiple_of_pow5(m, f);
+    }
+
+  // Check whether the mantissa of an uncentred value (whose decimal exponent is
+  // f) yields a tie.
+  template <typename Traits>
+  bool
+  is_tie_uncentred(const int32_t f)
+  {
+    return f > 0 && Traits::mantissa_size % 4 == 2;
+  }
+
+  // Return the shortest decimal field representation of a positive
+  // floating-point number whose binary field representation is given.
+  // Implementation based on: https://github.com/cassioneri/teju_jagua.
+  template <typename Traits, typename Mantissa = typename Traits::mantissa_t>
+    fields<Mantissa>
+    teju_jagua(const fields<Mantissa> binary)
+    {
+      const auto [m , e] = binary;
+
+      if (is_small_integer<Traits>(m, e))
+	return remove_trailing_zeros(m >> -e, 0);
+
+      const int32_t  f = log10_pow2(e);
+      const uint32_t r = log10_pow2_residual(e);
+      const auto     N = to_chars_table::get_multiplier(Mantissa{}, f);
+
+      constexpr uint32_t mantissa_size = Traits::mantissa_size;
+      constexpr Mantissa m_0 = pow2<Mantissa>(mantissa_size);
+      if (m != m_0 || e == Traits::exponent_minimum)
+      {
+	const Mantissa m_a = (2 * m - 1) << r;
+	const Mantissa a   = mshift(m_a, N);
+	const Mantissa m_b = (2 * m + 1) << r;
+	const Mantissa b   = mshift(m_b, N);
+	const Mantissa q   = div10(b);
+	const Mantissa s   = 10 * q;
+
+	if (s >= a)
+	{
+	  if (s == b)
+	  {
+	    if (m % 2 == 0 || !is_tie(m_b, f))
+	      return remove_trailing_zeros(q, f + 1);
+	  }
+	  else if (s > a || (m % 2 == 0 && is_tie(m_a, f)))
+	    return remove_trailing_zeros(q, f + 1);
+	}
+
+	if ((a + b) % 2 == 1)
+	  return { (a + b) / 2 + 1, f };
+
+	const Mantissa m_c = (2 * 2 * m) << r;
+	const Mantissa c_2 = mshift(m_c, N);
+	const Mantissa c   = c_2 / 2;
+
+	if (c_2 % 2 == 0 || (c % 2 == 0 && is_tie(c_2, -f)))
+	  return { c, f };
+
+	return { c + 1, f };
+      }
+
+      const Mantissa m_b = 2 * m_0 + 1;
+      const Mantissa b   = mshift(m_b << r, N);
+
+      const Mantissa m_a = 4 * m_0 - 1;
+      const Mantissa a   = mshift(m_a << r, N) / 2;
+
+      if (b > a)
+      {
+	const Mantissa q = div10(b);
+	const Mantissa s = 10 * q;
+
+	if (s > a || (s == a && is_tie_uncentred<Traits>(f)))
+	  return remove_trailing_zeros(q, f + 1);
+
+	// m_c = 2 * 2 * m_0 = 2 * 2 * 2^{mantissa_size}
+	// c_2 = mshift(m_c << r, N);
+	const uint32_t log2_m_c = mantissa_size + 2;
+	const Mantissa c_2      = mshift_pow2(log2_m_c + r, N);
+	const Mantissa c	= c_2 / 2;
+
+	if (c == a && !is_tie_uncentred<Traits>(f))
+	  return { c + 1, f };
+
+	if (c_2 % 2 == 0 || (c % 2 == 0 && is_tie(c_2, -f)))
+	  return { c, f };
+
+	return { c + 1, f };
+      }
+
+      else if (is_tie_uncentred<Traits>(f))
+	return remove_trailing_zeros(a, f);
+
+      const Mantissa m_c = 10 * 2 * 2 * m_0;
+      const Mantissa c_2 = mshift(m_c << r, N);
+      const Mantissa c   = c_2 / 2;
+
+      if (c_2 % 2 == 0 || (c % 2 == 0 && is_tie(c_2, -f)))
+	return { c, f - 1 };
+
+      return { c + 1, f - 1 };
+    }
+
+  // Return the shortest decimal field representation of a Float value.
+  template <typename Float, typename Traits = floating_type_traits<Float>>
+    typename Traits::fields_t
+    teju_jagua(const Float value)
+    {
+      auto const [m, e, sign] = to_binary(value);
+      auto const abs = teju_jagua<Traits>({ m, e });
+      return { abs.mantissa, abs.exponent, sign };
+    }
+
   // Decompose the floating-point value into its IEEE components.
   template<typename T>
     ieee_t<T>
@@ -454,12 +752,12 @@  namespace

       ieee_t<T> ieee_repr;
       ieee_repr.mantissa
-	= static_cast<mantissa_t>(value_bits & ((uint_t{1} << mantissa_bits) - 1u));
+	= static_cast<mantissa_t>(lsb(value_bits, mantissa_bits));
       value_bits >>= mantissa_bits;
       ieee_repr.biased_exponent
-	= static_cast<uint32_t>(value_bits & ((uint_t{1} << exponent_bits) - 1u));
+	= static_cast<uint32_t>(lsb(value_bits, exponent_bits));
       value_bits >>= exponent_bits;
-      ieee_repr.sign = (value_bits & 1) != 0;
+      ieee_repr.sign = lsb(value_bits, 1) != 0;
       return ieee_repr;
     }

@@ -542,12 +840,12 @@  namespace

       ieee_t<floating_type_float16_t> ieee_repr;
       ieee_repr.mantissa
-	= static_cast<mantissa_t>(value_bits & ((uint32_t{1} << mantissa_bits) - 1u));
+	= static_cast<mantissa_t>(lsb(value_bits, mantissa_bits));
       value_bits >>= mantissa_bits;
       ieee_repr.biased_exponent
-	= static_cast<uint32_t>(value_bits & ((uint32_t{1} << exponent_bits) - 1u));
+	= static_cast<uint32_t>(lsb(value_bits, exponent_bits));
       value_bits >>= exponent_bits;
-      ieee_repr.sign = (value_bits & 1) != 0;
+      ieee_repr.sign = lsb(value_bits, 1) != 0;
       // We have mantissa and biased_exponent from the float (originally
       // float16_t converted to float).
       // Transform that to float16_t mantissa and biased_exponent.
@@ -589,12 +887,12 @@  namespace

       ieee_t<floating_type_bfloat16_t> ieee_repr;
       ieee_repr.mantissa
-	= static_cast<mantissa_t>(value_bits & ((uint32_t{1} << mantissa_bits) - 1u));
+	= static_cast<mantissa_t>(lsb(value_bits, mantissa_bits));
       value_bits >>= mantissa_bits;
       ieee_repr.biased_exponent
-	= static_cast<uint32_t>(value_bits & ((uint32_t{1} << exponent_bits) - 1u));
+	= static_cast<uint32_t>(lsb(value_bits, exponent_bits));
       value_bits >>= exponent_bits;
-      ieee_repr.sign = (value_bits & 1) != 0;
+      ieee_repr.sign = lsb(value_bits, 1) != 0;
       // We have mantissa and biased_exponent from the float (originally
       // bfloat16_t converted to float).
       // Transform that to bfloat16_t mantissa and biased_exponent.
@@ -609,7 +907,10 @@  namespace
     floating_to_shortest_scientific(const T value)
     {
       if constexpr (std::is_same_v<T, float>)
-	return ryu::floating_to_fd32(value);
+      {
+	(void) &ryu::floating_to_fd32; // TODO (CN): remove.
+	return teju_jagua(value);
+      }
       else if constexpr (std::is_same_v<T, double>)
 	return ryu::floating_to_fd64(value);
       else if constexpr (std::is_same_v<T, long double>
diff --git a/libstdc++-v3/src/c++17/floating_to_chars_tables.h b/libstdc++-v3/src/c++17/floating_to_chars_tables.h
new file mode 100644
index 00000000000..5cb648713b7
--- /dev/null
+++ b/libstdc++-v3/src/c++17/floating_to_chars_tables.h
@@ -0,0 +1,716 @@ 
+// Tables used by std::to_chars implementation for floating-point types -*- C++ -*-
+
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_FLOATING_TO_CHARS_TABLES_H
+#define _GLIBCXX_FLOATING_TO_CHARS_TABLES_H
+
+#include <cstdint>
+
+namespace {
+
+// Upper and lower parts of mantissa multipliers.
+template <typename Mantissa>
+struct parts {
+  const Mantissa upper;
+  const Mantissa lower;
+};
+
+// Taken from: https://github.com/cassioneri/teju_jagua.
+struct to_chars_table {
+
+  // Get the multiplier for mantissas of type uint32_t at index f.
+  // Suits IEEE Binary32.
+  static parts<uint32_t>
+  get_multiplier(uint32_t /*tag_dispatch*/, const int32_t f) {
+    const uint64_t N = _get_multiplier(f).upper + 1;
+    return { static_cast<uint32_t>(N >> 32), static_cast<uint32_t>(N) };
+  }
+
+private:
+
+  static constexpr int32_t _index_minimum = -324;
+  static constexpr int32_t _index_maximum =  292;
+
+  static const parts<uint64_t>&
+  _get_multiplier(const int32_t f)
+  {
+    __glibcxx_assert(_index_minimum <= f && f <= _index_maximum);
+    return _entry[f - _index_minimum];
+  }
+
+  // Multipliers for mantissas of type uint64_t.
+  // Suits IEEE Binary64.
+  static constexpr parts<uint64_t> _entry[] =
+  {
+    { 0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2 }, // -324
+    { 0xfcf62c1dee382c42, 0x46729e03dd9ed7b6 }, // -323
+    { 0xca5e89b18b602368, 0x385bb19cb14bdfc5 }, // -322
+    { 0xa1e53af46f801c53, 0x60495ae3c1097fd1 }, // -321
+    { 0x81842f29f2cce375, 0xe6a1158300d46641 }, // -320
+    { 0xcf39e50feae16bef, 0xd768226b34870a01 }, // -319
+    { 0xa5c7ea73224deff3, 0x12b9b522906c0801 }, // -318
+    { 0x849feec281d7f328, 0xdbc7c41ba6bcd334 }, // -317
+    { 0xd433179d9c8cb841, 0x5fa60692a46151ec }, // -316
+    { 0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23 }, // -315
+    { 0x87cec76f1c830548, 0x8f2293910d0b15b6 }, // -314
+    { 0xd94ad8b1c7380874, 0x18375281ae7822bd }, // -313
+    { 0xadd57a27d29339f6, 0x79c5db9af1f9b564 }, // -312
+    { 0x8b112e86420f6191, 0xfb04afaf27faf783 }, // -311
+    { 0xde81e40a034bcf4f, 0xf8077f7ea65e58d2 }, // -310
+    { 0xb201833b35d63f73, 0x2cd2cc6551e513db }, // -309
+    { 0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649 }, // -308
+    { 0xe3d8f9e563a198e5, 0x58180fddd97723a7 }, // -307
+    { 0xb6472e511c81471d, 0xe0133fe4adf8e953 }, // -306
+    { 0x91d28b7416cdd27e, 0x4cdc331d57fa5442 }, // -305
+    { 0xe950df20247c83fd, 0x47c6b82ef32a206a }, // -304
+    { 0xbaa718e68396cffd, 0xd30560258f54e6bb }, // -303
+    { 0x95527a5202df0ccb, 0x0f37801e0c43ebc9 }, // -302
+    { 0xeeea5d5004981478, 0x1858ccfce06cac75 }, // -301
+    { 0xbf21e44003acdd2c, 0xe0470a63e6bd56c4 }, // -300
+    { 0x98e7e9cccfbd7dbd, 0x8038d51cb897789d }, // -299
+    { 0xf4a642e14c6262c8, 0xcd27bb612758c0fb }, // -298
+    { 0xc3b8358109e84f07, 0x0a862f80ec4700c9 }, // -297
+    { 0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4 }, // -296
+    { 0xfa856334878fc150, 0xb14f98f6f0feb952 }, // -295
+    { 0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8 }, // -294
+    { 0xa0555e361951c366, 0xd7e105bcc3326220 }, // -293
+    { 0x80444b5e7aa7cf85, 0x7980d163cf5b81b4 }, // -292
+    { 0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec }, // -291
+    { 0xa42e74f3d032f525, 0xba3e7ca8b77f5e56 }, // -290
+    { 0x83585d8fd9c25db7, 0xc831fd53c5ff7eac }, // -289
+    { 0xd226fc195c6a2f8c, 0x73832eec6fff3112 }, // -288
+    { 0xa81f301449ee8c70, 0x5c68f256bfff5a75 }, // -287
+    { 0x867f59a9d4bed6c0, 0x49ed8eabcccc485e }, // -286
+    { 0xd732290fbacaf133, 0xa97c177947ad4096 }, // -285
+    { 0xac2820d9623bf429, 0x546345fa9fbdcd45 }, // -284
+    { 0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e }, // -283
+    { 0xdc5c5301c56b75f7, 0x7641a140cc7810fc }, // -282
+    { 0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63 }, // -281
+    { 0x8d07e33455637eb2, 0xdb0b487b6423e1e9 }, // -280
+    { 0xe1a63853bbd26451, 0x5e7873f8a0396974 }, // -279
+    { 0xb484f9dc9641e9da, 0xb1f9f660802dedf7 }, // -278
+    { 0x906a617d450187e2, 0x27fb2b80668b24c6 }, // -277
+    { 0xe7109bfba19c0c9d, 0x0cc512670a783ad5 }, // -276
+    { 0xb8da1662e7b00a17, 0x3d6a751f3b936244 }, // -275
+    { 0x93e1ab8252f33b45, 0xcabb90e5c942b504 }, // -274
+    { 0xec9c459d51852ba2, 0xddf8e7d60ed1219f }, // -273
+    { 0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19 }, // -272
+    { 0x976e41088617ca01, 0xd5be0503e085d814 }, // -271
+    { 0xf24a01a73cf2dccf, 0xbc633b39673c8ced }, // -270
+    { 0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1 }, // -269
+    { 0x9b10a4e5e9913128, 0xca7cf2b4191c8327 }, // -268
+    { 0xf81aa16fdc1b81da, 0xdd94b7868e94050b }, // -267
+    { 0xc67bb4597ce2ce48, 0xb143c6053edcd0d6 }, // -266
+    { 0x9ec95d1463e8a506, 0xf4363804324a40ab }, // -265
+    { 0xfe0efb53d30dd4d7, 0xed238cd383aa0111 }, // -264
+    { 0xcb3f2f7642717713, 0x241c70a936219a74 }, // -263
+    { 0xa298f2c501f45f42, 0x8349f3ba91b47b90 }, // -262
+    { 0x8213f56a67f6b29b, 0x9c3b29620e29fc74 }, // -261
+    { 0xd01fef10a657842c, 0x2d2b7569b0432d86 }, // -260
+    { 0xa67ff273b8460356, 0x8a892abaf368f138 }, // -259
+    { 0x8533285c936b35de, 0xd53a88958f872760 }, // -258
+    { 0xd51ea6fa85785631, 0x552a74227f3ea566 }, // -257
+    { 0xaa7eebfb9df9de8d, 0xddbb901b98feeab8 }, // -256
+    { 0x8865899617fb1871, 0x7e2fa67c7a658893 }, // -255
+    { 0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f }, // -254
+    { 0xae9672aba3d0c320, 0xa184ac2473b529b2 }, // -253
+    { 0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f }, // -252
+    { 0xdf78e4b2bd342cf6, 0x914da9246b255417 }, // -251
+    { 0xb2c71d5bca9023f8, 0x743e20e9ef511013 }, // -250
+    { 0x8f05b1163ba6832d, 0x29cb4d87f2a7400f }, // -249
+    { 0xe4d5e82392a40515, 0x0fabaf3feaa5334b }, // -248
+    { 0xb7118682dbb66a77, 0x3fbc8c33221dc2a2 }, // -247
+    { 0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5 }, // -246
+    { 0xea53df5fd18d5513, 0x84c86189216dc5ee }, // -245
+    { 0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2 }, // -244
+    { 0x95f83d0a1fb69cd9, 0x4abdaf101564f98f }, // -243
+    { 0xeff394dcff8a948e, 0xddfc4b4cef07f5b1 }, // -242
+    { 0xbff610b0cc6edd3f, 0x17fd090a58d32af4 }, // -241
+    { 0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a }, // -240
+    { 0xf5b5d7ec8acb58a2, 0xae10af696774b1dc }, // -239
+    { 0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3 }, // -238
+    { 0x9d412e0806e88aa5, 0x8e1f289560ee864f }, // -237
+    { 0xfb9b7cd9a4a7443c, 0x169840ef017da3b2 }, // -236
+    { 0xc94930ae1d529cfc, 0xdee033f26797b628 }, // -235
+    { 0xa1075a24e4421730, 0xb24cf65b8612f820 }, // -234
+    { 0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a }, // -233
+    { 0xce1de40642e3f4b9, 0x36251260ab9d668f }, // -232
+    { 0xa4e4b66b68b65d60, 0xf81da84d56178540 }, // -231
+    { 0x83ea2b892091e44d, 0x934aed0aab460433 }, // -230
+    { 0xd31045a8341ca07c, 0x1ede48111209a051 }, // -229
+    { 0xa8d9d1535ce3b396, 0x7f1839a741a14d0e }, // -228
+    { 0x8714a775e3e95c78, 0x65acfaec34810a72 }, // -227
+    { 0xd8210befd30efa5a, 0x3c47f7e05401aa4f }, // -226
+    { 0xace73cbfdc0bfb7b, 0x636cc64d1001550c }, // -225
+    { 0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70 }, // -224
+    { 0xdd50f1996b947518, 0xd12f124e28f7771a }, // -223
+    { 0xb10d8e1456105dad, 0x7425a83e872c5f48 }, // -222
+    { 0x8da471a9de737e24, 0x5ceaecfed289e5d3 }, // -221
+    { 0xe2a0b5dc971f303a, 0x2e44ae64840fd61e }, // -220
+    { 0xb54d5e4a127f59c8, 0x2503beb6d00cab4c }, // -219
+    { 0x910ab1d4db9914a0, 0x1d9c9892400a22a3 }, // -218
+    { 0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438 }, // -217
+    { 0xb9a74a0637ce2ee1, 0x6d953e2bd7173693 }, // -216
+    { 0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9 }, // -215
+    { 0xeda2ee1c7064130c, 0x1162def06f79df74 }, // -214
+    { 0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d }, // -213
+    { 0x98165af37b2153de, 0xc3727a337a8b704b }, // -212
+    { 0xf356f7ebf83552fe, 0x0583f6b8c4124d44 }, // -211
+    { 0xc2abf989935ddbfe, 0x6acff893d00ea436 }, // -210
+    { 0x9bbcc7a142b17ccb, 0x88a66076400bb692 }, // -209
+    { 0xf92e0c3537826145, 0xa7709a56ccdf8a83 }, // -208
+    { 0xc75809c42c684dd1, 0x52c07b78a3e60869 }, // -207
+    { 0x9f79a169bd203e41, 0x0f0062c6e984d387 }, // -206
+    { 0xff290242c83396ce, 0x7e67047175a15272 }, // -205
+    { 0xcc20ce9bd35c78a5, 0x31ec038df7b441f5 }, // -204
+    { 0xa34d721642b06084, 0x27f002d7f95d0191 }, // -203
+    { 0x82a45b450226b39c, 0xecc0024661173474 }, // -202
+    { 0xd106f86e69d785c7, 0xe13336d701beba53 }, // -201
+    { 0xa738c6bebb12d16c, 0xb428f8ac016561dc }, // -200
+    { 0x85c7056562757456, 0xf6872d5667844e4a }, // -199
+    { 0xd60b3bd56a5586f1, 0x8a71e223d8d3b075 }, // -198
+    { 0xab3c2fddeeaad25a, 0xd527e81cad7626c4 }, // -197
+    { 0x88fcf317f22241e2, 0x441fece3bdf81f04 }, // -196
+    { 0xdb2e51bfe9d0696a, 0x06997b05fcc0319f }, // -195
+    { 0xaf58416654a6babb, 0x387ac8d1970027b3 }, // -194
+    { 0x8c469ab843b89562, 0x93956d7478ccec8f }, // -193
+    { 0xe070f78d3927556a, 0x85bbe253f47b1418 }, // -192
+    { 0xb38d92d760ec4455, 0x37c981dcc395a9ad }, // -191
+    { 0x8fa475791a569d10, 0xf96e017d694487bd }, // -190
+    { 0xe5d3ef282a242e81, 0x8f1668c8a86da5fb }, // -189
+    { 0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30 }, // -188
+    { 0x9316ff75dd87cbd8, 0x09a7f12442d588f3 }, // -187
+    { 0xeb57ff22fc0c7959, 0xa90cb506d155a7eb }, // -186
+    { 0xbc4665b596706114, 0x873d5d9f0dde1fef }, // -185
+    { 0x969eb7c47859e743, 0x9f644ae5a4b1b326 }, // -184
+    { 0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6 }, // -183
+    { 0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de }, // -182
+    { 0x9a3c2087a63f6399, 0x36ac54e2f678864c }, // -181
+    { 0xf6c69a72a3989f5b, 0x8aad549e57273d46 }, // -180
+    { 0xc56baec21c7a1916, 0x088aaa1845b8fdd1 }, // -179
+    { 0x9defbf01b061adab, 0x3a0888136afa64a8 }, // -178
+    { 0xfcb2cb35e702af78, 0x5cda735244c3d43f }, // -177
+    { 0xca28a291859bbf93, 0x7d7b8f7503cfdcff }, // -176
+    { 0xa1ba1ba79e1632dc, 0x6462d92a69731733 }, // -175
+    { 0x8161afb94b44f57d, 0x1d1be0eebac278f6 }, // -174
+    { 0xcf02b2c21207ef2e, 0x94f967e45e03f4bc }, // -173
+    { 0xa59bc234db398c25, 0x43fab9837e699096 }, // -172
+    { 0x847c9b5d7c2e09b7, 0x69956135febada12 }, // -171
+    { 0xd3fa922f2d1675f2, 0x42889b8997915ce9 }, // -170
+    { 0xa99541bf57452b28, 0x353a1607ac744a54 }, // -169
+    { 0x87aa9aff79042286, 0x90fb44d2f05d0843 }, // -168
+    { 0xd910f7ff28069da4, 0x1b2ba1518094da05 }, // -167
+    { 0xada72ccc20054ae9, 0xaf561aa79a10ae6b }, // -166
+    { 0x8aec23d680043bee, 0x25de7bb9480d5855 }, // -165
+    { 0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc }, // -164
+    { 0xb1d219647ae6b31c, 0x596eb2d8ae258fc9 }, // -163
+    { 0x8e41ade9fbebc27d, 0x14588f13be847308 }, // -162
+    { 0xe39c49765fdf9d94, 0xed5a7e85fda0b80c }, // -161
+    { 0xb616a12b7fe617aa, 0x577b986b314d600a }, // -160
+    { 0x91abb422ccb812ee, 0xac62e055c10ab33b }, // -159
+    { 0xe912b9d1478ceb17, 0x7a37cd5601aab85e }, // -158
+    { 0xba756174393d88df, 0x94f971119aeef9e5 }, // -157
+    { 0x952ab45cfa97a0b2, 0xdd945a747bf26184 }, // -156
+    { 0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39 }, // -155
+    { 0xbeeefb584aff8603, 0xaafb550ffacfd8fb }, // -154
+    { 0x98bf2f79d5993802, 0xef2f773ffbd97a62 }, // -153
+    { 0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a }, // -152
+    { 0xc38413cf25e2d70d, 0xfef5138519684abb }, // -151
+    { 0x9c69a97284b578d7, 0xff2a760414536efc }, // -150
+    { 0xfa42a8b73abbf48c, 0xcb772339ba1f17fa }, // -149
+    { 0xc83553c5c8965d3d, 0x6f92829494e5acc8 }, // -148
+    { 0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d }, // -147
+    { 0x802221226be55a64, 0xc2494954da2c978a }, // -146
+    { 0xcd036837130890a1, 0x36dba887c37a8c10 }, // -145
+    { 0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7 }, // -144
+    { 0x8335616aed761f1f, 0x7f44e6bd49e807b9 }, // -143
+    { 0xd1ef0244af2364ff, 0x3207d795430cd927 }, // -142
+    { 0xa7f26836f282b732, 0x8e6cac7768d7141f }, // -141
+    { 0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3 }, // -140
+    { 0xd6f8d7509292d603, 0x45a9d2845d3c42b7 }, // -139
+    { 0xabfa45da0edbde69, 0x0487db9d17636893 }, // -138
+    { 0x899504ae72497eba, 0x6a06494a791c53a9 }, // -137
+    { 0xdc21a1171d42645d, 0x76707543f4fa1f74 }, // -136
+    { 0xb01ae745b101e9e4, 0x5ec05dcff72e7f90 }, // -135
+    { 0x8ce2529e2734bb1d, 0x1899e4a65f58660d }, // -134
+    { 0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b }, // -133
+    { 0xb454e4a179dd1877, 0x29babe4598c311fc }, // -132
+    { 0x9043ea1ac7e41392, 0x87c89837ad68db30 }, // -131
+    { 0xe6d3102ad96cec1d, 0xa60dc059157491e6 }, // -130
+    { 0xb8a8d9bbe123f017, 0xb80b0047445d4185 }, // -129
+    { 0x93ba47c980e98cdf, 0xc66f336c36b10138 }, // -128
+    { 0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf }, // -127
+    { 0xbd176620a501fbff, 0xb650e5a93bc3d899 }, // -126
+    { 0x9745eb4d50ce6332, 0xf840b7ba963646e1 }, // -125
+    { 0xf209787bb47d6b84, 0xc0678c5dbd23a49b }, // -124
+    { 0xc1a12d2fc3978937, 0x0052d6b1641c83af }, // -123
+    { 0x9ae757596946075f, 0x3375788de9b06959 }, // -122
+    { 0xf7d88bc24209a565, 0x1f225a7ca91a4227 }, // -121
+    { 0xc646d63501a1511d, 0xb281e1fd541501b9 }, // -120
+    { 0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb }, // -119
+    { 0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7 }, // -118
+    { 0xcb090c8001ab551c, 0x5cadf5bfd3072cc6 }, // -117
+    { 0xa26da3999aef7749, 0xe3be5e330f38f09e }, // -116
+    { 0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f }, // -115
+    { 0xcfe87f7cef46ff16, 0xe612641865679a64 }, // -114
+    { 0xa6539930bf6bff45, 0x84db8346b786151d }, // -113
+    { 0x850fadc09923329e, 0x03e2cf6bc604ddb1 }, // -112
+    { 0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b }, // -111
+    { 0xaa51823e34a7eede, 0xbd4b46f0599fd416 }, // -110
+    { 0x884134fe908658b2, 0x3109058d147fdcde }, // -109
+    { 0xda01ee641a708de9, 0xe80e6f4820cc9496 }, // -108
+    { 0xae67f1e9aec07187, 0xecd8590680a3aa12 }, // -107
+    { 0x8b865b215899f46c, 0xbd79e0d20082ee75 }, // -106
+    { 0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee }, // -105
+    { 0xb2977ee300c50fe7, 0x58edec91ec2cb658 }, // -104
+    { 0x8edf98b59a373fec, 0x4724bd4189bd5ead }, // -103
+    { 0xe498f455c38b997a, 0x0b6dfb9c0f956448 }, // -102
+    { 0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d }, // -101
+    { 0x924d692ca61be758, 0x593c2626705f9c57 }, // -100
+    { 0xea1575143cf97226, 0xf52d09d71a3293be }, // -99
+    { 0xbb445da9ca61281f, 0x2a8a6e45ae8edc98 }, // -98
+    { 0x95d04aee3b80ece5, 0xbba1f1d158724a13 }, // -97
+    { 0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f }, // -96
+    { 0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f }, // -95
+    { 0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc }, // -94
+    { 0xf5746577930d6500, 0xca8f44ec7ee3647a }, // -93
+    { 0xc45d1df942711d9a, 0x3ba5d0bd324f8395 }, // -92
+    { 0x9d174b2dcec0e47b, 0x62eb0d64283f9c77 }, // -91
+    { 0xfb5878494ace3a5f, 0x04ab48a04065c724 }, // -90
+    { 0xc913936dd571c84c, 0x03bc3a19cd1e38ea }, // -89
+    { 0xa0dc75f1778e39d6, 0x696361ae3db1c722 }, // -88
+    { 0x80b05e5ac60b6178, 0x544f8158315b05b5 }, // -87
+    { 0xcde6fd5e09abcf26, 0xed4c0226b55e6f87 }, // -86
+    { 0xa4b8cab1a1563f52, 0x577001b891185939 }, // -85
+    { 0x83c7088e1aab65db, 0x792667c6da79e0fb }, // -84
+    { 0xd2d80db02aabd62b, 0xf50a3fa490c30191 }, // -83
+    { 0xa8acd7c0222311bc, 0xc40832ea0d68ce0d }, // -82
+    { 0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4 }, // -81
+    { 0xd7e77a8f87daf7fb, 0xdc33745ec97be907 }, // -80
+    { 0xacb92ed9397bf996, 0x49c2c37f07965405 }, // -79
+    { 0x8a2dbf142dfcc7ab, 0x6e3569326c784338 }, // -78
+    { 0xdd15fe86affad912, 0x49ef0eb713f39ebf }, // -77
+    { 0xb0de65388cc8ada8, 0x3b25a55f43294bcc }, // -76
+    { 0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3 }, // -75
+    { 0xe264589a4dcdab14, 0xc696963c7eed2dd2 }, // -74
+    { 0xb51d13aea4a488dd, 0x6babab6398bdbe42 }, // -73
+    { 0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce }, // -72
+    { 0xe7d34c64a9c85d44, 0x60dbbca87196b617 }, // -71
+    { 0xb975d6b6ee39e436, 0xb3e2fd538e122b45 }, // -70
+    { 0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b }, // -69
+    { 0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde }, // -68
+    { 0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318 }, // -67
+    { 0x97edd871cfda3a56, 0x97758bf0e3cbb5ad }, // -66
+    { 0xf316271c7fc3908a, 0x8bef464e3945ef7b }, // -65
+    { 0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc }, // -64
+    { 0x9b934c3b330c8577, 0x63cc55f49f88eb30 }, // -63
+    { 0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3 }, // -62
+    { 0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6 }, // -61
+    { 0x9f4f2726179a2245, 0x01d762422c946591 }, // -60
+    { 0xfee50b7025c36a08, 0x02f236d04753d5b5 }, // -59
+    { 0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491 }, // -58
+    { 0xa321f2d7226895c7, 0xaff72d52192b6a0e }, // -57
+    { 0x82818f1281ed449f, 0xbff8f10e7a8921a5 }, // -56
+    { 0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6e }, // -55
+    { 0xa70c3c40a64e6c51, 0x999090b65f67d925 }, // -54
+    { 0x85a36366eb71f041, 0x47a6da2b7f864751 }, // -53
+    { 0xd5d238a4abe98068, 0x72a4904598d6d881 }, // -52
+    { 0xab0e93b6efee0053, 0x8eea0d047a457a01 }, // -51
+    { 0x88d8762bf324cd0f, 0xa5880a69fb6ac801 }, // -50
+    { 0xdaf3f04651d47b4c, 0x3c0cdd765f114001 }, // -49
+    { 0xaf298d050e4395d6, 0x9670b12b7f410001 }, // -48
+    { 0x8c213d9da502de45, 0x4526f422cc340001 }, // -47
+    { 0xe0352f62a19e306e, 0xd50b2037ad200001 }, // -46
+    { 0xb35dbf821ae4f38b, 0xdda2802c8a800001 }, // -45
+    { 0x8f7e32ce7bea5c6f, 0xe4820023a2000001 }, // -44
+    { 0xe596b7b0c643c719, 0x6d9ccd05d0000001 }, // -43
+    { 0xb7abc627050305ad, 0xf14a3d9e40000001 }, // -42
+    { 0x92efd1b8d0cf37be, 0x5aa1cae500000001 }, // -41
+    { 0xeb194f8e1ae525fd, 0x5dcfab0800000001 }, // -40
+    { 0xbc143fa4e250eb31, 0x17d955a000000001 }, // -39
+    { 0x96769950b50d88f4, 0x1314448000000001 }, // -38
+    { 0xf0bdc21abb48db20, 0x1e86d40000000001 }, // -37
+    { 0xc097ce7bc90715b3, 0x4b9f100000000001 }, // -36
+    { 0x9a130b963a6c115c, 0x3c7f400000000001 }, // -35
+    { 0xf684df56c3e01bc6, 0xc732000000000001 }, // -34
+    { 0xc5371912364ce305, 0x6c28000000000001 }, // -33
+    { 0x9dc5ada82b70b59d, 0xf020000000000001 }, // -32
+    { 0xfc6f7c4045812296, 0x4d00000000000001 }, // -31
+    { 0xc9f2c9cd04674ede, 0xa400000000000001 }, // -30
+    { 0xa18f07d736b90be5, 0x5000000000000001 }, // -29
+    { 0x813f3978f8940984, 0x4000000000000001 }, // -28
+    { 0xcecb8f27f4200f3a, 0x0000000000000001 }, // -27
+    { 0xa56fa5b99019a5c8, 0x0000000000000001 }, // -26
+    { 0x84595161401484a0, 0x0000000000000001 }, // -25
+    { 0xd3c21bcecceda100, 0x0000000000000001 }, // -24
+    { 0xa968163f0a57b400, 0x0000000000000001 }, // -23
+    { 0x878678326eac9000, 0x0000000000000001 }, // -22
+    { 0xd8d726b7177a8000, 0x0000000000000001 }, // -21
+    { 0xad78ebc5ac620000, 0x0000000000000001 }, // -20
+    { 0x8ac7230489e80000, 0x0000000000000001 }, // -19
+    { 0xde0b6b3a76400000, 0x0000000000000001 }, // -18
+    { 0xb1a2bc2ec5000000, 0x0000000000000001 }, // -17
+    { 0x8e1bc9bf04000000, 0x0000000000000001 }, // -16
+    { 0xe35fa931a0000000, 0x0000000000000001 }, // -15
+    { 0xb5e620f480000000, 0x0000000000000001 }, // -14
+    { 0x9184e72a00000000, 0x0000000000000001 }, // -13
+    { 0xe8d4a51000000000, 0x0000000000000001 }, // -12
+    { 0xba43b74000000000, 0x0000000000000001 }, // -11
+    { 0x9502f90000000000, 0x0000000000000001 }, // -10
+    { 0xee6b280000000000, 0x0000000000000001 }, // -9
+    { 0xbebc200000000000, 0x0000000000000001 }, // -8
+    { 0x9896800000000000, 0x0000000000000001 }, // -7
+    { 0xf424000000000000, 0x0000000000000001 }, // -6
+    { 0xc350000000000000, 0x0000000000000001 }, // -5
+    { 0x9c40000000000000, 0x0000000000000001 }, // -4
+    { 0xfa00000000000000, 0x0000000000000001 }, // -3
+    { 0xc800000000000000, 0x0000000000000001 }, // -2
+    { 0xa000000000000000, 0x0000000000000001 }, // -1
+    { 0x8000000000000000, 0x0000000000000001 }, // 0
+    { 0xcccccccccccccccc, 0xcccccccccccccccd }, // 1
+    { 0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4 }, // 2
+    { 0x83126e978d4fdf3b, 0x645a1cac083126ea }, // 3
+    { 0xd1b71758e219652b, 0xd3c36113404ea4a9 }, // 4
+    { 0xa7c5ac471b478423, 0x0fcf80dc33721d54 }, // 5
+    { 0x8637bd05af6c69b5, 0xa63f9a49c2c1b110 }, // 6
+    { 0xd6bf94d5e57a42bc, 0x3d32907604691b4d }, // 7
+    { 0xabcc77118461cefc, 0xfdc20d2b36ba7c3e }, // 8
+    { 0x89705f4136b4a597, 0x31680a88f8953031 }, // 9
+    { 0xdbe6fecebdedd5be, 0xb573440e5a884d1c }, // 10
+    { 0xafebff0bcb24aafe, 0xf78f69a51539d749 }, // 11
+    { 0x8cbccc096f5088cb, 0xf93f87b7442e45d4 }, // 12
+    { 0xe12e13424bb40e13, 0x2865a5f206b06fba }, // 13
+    { 0xb424dc35095cd80f, 0x538484c19ef38c95 }, // 14
+    { 0x901d7cf73ab0acd9, 0x0f9d37014bf60a11 }, // 15
+    { 0xe69594bec44de15b, 0x4c2ebe687989a9b4 }, // 16
+    { 0xb877aa3236a4b449, 0x09befeb9fad487c3 }, // 17
+    { 0x9392ee8e921d5d07, 0x3aff322e62439fd0 }, // 18
+    { 0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6 }, // 19
+    { 0xbce5086492111aea, 0x88f4bb1ca6bcf585 }, // 20
+    { 0x971da05074da7bee, 0xd3f6fc16ebca5e04 }, // 21
+    { 0xf1c90080baf72cb1, 0x5324c68b12dd6339 }, // 22
+    { 0xc16d9a0095928a27, 0x75b7053c0f178294 }, // 23
+    { 0x9abe14cd44753b52, 0xc4926a9672793543 }, // 24
+    { 0xf79687aed3eec551, 0x3a83ddbd83f52205 }, // 25
+    { 0xc612062576589dda, 0x95364afe032a819e }, // 26
+    { 0x9e74d1b791e07e48, 0x775ea264cf55347e }, // 27
+    { 0xfd87b5f28300ca0d, 0x8bca9d6e188853fd }, // 28
+    { 0xcad2f7f5359a3b3e, 0x096ee45813a04331 }, // 29
+    { 0xa2425ff75e14fc31, 0xa1258379a94d028e }, // 30
+    { 0x81ceb32c4b43fcf4, 0x80eacf948770ced8 }, // 31
+    { 0xcfb11ead453994ba, 0x67de18eda5814af3 }, // 32
+    { 0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f }, // 33
+    { 0x84ec3c97da624ab4, 0xbd5af13bef0b113f }, // 34
+    { 0xd4ad2dbfc3d07787, 0x955e4ec64b44e865 }, // 35
+    { 0xaa242499697392d2, 0xdde50bd1d5d0b9ea }, // 36
+    { 0x881cea14545c7575, 0x7e50d64177da2e55 }, // 37
+    { 0xd9c7dced53c72255, 0x96e7bd358c904a22 }, // 38
+    { 0xae397d8aa96c1b77, 0xabec975e0a0d081b }, // 39
+    { 0x8b61313bbabce2c6, 0x2323ac4b3b3da016 }, // 40
+    { 0xdf01e85f912e37a3, 0x6b6c46dec52f6689 }, // 41
+    { 0xb267ed1940f1c61c, 0x55f038b237591ed4 }, // 42
+    { 0x8eb98a7a9a5b04e3, 0x77f3608e92adb243 }, // 43
+    { 0xe45c10c42a2b3b05, 0x8cb89a7db77c506b }, // 44
+    { 0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23 }, // 45
+    { 0x9226712162ab070d, 0xcab3961304ca70e9 }, // 46
+    { 0xe9d71b689dde71af, 0xaab8f01e6e10b4a7 }, // 47
+    { 0xbb127c53b17ec159, 0x5560c018580d5d53 }, // 48
+    { 0x95a8637627989aad, 0xdde7001379a44aa9 }, // 49
+    { 0xef73d256a5c0f77c, 0x963e66858f6d4441 }, // 50
+    { 0xbf8fdb78849a5f96, 0xde98520472bdd034 }, // 51
+    { 0x993fe2c6d07b7fab, 0xe546a8038efe402a }, // 52
+    { 0xf53304714d9265df, 0xd53dd99f4b3066a9 }, // 53
+    { 0xc428d05aa4751e4c, 0xaa97e14c3c26b887 }, // 54
+    { 0x9ced737bb6c4183d, 0x55464dd69685606c }, // 55
+    { 0xfb158592be068d2e, 0xeed6e2f0f0d56713 }, // 56
+    { 0xc8de047564d20a8b, 0xf245825a5a445276 }, // 57
+    { 0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5 }, // 58
+    { 0x808e17555f3ebf11, 0xe2bbd88bbee40bd1 }, // 59
+    { 0xcdb02555653131b6, 0x3792f412cb06794e }, // 60
+    { 0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8 }, // 61
+    { 0x83a3eeeef9153e89, 0x1953cf68300424ad }, // 62
+    { 0xd29fe4b18e88640e, 0x8eec7f0d19a03aae }, // 63
+    { 0xa87fea27a539e9a5, 0x3f2398d747b36225 }, // 64
+    { 0x86ccbb52ea94baea, 0x98e947129fc2b4ea }, // 65
+    { 0xd7adf884aa879177, 0x5b0ed81dcc6abb10 }, // 66
+    { 0xac8b2d36eed2dac5, 0xe272467e3d222f40 }, // 67
+    { 0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900 }, // 68
+    { 0xdcdb1b2798182244, 0xf8e431456cf88e66 }, // 69
+    { 0xb0af48ec79ace837, 0x2d835a9df0c6d852 }, // 70
+    { 0x8d590723948a535f, 0x579c487e5a38ad0f }, // 71
+    { 0xe2280b6c20dd5232, 0x25c6da63c38de1b1 }, // 72
+    { 0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4 }, // 73
+    { 0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3 }, // 74
+    { 0xe7958cb87392c2c2, 0xb60b1d1230b20e05 }, // 75
+    { 0xb94470938fa89bce, 0xf808e40e8d5b3e6a }, // 76
+    { 0x9436c0760c86e30b, 0xf9a0b6720aaf6522 }, // 77
+    { 0xed246723473e3813, 0x290123e9aab23b69 }, // 78
+    { 0xbdb6b8e905cb600f, 0x5400e987bbc1c921 }, // 79
+    { 0x97c560ba6b0919a5, 0xdccd879fc967d41b }, // 80
+    { 0xf2d56790ab41c2a2, 0xfae27299423fb9c4 }, // 81
+    { 0xc24452da229b021b, 0xfbe85badce996169 }, // 82
+    { 0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb }, // 83
+    { 0xf8a95fcf88747d94, 0x75a44c6397ce912b }, // 84
+    { 0xc6ede63fa05d3143, 0x91503d1c79720dbc }, // 85
+    { 0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca }, // 86
+    { 0xfea126b7d78186bc, 0xe2f610c84987bfa9 }, // 87
+    { 0xcbb41ef979346bca, 0x4f2b40a03ad2ffba }, // 88
+    { 0xa2f67f2dfa90563b, 0x728900802f0f32fb }, // 89
+    { 0x825ecc24c873782f, 0x8ed400668c0c28c9 }, // 90
+    { 0xd097ad07a71f26b2, 0x7e2000a41346a7a8 }, // 91
+    { 0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953 }, // 92
+    { 0x857fcae62d8493a5, 0x6f70a4400c562ddc }, // 93
+    { 0xd59944a37c0752a2, 0x4be76d3346f04960 }, // 94
+    { 0xaae103b5fcd2a881, 0xd652bdc29f26a11a }, // 95
+    { 0x88b402f7fd75539b, 0x11dbcb0218ebb415 }, // 96
+    { 0xdab99e59958885c4, 0xe95fab368e45ecee }, // 97
+    { 0xaefae51477a06b03, 0xede622920b6b23f2 }, // 98
+    { 0x8bfbea76c619ef36, 0x57eb4edb3c55b65b }, // 99
+    { 0xdff9772470297ebd, 0x59787e2b93bc56f8 }, // 100
+    { 0xb32df8e9f3546564, 0x47939822dc96abfa }, // 101
+    { 0x8f57fa54c2a9eab6, 0x9fa946824a12232e }, // 102
+    { 0xe55990879ddcaabd, 0xcc420a6a101d0516 }, // 103
+    { 0xb77ada0617e3bbcb, 0x09ce6ebb40173745 }, // 104
+    { 0x92c8ae6b464fc96f, 0x3b0b8bc90012929e }, // 105
+    { 0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f }, // 106
+    { 0xbbe226efb628afea, 0x890489f70a55368c }, // 107
+    { 0x964e858c91ba2655, 0x3a6a07f8d510f870 }, // 108
+    { 0xf07da27a82c37088, 0x5d767327bb4e5a4d }, // 109
+    { 0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7 }, // 110
+    { 0x99ea0196163fa42e, 0x504bced1bf8e4e46 }, // 111
+    { 0xf64335bcf065d37d, 0x4d4617b5ff4a16d6 }, // 112
+    { 0xc5029163f384a931, 0x0a9e795e65d4df12 }, // 113
+    { 0x9d9ba7832936edc0, 0xd54b944b84aa4c0e }, // 114
+    { 0xfc2c3f3841f17c67, 0xbbac2078d443ace3 }, // 115
+    { 0xc9bcff6034c13052, 0xfc89b393dd02f0b6 }, // 116
+    { 0xa163ff802a3426a8, 0xca07c2dcb0cf26f8 }, // 117
+    { 0x811ccc668829b887, 0x0806357d5a3f5260 }, // 118
+    { 0xce947a3da6a9273e, 0x733d226229feea33 }, // 119
+    { 0xa54394fe1eedb8fe, 0xc2974eb4ee658829 }, // 120
+    { 0x843610cb4bf160cb, 0xcedf722a585139bb }, // 121
+    { 0xd389b47879823479, 0x4aff1d108d4ec2c4 }, // 122
+    { 0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0 }, // 123
+    { 0x87625f056c7c4a8b, 0x11471cd764ad4973 }, // 124
+    { 0xd89d64d57a607744, 0xe871c7bf077ba8b8 }, // 125
+    { 0xad4ab7112eb3929d, 0x86c16c98d2c953c7 }, // 126
+    { 0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c }, // 127
+    { 0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf }, // 128
+    { 0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3 }, // 129
+    { 0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2 }, // 130
+    { 0xe3231912d5bf60e6, 0x10e1fff697ed6c6a }, // 131
+    { 0xb5b5ada8aaff80b8, 0x0d819992132456bb }, // 132
+    { 0x915e2486ef32cd60, 0x0ace1474dc1d122f }, // 133
+    { 0xe896a0d7e51e1566, 0x77b020baf9c81d18 }, // 134
+    { 0xba121a4650e4ddeb, 0x92f34d62616ce414 }, // 135
+    { 0x94db483840b717ef, 0xa8c2a44eb4571cdd }, // 136
+    { 0xee2ba6c0678b597f, 0x746aa07ded582e2d }, // 137
+    { 0xbe89523386091465, 0xf6bbb397f1135824 }, // 138
+    { 0x986ddb5c6b3a76b7, 0xf89629465a75e01d }, // 139
+    { 0xf3e2f893dec3f126, 0x5a89dba3c3efccfb }, // 140
+    { 0xc31bfa0fe5698db8, 0x486e494fcff30a63 }, // 141
+    { 0x9c1661a651213e2d, 0x06bea10ca65c084f }, // 142
+    { 0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1 }, // 143
+    { 0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1 }, // 144
+    { 0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634 }, // 145
+    { 0xffbbcfe994e5c61f, 0xfdf17746497f7053 }, // 146
+    { 0xcc963fee10b7d1b3, 0x318df905079926a9 }, // 147
+    { 0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb }, // 148
+    { 0x82ef85133de648c4, 0x9a984d73dbe722fc }, // 149
+    { 0xd17f3b51fca3a7a0, 0xf75a15862ca504c6 }, // 150
+    { 0xa798fc4196e952e7, 0x2c48113823b73705 }, // 151
+    { 0x8613fd0145877585, 0xbd06742ce95f5f37 }, // 152
+    { 0xd686619ba27255a2, 0xc80a537b0efefebe }, // 153
+    { 0xab9eb47c81f5114f, 0x066ea92f3f326565 }, // 154
+    { 0x894bc396ce5da772, 0x6b8bba8c328eb784 }, // 155
+    { 0xdbac6c247d62a583, 0xdf45f746b74abf3a }, // 156
+    { 0xafbd2350644eeacf, 0xe5d1929ef90898fb }, // 157
+    { 0x8c974f7383725573, 0x1e414218c73a13fc }, // 158
+    { 0xe0f218b8d25088b8, 0x306869c13ec3532d }, // 159
+    { 0xb3f4e093db73a093, 0x59ed216765690f57 }, // 160
+    { 0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac }, // 161
+    { 0xe65829b3046b0afa, 0x0cb4a5a3112a5113 }, // 162
+    { 0xb84687c269ef3bfb, 0x3d5d514f40eea743 }, // 163
+    { 0x936b9fcebb25c995, 0xcab10dd900beec35 }, // 164
+    { 0xebdf661791d60f56, 0x111b495b3464ad22 }, // 165
+    { 0xbcb2b812db11a5de, 0x7415d448f6b6f0e8 }, // 166
+    { 0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba }, // 167
+    { 0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2 }, // 168
+    { 0xc13a148e3032d6e7, 0xe36a52363c1faf02 }, // 169
+    { 0x9a94dd3e8cf578b9, 0x82bb74f8301958cf }, // 170
+    { 0xf7549530e188c128, 0xd12bee59e68ef47d }, // 171
+    { 0xc5dd44271ad3cdba, 0x40eff1e1853f29fe }, // 172
+    { 0x9e4a9cec15763e2e, 0x9a598e4e043287ff }, // 173
+    { 0xfd442e4688bd304a, 0x908f4a166d1da664 }, // 174
+    { 0xca9cf1d206fdc03b, 0xa6d90811f0e4851d }, // 175
+    { 0xa21727db38cb002f, 0xb8ada00e5a506a7d }, // 176
+    { 0x81ac1fe293d599bf, 0xc6f14cd848405531 }, // 177
+    { 0xcf79cc9db955c2cc, 0x7182148d4066eeb5 }, // 178
+    { 0xa5fb0a17c777cf09, 0xf468107100525891 }, // 179
+    { 0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074 }, // 180
+    { 0xd47487cc8470652b, 0x7647c32000696720 }, // 181
+    { 0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d }, // 182
+    { 0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7 }, // 183
+    { 0xd98ddaee19068c76, 0x3badd624dd9b0958 }, // 184
+    { 0xae0b158b4738705e, 0x9624ab50b148d446 }, // 185
+    { 0x8b3c113c38f9f37e, 0xde83bc408dd3dd05 }, // 186
+    { 0xdec681f9f4c31f31, 0x6405fa00e2ec94d5 }, // 187
+    { 0xb23867fb2a35b28d, 0xe99e619a4f23aa44 }, // 188
+    { 0x8e938662882af53e, 0x547eb47b7282ee9d }, // 189
+    { 0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94 }, // 190
+    { 0xb67f6455292cbf08, 0x1a3bc84c17b1d543 }, // 191
+    { 0x91ff83775423cc06, 0x7b6306a34627ddd0 }, // 192
+    { 0xe998d258869facd7, 0x2bd1a438703fc94c }, // 193
+    { 0xbae0a846d2195712, 0x8974836059cca10a }, // 194
+    { 0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1 }, // 195
+    { 0xef340a98172aace4, 0x86fb897116c87c35 }, // 196
+    { 0xbf5cd54678eef0b6, 0xd262d45a78a0635e }, // 197
+    { 0x991711052d8bf3c5, 0x751bdd152d4d1c4b }, // 198
+    { 0xf4f1b4d515acb93b, 0xee92fb5515482d45 }, // 199
+    { 0xc3f490aa77bd60fc, 0xbedbfc4411068a9d }, // 200
+    { 0x9cc3a6eec6311a63, 0xcbe3303674053bb1 }, // 201
+    { 0xfad2a4b13d1b5d6c, 0x796b805720085f82 }, // 202
+    { 0xc8a883c0fdaf7df0, 0x6122cd128006b2ce }, // 203
+    { 0xa086cfcd97bf97f3, 0x80e8a40eccd228a5 }, // 204
+    { 0x806bd9714632dff6, 0x00ba1cd8a3db53b7 }, // 205
+    { 0xcd795be870516656, 0x67902e276c921f8c }, // 206
+    { 0xa46116538d0deb78, 0x52d9be85f074e609 }, // 207
+    { 0x8380dea93da4bc60, 0x4247cb9e59f71e6e }, // 208
+    { 0xd267caa862a12d66, 0xd072df63c324fd7c }, // 209
+    { 0xa8530886b54dbdeb, 0xd9f57f830283fdfd }, // 210
+    { 0x86a8d39ef77164bc, 0xae5dff9c02033198 }, // 211
+    { 0xd77485cb25823ac7, 0x7d633293366b828c }, // 212
+    { 0xac5d37d5b79b6239, 0x311c2875c522ced6 }, // 213
+    { 0x89e42caaf9491b60, 0xf41686c49db57245 }, // 214
+    { 0xdca04777f541c567, 0xecf0d7a0fc5583a1 }, // 215
+    { 0xb080392cc4349dec, 0xbd8d794d96aacfb4 }, // 216
+    { 0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d }, // 217
+    { 0xe1ebce4dc7f16dfb, 0xd3e8495912c62895 }, // 218
+    { 0xb4bca50b065abe63, 0x0fed077a756b53aa }, // 219
+    { 0x9096ea6f3848984f, 0x3ff0d2c85def7622 }, // 220
+    { 0xe757dd7ec07426e5, 0x331aeada2fe589d0 }, // 221
+    { 0xb913179899f68584, 0x28e2557b59846e40 }, // 222
+    { 0x940f4613ae5ed136, 0x871b7795e136be9a }, // 223
+    { 0xece53cec4a314ebd, 0xa4f8bf5635246429 }, // 224
+    { 0xbd8430bd08277231, 0x50c6ff782a838354 }, // 225
+    { 0x979cf3ca6cec5b5a, 0xa705992ceecf9c43 }, // 226
+    { 0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e }, // 227
+    { 0xc21094364dfb5636, 0x985915fc12f542e5 }, // 228
+    { 0x9b407691d7fc44f8, 0x79e0de63425dcf1e }, // 229
+    { 0xf867241c8cc6d4c0, 0xc30163d203c94b63 }, // 230
+    { 0xc6b8e9b0709f109a, 0x359ab6419ca1091c }, // 231
+    { 0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0 }, // 232
+    { 0xfe5d54150b090b02, 0xd3f93b35435d7c4d }, // 233
+    { 0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a }, // 234
+    { 0xa2cb1717b52481ed, 0x54768c4b0c64ca6f }, // 235
+    { 0x823c12795db6ce57, 0x76c53d08d6b70859 }, // 236
+    { 0xd0601d8efc57b08b, 0xf13b94daf124da27 }, // 237
+    { 0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f }, // 238
+    { 0x855c3be0a17fcd26, 0x5cf2eea09a550680 }, // 239
+    { 0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65 }, // 240
+    { 0xaab37fd7d8f58178, 0xc8e5087ba6d33b84 }, // 241
+    { 0x888f99797a5e012d, 0x6d8406c952429604 }, // 242
+    { 0xda7f5bf590966848, 0xaf39a475506a899f }, // 243
+    { 0xaecc49914078536d, 0x58fae9f773886e19 }, // 244
+    { 0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1 }, // 245
+    { 0xdfbdcece67006ac9, 0x67a791e093e1d49b }, // 246
+    { 0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16 }, // 247
+    { 0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811 }, // 248
+    { 0xe51c79a85916f484, 0x82b7e12780e7401b }, // 249
+    { 0xb749faed14125d36, 0xcef980ec671f667c }, // 250
+    { 0x92a1958a7675175f, 0x0bfacd89ec191eca }, // 251
+    { 0xea9c227723ee8bcb, 0x465e15a979c1cadd }, // 252
+    { 0xbbb01b9283253ca2, 0x9eb1aaedfb016f17 }, // 253
+    { 0x96267c7535b763b5, 0x4bc1558b2f3458df }, // 254
+    { 0xf03d93eebc589f88, 0x793555ab7eba27cb }, // 255
+    { 0xc0314325637a1939, 0xfa911155fefb5309 }, // 256
+    { 0x99c102844f94e0fb, 0x2eda7444cbfc426e }, // 257
+    { 0xf6019da07f549b2b, 0x7e2a53a146606a49 }, // 258
+    { 0xc4ce17b399107c22, 0xcb550fb4384d21d4 }, // 259
+    { 0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa }, // 260
+    { 0xfbe9141915d7a922, 0x4bf1ff9f0062baa9 }, // 261
+    { 0xc987434744ac874e, 0xa327ffb266b56221 }, // 262
+    { 0xa139029f6a239f72, 0x1c1fffc1ebc44e81 }, // 263
+    { 0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a }, // 264
+    { 0xce5d73ff402d98e3, 0xfb0a3d212dc81290 }, // 265
+    { 0xa5178fff668ae0b6, 0x626e974dbe39a873 }, // 266
+    { 0x8412d9991ed58091, 0xe858790afe9486c3 }, // 267
+    { 0xd3515c2831559a83, 0x0d5a5b44ca873e04 }, // 268
+    { 0xa90de3535aaae202, 0x711515d0a205cb37 }, // 269
+    { 0x873e4f75e2224e68, 0x5a7744a6e804a292 }, // 270
+    { 0xd863b256369d4a40, 0x90bed43e40076a83 }, // 271
+    { 0xad1c8eab5ee43b66, 0xda3243650005eed0 }, // 272
+    { 0x8a7d3eef7f1cfc52, 0x482835ea666b2573 }, // 273
+    { 0xdd95317f31c7fa1d, 0x40405643d711d584 }, // 274
+    { 0xb1442798f49ffb4a, 0x99cd11cfdf41779d }, // 275
+    { 0x8dd01fad907ffc3b, 0xae3da7d97f6792e4 }, // 276
+    { 0xe2e69915b3fff9f9, 0x16c90c8f323f516d }, // 277
+    { 0xb58547448ffffb2d, 0xabd40a0c2832a78b }, // 278
+    { 0x91376c36d99995be, 0x23100809b9c21fa2 }, // 279
+    { 0xe858ad248f5c22c9, 0xd1b3400f8f9cff69 }, // 280
+    { 0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54 }, // 281
+    { 0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa }, // 282
+    { 0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9 }, // 283
+    { 0xbe5691ef416bd60c, 0x23cc986bc656d554 }, // 284
+    { 0x9845418c345644d6, 0x830a13896b78aaaa }, // 285
+    { 0xf3a20279ed56d48a, 0x6b43527578c11110 }, // 286
+    { 0xc2e801fb244576d5, 0x229c41f793cda740 }, // 287
+    { 0x9becce62836ac577, 0x4ee367f9430aec33 }, // 288
+    { 0xf97ae3d0d2446f25, 0x4b0573286b44ad1e }, // 289
+    { 0xc795830d75038c1d, 0xd59df5b9ef6a2418 }, // 290
+    { 0x9faacf3df73609b1, 0x77b191618c54e9ad }, // 291
+    { 0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b }, // 292
+  };
+};
+
+template <typename>
+struct minverse;
+
+// Taken from: https://github.com/cassioneri/teju_jagua.
+template <>
+struct minverse<uint32_t> {
+  static struct {
+    const uint32_t multiplier;
+    const uint32_t bound;
+  } constexpr data[] =
+  {
+    { 0x00000001, 0xffffffff },
+    { 0xcccccccd, 0x33333333 },
+    { 0xc28f5c29, 0x0a3d70a3 },
+    { 0x26e978d5, 0x020c49ba },
+    { 0x3afb7e91, 0x0068db8b },
+    { 0x0bcbe61d, 0x0014f8b5 },
+    { 0x68c26139, 0x000431bd },
+    { 0xae8d46a5, 0x0000d6bf },
+    { 0x22e90e21, 0x00002af3 },
+    { 0x3a2e9c6d, 0x00000897 },
+    { 0x3ed61f49, 0x000001b7 },
+    { 0x0c913975, 0x00000057 },
+    { 0xcf503eb1, 0x00000011 },
+    { 0xf6433fbd, 0x00000003 },
+  };
+};
+
+} // namespace <anonymous>
+
+#endif // _GLIBCXX_FLOATING_TO_CHARS_TABLES_H