Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 08:19:37

0001 // Copyright 2020-2022 Junekey Jeon
0002 //
0003 // The contents of this file may be used under the terms of
0004 // the Apache License v2.0 with LLVM Exceptions.
0005 //
0006 //    (See accompanying file LICENSE-Apache or copy at
0007 //     https://llvm.org/foundation/relicensing/LICENSE.txt)
0008 //
0009 // Alternatively, the contents of this file may be used under the terms of
0010 // the Boost Software License, Version 1.0.
0011 //    (See accompanying file LICENSE-Boost or copy at
0012 //     https://www.boost.org/LICENSE_1_0.txt)
0013 //
0014 // Unless required by applicable law or agreed to in writing, this software
0015 // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0016 // KIND, either express or implied.
0017 //
0018 // Some parts are copied from Dragonbox project.
0019 //
0020 // Copyright 2023 Matt Borland
0021 // Distributed under the Boost Software License, Version 1.0.
0022 // https://www.boost.org/LICENSE_1_0.txt
0023 
0024 #ifndef BOOST_CHARCONV_DETAIL_FLOFF
0025 #define BOOST_CHARCONV_DETAIL_FLOFF
0026 
0027 #include <boost/charconv/detail/config.hpp>
0028 #include <boost/charconv/detail/bit_layouts.hpp>
0029 #include <boost/charconv/detail/emulated128.hpp>
0030 #include <boost/charconv/detail/dragonbox/dragonbox_common.hpp>
0031 #include <boost/charconv/detail/to_chars_result.hpp>
0032 #include <boost/charconv/chars_format.hpp>
0033 #include <boost/core/bit.hpp>
0034 #include <type_traits>
0035 #include <limits>
0036 #include <cstdint>
0037 #include <cstring>
0038 #include <cstddef>
0039 #include <climits>
0040 
0041 #ifdef BOOST_MSVC
0042 # pragma warning(push)
0043 # pragma warning(disable: 4127) // Extensive use of BOOST_IF_CONSTEXPR emits warnings under C++11 and 14
0044 # pragma warning(disable: 4554) // parentheses are used be warning is still emitted
0045 #endif
0046 
0047 namespace boost { namespace charconv { namespace detail {
0048 
0049 #ifdef BOOST_MSVC
0050 # pragma warning(push)
0051 # pragma warning(disable: 4702) // use of BOOST_IF_CONSTEXPR can result in unreachable code if max_blocks is 3
0052                                 // Other older compilers will emit warnings if the unreachable code is wrapped
0053                                 // in an else block (e.g. no return statment)
0054 #endif
0055 
0056 template <std::size_t max_blocks>
0057 struct fixed_point_calculator 
0058 {
0059     static_assert(1 < max_blocks, "Max blocks must be greater than 1");
0060 
0061     // Multiply multiplier to the fractional blocks and take the resulting integer part.
0062     // The fractional blocks are updated.
0063     template <typename MultiplierType>
0064     BOOST_FORCEINLINE static MultiplierType generate(MultiplierType multiplier,
0065                                                      std::uint64_t* blocks_ptr,
0066                                                      std::size_t number_of_blocks) noexcept
0067     {
0068         BOOST_CHARCONV_ASSERT(0 < number_of_blocks && number_of_blocks <= max_blocks);
0069 
0070         BOOST_IF_CONSTEXPR (max_blocks == 3)
0071         {
0072             uint128 mul_result;
0073             std::uint64_t carry = 0;
0074 
0075             switch (number_of_blocks) 
0076             {
0077             case 3:
0078                 mul_result = umul128(blocks_ptr[2], multiplier);
0079                 blocks_ptr[2] = mul_result.low;
0080                 carry = mul_result.high;
0081                 BOOST_FALLTHROUGH;
0082 
0083             case 2:
0084                 mul_result = umul128(blocks_ptr[1], multiplier);
0085                 mul_result += carry;
0086                 blocks_ptr[1] = mul_result.low;
0087                 carry = mul_result.high;
0088                 BOOST_FALLTHROUGH;
0089 
0090             case 1:
0091                 mul_result = umul128(blocks_ptr[0], multiplier);
0092                 mul_result += carry;
0093                 blocks_ptr[0] = mul_result.low;
0094                 return mul_result.high;
0095 
0096             default:
0097                 BOOST_UNREACHABLE_RETURN(carry); // NOLINT : Macro for unreachable can expand to be empty
0098             }
0099         }
0100 
0101         auto mul_result = umul128(blocks_ptr[number_of_blocks - 1], multiplier);
0102         blocks_ptr[number_of_blocks - 1] = mul_result.low;
0103         auto carry = mul_result.high;
0104         for (std::size_t i = 1; i < number_of_blocks; ++i) 
0105         {
0106             mul_result = umul128(blocks_ptr[number_of_blocks - i - 1], multiplier);
0107             mul_result += carry;
0108             blocks_ptr[number_of_blocks - i - 1] = mul_result.low;
0109             carry = mul_result.high;
0110         }
0111 
0112         return MultiplierType(carry);
0113     }
0114 
0115     // Multiply multiplier to the fractional blocks and discard the resulting integer part.
0116     // The fractional blocks are updated.
0117     template <typename MultiplierType>
0118     BOOST_FORCEINLINE static void discard_upper(MultiplierType multiplier,
0119                                                 std::uint64_t* blocks_ptr,
0120                                                 std::size_t number_of_blocks) noexcept 
0121     {
0122         BOOST_CHARCONV_ASSERT(0 < number_of_blocks && number_of_blocks <= max_blocks);
0123 
0124         blocks_ptr[0] *= multiplier;
0125         if (number_of_blocks > 1) 
0126         {
0127             BOOST_IF_CONSTEXPR (max_blocks == 3) 
0128             {
0129                 uint128 mul_result;
0130                 std::uint64_t carry = 0;
0131 
0132                 if (number_of_blocks > 2)
0133                 {
0134                     mul_result = umul128(multiplier, blocks_ptr[2]);
0135                     blocks_ptr[2] = mul_result.low;
0136                     carry = mul_result.high;
0137                 }
0138 
0139                 mul_result = umul128(multiplier, blocks_ptr[1]);
0140                 mul_result += carry;
0141                 blocks_ptr[1] = mul_result.low;
0142                 blocks_ptr[0] += mul_result.high;
0143             }
0144             else 
0145             {
0146                 auto mul_result = umul128(multiplier, blocks_ptr[number_of_blocks - 1]);
0147                 blocks_ptr[number_of_blocks - 1] = mul_result.low;
0148                 auto carry = mul_result.high;
0149 
0150                 for (std::size_t i = 2; i < number_of_blocks; ++i)
0151                 {
0152                     mul_result = umul128(multiplier, blocks_ptr[number_of_blocks - i]);
0153                     mul_result += carry;
0154                     blocks_ptr[number_of_blocks - i] = mul_result.low;
0155                     carry = mul_result.high;
0156                 }
0157 
0158                 blocks_ptr[0] += carry;
0159             }
0160         }
0161     }
0162 
0163     // Multiply multiplier to the fractional blocks and take the resulting integer part.
0164     // Don't care about what happens to the fractional blocks.
0165     template <typename MultiplierType>
0166     BOOST_FORCEINLINE static MultiplierType
0167     generate_and_discard_lower(MultiplierType multiplier, std::uint64_t* blocks_ptr,
0168                                 std::size_t number_of_blocks) noexcept 
0169     {
0170         BOOST_CHARCONV_ASSERT(0 < number_of_blocks && number_of_blocks <= max_blocks);
0171 
0172         BOOST_IF_CONSTEXPR (max_blocks == 3) 
0173         {
0174             uint128 mul_result;
0175             std::uint64_t carry = 0;
0176 
0177             switch (number_of_blocks) 
0178             {
0179             case 3:
0180                 mul_result = umul128(blocks_ptr[2], static_cast<std::uint64_t>(multiplier));
0181                 carry = mul_result.high;
0182                 BOOST_FALLTHROUGH;
0183 
0184             case 2:
0185                 mul_result = umul128(blocks_ptr[1], static_cast<std::uint64_t>(multiplier));
0186                 mul_result += carry;
0187                 carry = mul_result.high;
0188                 BOOST_FALLTHROUGH;
0189 
0190             case 1:
0191                 mul_result = umul128(blocks_ptr[0], static_cast<std::uint64_t>(multiplier));
0192                 mul_result += carry;
0193                 return static_cast<MultiplierType>(mul_result.high);
0194 
0195             default:
0196                 BOOST_UNREACHABLE_RETURN(carry); // NOLINT
0197             }
0198         }
0199 
0200         auto mul_result = umul128(blocks_ptr[number_of_blocks - 1], static_cast<std::uint64_t>(multiplier));
0201         auto carry = mul_result.high;
0202         for (std::size_t i = 1; i < number_of_blocks; ++i)
0203         {
0204             mul_result = umul128(blocks_ptr[number_of_blocks - i - 1], static_cast<std::uint64_t>(multiplier));
0205             mul_result += carry;
0206             carry = mul_result.high;
0207         }
0208 
0209         return static_cast<MultiplierType>(carry);
0210     }
0211 };
0212 
0213 #ifdef BOOST_MSVC
0214 # pragma warning(pop)
0215 #endif
0216 
0217 template <bool b>
0218 struct additional_static_data_holder_impl
0219 {
0220     static constexpr char radix_100_table[] = {
0221         '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', //
0222         '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', //
0223         '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', //
0224         '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', //
0225         '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', //
0226         '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', //
0227         '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', //
0228         '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', //
0229         '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', //
0230         '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', //
0231         '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', //
0232         '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', //
0233         '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', //
0234         '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', //
0235         '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', //
0236         '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', //
0237         '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', //
0238         '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', //
0239         '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', //
0240         '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'  //
0241     };
0242 
0243     static constexpr std::uint32_t fractional_part_rounding_thresholds32[] = {
0244         UINT32_C(2576980378), UINT32_C(2190433321), UINT32_C(2151778616), UINT32_C(2147913145),
0245         UINT32_C(2147526598), UINT32_C(2147487943), UINT32_C(2147484078), UINT32_C(2147483691)
0246     };
0247 
0248     static constexpr std::uint64_t fractional_part_rounding_thresholds64[] = {
0249         UINT64_C(11068046444225730970), UINT64_C(9407839477591871325), UINT64_C(9241818780928485360),
0250         UINT64_C(9225216711262146764),  UINT64_C(9223556504295512904), UINT64_C(9223390483598849518),
0251         UINT64_C(9223373881529183179),  UINT64_C(9223372221322216546), UINT64_C(9223372055301519882),
0252         UINT64_C(9223372038699450216),  UINT64_C(9223372037039243249), UINT64_C(9223372036873222553),
0253         UINT64_C(9223372036856620483),  UINT64_C(9223372036854960276), UINT64_C(9223372036854794255),
0254         UINT64_C(9223372036854777653),  UINT64_C(9223372036854775993), UINT64_C(9223372036854775827)
0255     };
0256 };
0257 
0258 #if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900)
0259 
0260 template <bool b> constexpr char additional_static_data_holder_impl<b>::radix_100_table[];
0261 template <bool b> constexpr std::uint32_t additional_static_data_holder_impl<b>::fractional_part_rounding_thresholds32[];
0262 template <bool b> constexpr std::uint64_t additional_static_data_holder_impl<b>::fractional_part_rounding_thresholds64[];
0263 
0264 #endif
0265 
0266 using additional_static_data_holder = additional_static_data_holder_impl<true>;
0267 
0268 struct compute_mul_result 
0269 {
0270     std::uint64_t result;
0271     bool is_integer;
0272 };
0273 
0274 // Load the necessary bits into blocks_ptr and then return the number of cache blocks
0275 // loaded. The most significant block is loaded into blocks_ptr[0].
0276 template <typename ExtendedCache, bool zero_out, 
0277           typename CacheBlockType = typename std::decay<decltype(ExtendedCache::cache[0])>::type,
0278           typename std::enable_if<(ExtendedCache::constant_block_count), bool>::type = true>
0279 inline std::uint8_t cache_block_count_helper(CacheBlockType*, int, int, std::uint32_t) noexcept 
0280 {
0281     return static_cast<std::uint8_t>(ExtendedCache::max_cache_blocks);
0282 }
0283 
0284 template <typename ExtendedCache, bool zero_out,
0285           typename CacheBlockType = typename std::decay<decltype(ExtendedCache::cache[0])>::type,
0286           typename std::enable_if<!(ExtendedCache::constant_block_count), bool>::type = true>
0287 inline std::uint8_t cache_block_count_helper(CacheBlockType*, int e, int, std::uint32_t multiplier_index) noexcept 
0288 {
0289     const auto mul_info = ExtendedCache::multiplier_index_info_table[multiplier_index];
0290 
0291     const auto cache_block_count_index =
0292                 mul_info.cache_block_count_index_offset +
0293                 static_cast<std::uint32_t>(e - ExtendedCache::e_min) / ExtendedCache::collapse_factor -
0294                 ExtendedCache::cache_block_count_offset_base;
0295 
0296     BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks < 3)
0297     {
0298         // 1-bit packing.
0299         return static_cast<std::uint8_t>(
0300                     (ExtendedCache::cache_block_counts[cache_block_count_index /
0301                                                         8] >>
0302                     (cache_block_count_index % 8)) &
0303                     0x1) +
0304                 1;
0305     }
0306     else BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks < 4)
0307     {
0308         // 2-bit packing.
0309         return static_cast<std::uint8_t>(
0310             (ExtendedCache::cache_block_counts[cache_block_count_index / 4] >>
0311                 (2 * (cache_block_count_index % 4))) &
0312             0x3);
0313     }
0314     else 
0315     {
0316         // 4-bit packing.
0317         return std::uint8_t(
0318             (ExtendedCache::cache_block_counts[cache_block_count_index / 2] >>
0319                 (4 * (cache_block_count_index % 2))) &
0320             0xf);
0321     }
0322 }
0323 
0324 template <typename ExtendedCache, bool zero_out,
0325           typename CacheBlockType = typename std::decay<decltype(ExtendedCache::cache[0])>::type>
0326 BOOST_FORCEINLINE std::uint8_t load_extended_cache(CacheBlockType* blocks_ptr, int e, int k,
0327                                                    std::uint32_t multiplier_index) noexcept 
0328 {
0329     BOOST_IF_CONSTEXPR (zero_out)
0330     {
0331         std::memset(blocks_ptr, 0, sizeof(CacheBlockType) * ExtendedCache::max_cache_blocks);
0332     }
0333 
0334     const auto mul_info = ExtendedCache::multiplier_index_info_table[multiplier_index];
0335 
0336     std::uint32_t number_of_leading_zero_blocks;
0337     std::uint32_t first_cache_block_index;
0338     std::uint32_t bit_offset;
0339     std::uint32_t excessive_bits_to_left;
0340     std::uint32_t excessive_bits_to_right;
0341     std::uint8_t  cache_block_count = cache_block_count_helper<ExtendedCache, zero_out, CacheBlockType>(blocks_ptr, e, k, multiplier_index);
0342 
0343     // The request window starting/ending positions.
0344     auto start_bit_index = static_cast<int>(mul_info.cache_bit_index_offset) + e - ExtendedCache::cache_bit_index_offset_base;
0345     auto end_bit_index = start_bit_index + cache_block_count * static_cast<int>(ExtendedCache::cache_bits_unit);
0346 
0347     // The source window starting/ending positions.
0348     const auto src_start_bit_index = static_cast<int>(mul_info.first_cache_bit_index);
0349     const auto src_end_bit_index = static_cast<int>(ExtendedCache::multiplier_index_info_table[multiplier_index + 1].first_cache_bit_index);
0350 
0351     // If the request window goes further than the left boundary of the source window,
0352     if (start_bit_index < src_start_bit_index)
0353     {
0354         number_of_leading_zero_blocks =
0355             static_cast<std::uint32_t>(src_start_bit_index - start_bit_index) /
0356             static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit);
0357         excessive_bits_to_left = static_cast<std::uint32_t>(src_start_bit_index - start_bit_index) %
0358                                     static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit);
0359 
0360         BOOST_IF_CONSTEXPR (!zero_out)
0361         {
0362             std::memset(blocks_ptr, 0, number_of_leading_zero_blocks * sizeof(CacheBlockType));
0363         }
0364 
0365         start_bit_index += static_cast<int>(number_of_leading_zero_blocks * ExtendedCache::cache_bits_unit);
0366 
0367         const auto src_start_block_index =
0368             static_cast<int>(static_cast<std::uint32_t>(src_start_bit_index) /
0369                 static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit));
0370         
0371         const auto src_start_block_bit_index =
0372             src_start_block_index * static_cast<int>(ExtendedCache::cache_bits_unit);
0373 
0374         first_cache_block_index = static_cast<std::uint32_t>(src_start_block_index);
0375 
0376         if (start_bit_index < src_start_block_bit_index)
0377         {
0378             auto shift_amount = src_start_block_bit_index - start_bit_index;
0379             BOOST_CHARCONV_ASSERT(shift_amount >= 0 && shift_amount < static_cast<int>(ExtendedCache::cache_bits_unit));
0380 
0381             blocks_ptr[number_of_leading_zero_blocks] =
0382                 ((ExtendedCache::cache[src_start_block_index] >> shift_amount) &
0383                     (CacheBlockType(CacheBlockType(0) - CacheBlockType(1)) >>
0384                     excessive_bits_to_left));
0385 
0386             ++number_of_leading_zero_blocks;
0387             bit_offset = static_cast<std::uint32_t>(static_cast<int>(ExtendedCache::cache_bits_unit) - shift_amount);
0388             excessive_bits_to_left = 0;
0389         }
0390         else 
0391         {
0392             bit_offset = static_cast<std::uint32_t>(start_bit_index - src_start_block_bit_index);
0393         }
0394     }
0395     else 
0396     {
0397         number_of_leading_zero_blocks = 0;
0398         first_cache_block_index =
0399             static_cast<std::uint32_t>(start_bit_index) / static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit);
0400         bit_offset =
0401             static_cast<std::uint32_t>(start_bit_index) % static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit);
0402         excessive_bits_to_left = 0;
0403     }
0404 
0405     // If the request window goes further than the right boundary of the source window,
0406     if (end_bit_index > src_end_bit_index)
0407     {
0408         const std::uint8_t number_of_trailing_zero_blocks =
0409             static_cast<std::uint8_t>(end_bit_index - src_end_bit_index) / ExtendedCache::cache_bits_unit;
0410         excessive_bits_to_right = static_cast<std::uint32_t>(end_bit_index - src_end_bit_index) %
0411                                     static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit);
0412 
0413         cache_block_count -= number_of_trailing_zero_blocks;
0414     }
0415     else
0416     {
0417         excessive_bits_to_right = 0;
0418     }
0419 
0420     // Load blocks.
0421     const auto number_of_blocks_to_load = cache_block_count - number_of_leading_zero_blocks;
0422     auto* const dst_ptr = blocks_ptr + number_of_leading_zero_blocks;
0423     if (bit_offset == 0)
0424     {
0425         BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks == 3)
0426         {
0427             switch (number_of_blocks_to_load)
0428             {
0429             case 3:
0430                 std::memcpy(dst_ptr, ExtendedCache::cache + first_cache_block_index, 3 * sizeof(CacheBlockType));
0431                 break;
0432             case 2:
0433                 std::memcpy(dst_ptr, ExtendedCache::cache + first_cache_block_index, 2 * sizeof(CacheBlockType));
0434                 break;
0435             case 1:
0436                 std::memcpy(dst_ptr, ExtendedCache::cache + first_cache_block_index, 1 * sizeof(CacheBlockType));
0437                 break;
0438             case 0:
0439                 break;
0440             default:
0441                 BOOST_UNREACHABLE_RETURN(dst_ptr); // NOLINT
0442             }
0443         }
0444         else 
0445         {
0446             std::memcpy(dst_ptr, ExtendedCache::cache + first_cache_block_index, number_of_blocks_to_load * sizeof(CacheBlockType));
0447         }
0448     }
0449     else 
0450     {
0451         BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks == 3)
0452         {
0453             switch (number_of_blocks_to_load)
0454             {
0455             case 3:
0456                 *(dst_ptr + 2) =
0457                     (ExtendedCache::cache[first_cache_block_index + 2] << bit_offset) |
0458                     (ExtendedCache::cache[first_cache_block_index + 3] >>
0459                         (ExtendedCache::cache_bits_unit - bit_offset));
0460                 BOOST_FALLTHROUGH;
0461             case 2:
0462                 *(dst_ptr + 1) =
0463                     (ExtendedCache::cache[first_cache_block_index + 1] << bit_offset) |
0464                     (ExtendedCache::cache[first_cache_block_index + 2] >>
0465                         (ExtendedCache::cache_bits_unit - bit_offset));
0466                 BOOST_FALLTHROUGH;
0467             case 1:
0468                 *dst_ptr = (ExtendedCache::cache[first_cache_block_index] << bit_offset) |
0469                             (ExtendedCache::cache[first_cache_block_index + 1] >>
0470                             (ExtendedCache::cache_bits_unit - bit_offset));
0471             case 0:
0472                 break;
0473             default:
0474                 BOOST_UNREACHABLE_RETURN(dst_ptr); // NOLINT
0475             }
0476         }
0477         else 
0478         {
0479             for (std::uint8_t i = 0; i < number_of_blocks_to_load; ++i)
0480             {
0481                 *(dst_ptr + i) =
0482                     (ExtendedCache::cache[first_cache_block_index + i] << bit_offset) |
0483                     (ExtendedCache::cache[first_cache_block_index + i + 1] >>
0484                         (ExtendedCache::cache_bits_unit - bit_offset));
0485             }
0486         }
0487     }
0488     
0489     // Remove possible flooding bits from adjacent entries.
0490     *dst_ptr &= (CacheBlockType(CacheBlockType(0) - CacheBlockType(1)) >> excessive_bits_to_left);
0491 
0492     blocks_ptr[cache_block_count - 1] &= (CacheBlockType(CacheBlockType(0) - CacheBlockType(1)) << excessive_bits_to_right);
0493 
0494     // To compute ceil(2^Q * x / D), we need to check if
0495     // 2^Q * x / D = 2^(Q + e + k - eta - 1) * 5^(k - eta) is an integer or not.
0496     if (k < ExtendedCache::segment_length ||
0497         e + k + static_cast<int>(cache_block_count * ExtendedCache::cache_bits_unit) -
0498                 static_cast<int>(excessive_bits_to_right) <
0499             ExtendedCache::segment_length + 1) {
0500         blocks_ptr[cache_block_count - 1] += (CacheBlockType(1) << excessive_bits_to_right);
0501         BOOST_CHARCONV_ASSERT(blocks_ptr[cache_block_count - 1] != 0);
0502     }
0503 
0504     return cache_block_count;
0505 }
0506 
0507 template <bool constant_block_count, std::uint8_t max_cache_blocks>
0508 struct cache_block_count_t;
0509 
0510 template <std::uint8_t max_cache_blocks>
0511 struct cache_block_count_t<false, max_cache_blocks>
0512 {
0513     std::uint8_t value;
0514     
0515     operator std::uint8_t() const noexcept { return value; } // NOLINT : implicit conversions are ok for block count
0516     cache_block_count_t& operator=(std::uint8_t new_value) noexcept
0517     {
0518         value = new_value;
0519         return *this;
0520     }
0521 };
0522 
0523 template <std::uint8_t max_cache_blocks>
0524 struct cache_block_count_t<true, max_cache_blocks>
0525 {
0526     static constexpr std::uint8_t value = max_cache_blocks;
0527     operator std::uint8_t() const noexcept { return value; } // NOLINT : implicit conversions are ok for block count
0528     cache_block_count_t& operator=(std::uint8_t) noexcept
0529     {
0530         // Don't do anything.
0531         return *this;
0532     }
0533 };
0534 
0535 template <unsigned n>
0536 struct uconst
0537 {
0538     constexpr uconst() {}; // NOLINT : Clang 3.x does not support = default
0539     static constexpr unsigned value = n;
0540 };
0541 
0542 BOOST_INLINE_VARIABLE constexpr uconst<0>  uconst0;
0543 BOOST_INLINE_VARIABLE constexpr uconst<1>  uconst1;
0544 BOOST_INLINE_VARIABLE constexpr uconst<6>  uconst6;
0545 BOOST_INLINE_VARIABLE constexpr uconst<9>  uconst9;
0546 BOOST_INLINE_VARIABLE constexpr uconst<14> uconst14;
0547 BOOST_INLINE_VARIABLE constexpr uconst<16> uconst16;
0548 
0549 #ifdef __clang__
0550 #  pragma clang diagnostic push
0551 #  pragma clang diagnostic ignored "-Wsign-conversion"
0552 #elif defined(__GNUC__)
0553 #  pragma GCC diagnostic push
0554 #  pragma GCC diagnostic ignored "-Wsign-conversion"
0555 #elif defined(BOOST_MSVC)
0556 #  pragma warning(push)
0557 #  pragma warning(disable: 4365 4267)
0558 #endif
0559 
0560 template <unsigned digits, bool dummy = (digits <= 9)>
0561 struct uint_with_known_number_of_digits;
0562 
0563 template <unsigned digits_>
0564 struct uint_with_known_number_of_digits<digits_, true> 
0565 {
0566     static constexpr auto digits = digits_;
0567     std::uint32_t value;
0568 };
0569 
0570 template <unsigned digits_>
0571 struct uint_with_known_number_of_digits<digits_, false>
0572 {
0573     static constexpr auto digits = digits_;
0574     std::uint64_t value;
0575 };
0576 
0577 template <typename HasFurtherDigits, typename... Args, typename std::enable_if<std::is_same<HasFurtherDigits, bool>::value, bool>::type = true>
0578 static BOOST_FORCEINLINE bool check_rounding_condition_inside_subsegment(
0579     std::uint32_t current_digits, std::uint32_t fractional_part,
0580     int remaining_digits_in_the_current_subsegment, HasFurtherDigits has_further_digits,
0581     Args...) noexcept 
0582 {
0583     if (fractional_part >= additional_static_data_holder::fractional_part_rounding_thresholds32[remaining_digits_in_the_current_subsegment - 1])
0584     {
0585         return true;
0586     }
0587 
0588     return ((fractional_part >> 31) & ((current_digits & 1) | has_further_digits)) != 0;
0589 }
0590 
0591 template <typename HasFurtherDigits, typename... Args,
0592           typename std::enable_if<!std::is_same<HasFurtherDigits, bool>::value, bool>::type = true>
0593 static BOOST_FORCEINLINE bool check_rounding_condition_inside_subsegment(
0594     std::uint32_t current_digits, std::uint32_t fractional_part,
0595     int remaining_digits_in_the_current_subsegment, HasFurtherDigits has_further_digits,
0596     Args... args) noexcept 
0597 {
0598     if (fractional_part >= additional_static_data_holder::fractional_part_rounding_thresholds32[remaining_digits_in_the_current_subsegment - 1]) 
0599     {
0600         return true;
0601     }
0602     
0603     return fractional_part >= 0x80000000 && ((current_digits & 1) != 0 || has_further_digits(args...));
0604 }
0605 
0606 template <typename HasFurtherDigits, typename... Args,
0607           typename std::enable_if<std::is_same<HasFurtherDigits, bool>::value, bool>::type = true>
0608 static BOOST_FORCEINLINE bool check_rounding_condition_with_next_bit(std::uint32_t current_digits, bool next_bit,
0609                                                                      HasFurtherDigits has_further_digits, Args...) noexcept 
0610 {
0611     if (!next_bit) 
0612     {
0613         return false;
0614     }
0615 
0616     return ((current_digits & 1) | has_further_digits) != 0;
0617 }
0618 
0619 template <typename HasFurtherDigits, typename... Args,
0620           typename std::enable_if<!std::is_same<HasFurtherDigits, bool>::value, bool>::type = true>
0621 static BOOST_FORCEINLINE bool check_rounding_condition_with_next_bit(std::uint32_t current_digits, bool next_bit,
0622                                                                      HasFurtherDigits has_further_digits, Args... args) noexcept 
0623 {
0624     if (!next_bit) 
0625     {
0626         return false;
0627     }
0628 
0629     return (current_digits & 1) != 0 || has_further_digits(args...);
0630 }
0631 
0632 template <typename UintWithKnownDigits, typename HasFurtherDigits, typename... Args, 
0633           typename std::enable_if<std::is_same<HasFurtherDigits, bool>::value, bool>::type = true>
0634 static BOOST_FORCEINLINE bool check_rounding_condition_subsegment_boundary_with_next_subsegment(
0635     std::uint32_t current_digits, UintWithKnownDigits next_subsegment,
0636     HasFurtherDigits has_further_digits, Args...) noexcept 
0637 {
0638     if (next_subsegment.value > power_of_10[decltype(next_subsegment)::digits] / 2)
0639     {
0640         return true;
0641     }
0642 
0643     return next_subsegment.value == power_of_10[decltype(next_subsegment)::digits] / 2 && 
0644                                     ((current_digits & 1) | has_further_digits) != 0;
0645 }
0646 
0647 template <typename UintWithKnownDigits, typename HasFurtherDigits, typename... Args, 
0648           typename std::enable_if<!std::is_same<HasFurtherDigits, bool>::value, bool>::type = true>
0649 static BOOST_FORCEINLINE bool check_rounding_condition_subsegment_boundary_with_next_subsegment(
0650     std::uint32_t current_digits, UintWithKnownDigits next_subsegment,
0651     HasFurtherDigits has_further_digits, Args... args) noexcept 
0652 {
0653     if (next_subsegment.value > power_of_10[decltype(next_subsegment)::digits] / 2) 
0654     {
0655         return true;
0656     }
0657 
0658     return next_subsegment.value == power_of_10[decltype(next_subsegment)::digits] / 2 &&
0659                                     ((current_digits & 1) != 0 || has_further_digits(args...));
0660 }
0661 
0662 #ifdef __clang__
0663 #  pragma clang diagnostic pop
0664 #elif defined(__GNUC__)
0665 #  pragma GCC diagnostic pop
0666 #elif defined(BOOST_MSVC)
0667 #  pragma warning(pop)
0668 #endif
0669 
0670 #ifdef BOOST_MSVC
0671 # pragma warning(push)
0672 # pragma warning(disable: 4307) // MSVC 14.1 emits warnings for uint64_t constants
0673 #endif
0674 
0675 namespace has_further_digits_impl {
0676 template <int k_right_threshold, int additional_neg_exp_of_2>
0677 bool no_neg_k_can_be_integer(int k, int exp2_base) noexcept 
0678 {
0679     return k < k_right_threshold || exp2_base + k < additional_neg_exp_of_2;
0680 }
0681 
0682 template <int k_left_threshold, int k_right_threshold, int additional_neg_exp_of_2, int min_neg_exp_of_5, typename SignificandType>
0683 bool only_one_neg_k_can_be_integer(int k, int exp2_base, SignificandType significand) noexcept
0684 {
0685     // Supposed to be k - additional_neg_exp_of_5_v < -min_neg_exp_of_5 || ...
0686     if (k < k_left_threshold || exp2_base + k < additional_neg_exp_of_2) 
0687     {
0688         return true;
0689     }
0690     // Supposed to be k - additional_neg_exp_of_5_v >= 0.
0691     if (k >= k_right_threshold) 
0692     {
0693         return false;
0694     }
0695 
0696     BOOST_CXX14_CONSTEXPR std::uint64_t mod_inv = compute_power(UINT64_C(0xcccccccccccccccd), static_cast<unsigned>(min_neg_exp_of_5));
0697     BOOST_CXX14_CONSTEXPR std::uint64_t max_quot = UINT64_C(0xffffffffffffffff) / compute_power(UINT64_C(5), static_cast<unsigned>(min_neg_exp_of_5));
0698 
0699     return (significand * mod_inv) > max_quot;
0700 }
0701 
0702 template <int k_left_threshold, int k_middle_threshold, int k_right_threshold,
0703             int additional_neg_exp_of_2, int min_neg_exp_of_5, int segment_length,
0704             typename SignificandType>
0705 bool only_two_neg_k_can_be_integer(int k, int exp2_base,
0706                                     SignificandType significand) noexcept {
0707     // Supposed to be k - additional_neg_exp_of_5_v < -min_neg_exp_of_5 - segment_length
0708     // || ...
0709     if (k < k_left_threshold || exp2_base + k < additional_neg_exp_of_2) {
0710         return true;
0711     }
0712     // Supposed to be k - additional_neg_exp_of_5_v >= 0.
0713     if (k >= k_right_threshold) {
0714         return false;
0715     }
0716 
0717     if (k >= k_middle_threshold) {
0718         BOOST_CXX14_CONSTEXPR std::uint64_t mod_inv =
0719             compute_power(UINT64_C(0xcccccccccccccccd), static_cast<unsigned>(min_neg_exp_of_5));
0720         BOOST_CXX14_CONSTEXPR std::uint64_t max_quot =
0721             UINT64_C(0xffffffffffffffff) /
0722             compute_power(UINT64_C(5), static_cast<unsigned>(min_neg_exp_of_5));
0723 
0724         return (significand * mod_inv) > max_quot;
0725     }
0726     else {
0727         BOOST_CXX14_CONSTEXPR std::uint64_t mod_inv = compute_power(
0728             UINT64_C(0xcccccccccccccccd), static_cast<unsigned>(min_neg_exp_of_5 + segment_length));
0729         BOOST_CXX14_CONSTEXPR std::uint64_t max_quot =
0730             UINT64_C(0xffffffffffffffff) /
0731             compute_power(UINT64_C(5),
0732                             static_cast<unsigned>(min_neg_exp_of_5 + segment_length));
0733 
0734         return (significand * mod_inv) > max_quot;
0735     }
0736 }
0737 } // Namespace has_further_digits_impl
0738 
0739 #ifdef BOOST_MSVC
0740 #pragma warning(pop)
0741 #endif
0742 
0743 inline void print_1_digit(std::uint32_t n, char* buffer) noexcept 
0744 {
0745     *buffer = char('0' + n);
0746 }
0747 
0748 inline void print_2_digits(std::uint32_t n, char* buffer) noexcept
0749 {
0750     std::memcpy(buffer, additional_static_data_holder::radix_100_table + n * 2, 2);
0751 }
0752 
0753 inline void print_6_digits(std::uint32_t n, char* buffer) noexcept 
0754 {
0755     // 429497 = ceil(2^32/10^4)
0756     auto prod = (n * UINT64_C(429497)) + 1;
0757     print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
0758     
0759     for (int i = 0; i < 2; ++i) 
0760     {
0761         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
0762         print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer + 2 + i * 2);
0763     }
0764 }
0765 
0766 inline void print_7_digits(std::uint32_t n, char* buffer) noexcept 
0767 {
0768     // 17592187 = ceil(2^(32+12)/10^6)
0769     auto prod = ((n * UINT64_C(17592187)) >> 12) + 1;
0770     print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
0771     
0772     for (int i = 0; i < 3; ++i)
0773     {
0774         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
0775         print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer + 1 + i * 2);
0776     }
0777 }
0778 
0779 inline void print_8_digits(std::uint32_t n, char* buffer) noexcept
0780 {
0781     // 140737489 = ceil(2^(32+15)/10^6)
0782     auto prod = ((n * UINT64_C(140737489)) >> 15) + 1;
0783     print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
0784     
0785     for (int i = 0; i < 3; ++i) 
0786     {
0787         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
0788         print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer + 2 + i * 2);
0789     }
0790 }
0791 
0792 inline void print_9_digits(std::uint32_t n, char* buffer) noexcept
0793 {
0794     // 1441151881 = ceil(2^(32+25)/10^8)
0795     auto prod = ((n * UINT64_C(1441151881)) >> 25) + 1;
0796     print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
0797     
0798     for (int i = 0; i < 4; ++i) 
0799     {
0800         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
0801         print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer + 1 + i * 2);
0802     }
0803 }
0804 
0805 struct main_cache_full 
0806 {
0807     template <typename FloatFormat>
0808     static constexpr typename main_cache_holder::cache_entry_type get_cache(int k) noexcept
0809     {
0810         return main_cache_holder::cache[std::size_t(k - main_cache_holder::min_k)];
0811     }
0812 };
0813 
0814 struct main_cache_compressed 
0815 {
0816     template <typename FloatFormat>
0817     static BOOST_CHARCONV_CXX14_CONSTEXPR typename main_cache_holder::cache_entry_type get_cache(int k) noexcept
0818     {
0819         BOOST_CHARCONV_ASSERT(k >= main_cache_holder::min_k && k <= main_cache_holder::max_k);
0820 
0821         BOOST_IF_CONSTEXPR (std::is_same<FloatFormat, ieee754_binary64>::value) 
0822         {
0823             // Compute the base index.
0824             const auto cache_index =
0825                 static_cast<int>(static_cast<std::uint32_t>(k - main_cache_holder::min_k) /
0826                     compressed_cache_detail::compression_ratio);
0827 
0828             const auto kb = cache_index * compressed_cache_detail::compression_ratio +
0829                             main_cache_holder::min_k;
0830 
0831             const auto offset = k - kb;
0832 
0833             // Get the base cache.
0834             const auto base_cache = compressed_cache_detail::cache_holder_t::table[cache_index];
0835 
0836             if (offset == 0)
0837             {
0838                 return base_cache;
0839             }
0840             else 
0841             {
0842 
0843                 // Compute the required amount of bit-shift.
0844                 const auto alpha = log::floor_log2_pow10(kb + offset) - log::floor_log2_pow10(kb) - offset;
0845                 BOOST_CHARCONV_ASSERT(alpha > 0 && alpha < 64);
0846 
0847                 // Try to recover the real cache.
0848                 const auto pow5 = compressed_cache_detail::pow5_holder_t::table[offset];
0849                 auto recovered_cache = umul128(base_cache.high, pow5);
0850                 const auto middle_low = umul128(base_cache.low, pow5);
0851 
0852                 recovered_cache += middle_low.high;
0853 
0854                 const auto high_to_middle = recovered_cache.high << (64 - alpha);
0855                 const auto middle_to_low = recovered_cache.low << (64 - alpha);
0856 
0857                 recovered_cache = uint128{(recovered_cache.low >> alpha) | high_to_middle, ((middle_low.low >> alpha) | middle_to_low)};
0858 
0859                 BOOST_CHARCONV_ASSERT(recovered_cache.low + 1 != 0);
0860                 recovered_cache = uint128(recovered_cache.high, recovered_cache.low + 1);
0861 
0862                 return recovered_cache;
0863             }
0864         }
0865         else
0866         {
0867             // Just use the full cache for anything other than binary64
0868             return main_cache_holder::cache[std::size_t(k - main_cache_holder::min_k)];
0869         }
0870     }
0871 };
0872 
0873 template <bool b>
0874 struct extended_cache_long_impl
0875 {
0876     static constexpr std::size_t max_cache_blocks = 3;
0877     static constexpr std::size_t cache_bits_unit = 64;
0878     static constexpr int segment_length = 22;
0879     static constexpr bool constant_block_count = true;
0880     static constexpr int e_min = -1074;
0881     static constexpr int k_min = -272;
0882     static constexpr int cache_bit_index_offset_base = 977;
0883     static constexpr std::uint64_t cache[] = {
0884         0xa37fce126597973c, 0xe50ff107bab528a0, 0x8f1ba3f17395a391, 0xd56bdc876cdb4648,
0885         0x6ca000bdd9e33bd4, 0x23cf34bbf983f78b, 0x8737d87296e93f5d, 0xa2824ba6d9df301d,
0886         0x8ce3eccf7cfb42ab, 0xe5ecdc0b78109f00, 0xa620c9995c9c5c3a, 0xa0f79c97ac210943,
0887         0x64dfb5636985915f, 0xc12f542e4c7ea6ee, 0x34de81232784ea17, 0xd0cbde7fac4643f2,
0888         0x5d9400de8fef7552, 0x81214f68696d9af2, 0xb7d0e0a2ccaccf20, 0x5c4ed9243f16193d,
0889         0xf71838486e60b926, 0x48892047ec1a8bf4, 0x14ff2faa9c32befa, 0x666fbaa24ddbb8e9,
0890         0x436682c807652a58, 0xed98ddaee19068c7, 0x63badd624dd9b095, 0x72dbb637d5b77493,
0891         0xd01998fb8d9e8861, 0xacb39418dce017b9, 0x8db8f2f13eed81cf, 0xfd699fbb7d0a737a,
0892         0x011cd67160923d91, 0x9a66fd7732c14d98, 0x235857d065a52d18, 0x895288951dab0d8e,
0893         0x59041cb66e4f0e68, 0x5e7c68240249e750, 0x8881a2a6ab00987b, 0x5fc8c32c863aaeac,
0894         0x3bafbe662a7f81a8, 0xd47692705ae76b64, 0xeb1cc7d99143fb53, 0xcf8be24f7b0fc499,
0895         0x6a276e8f0fbf33eb, 0x63b2d61966fa7243, 0x0970327d2cc58011, 0x43ff09410ec24aae,
0896         0x0bdb6f345ea1851d, 0x409c37132c5836ff, 0xf3150f74a6190324, 0x5c358d6c07453d23,
0897         0x7207012ad7846ba7, 0x61ad5d0772604733, 0x19a20a6e21c2018d, 0x5f568fd497ef18b2,
0898         0xeda5815eed00749f, 0x029531461bc483d8, 0xb8789d7784875911, 0x6fc40572236f2ba5,
0899         0x9c2a50a76ace3168, 0xbf4815c2bea56741, 0xf84e8f2fe9b211f5, 0x689033182d2ea7ed,
0900         0x5bcb3a3230a68f47, 0xa848403d116805ef, 0xfaeaa73623b79604, 0x31d76828d2181b64,
0901         0x7c4eabddc7dd634b, 0xc2b13231eeff6fda, 0x8094743db32bf251, 0x2df07391bde052d2,
0902         0xffd9bdbf321ad8ae, 0x06b2c6d1cf6cf742, 0xf32a54ce1598fe8f, 0x1cc2e3082d28897e,
0903         0x0485f2e46b488584, 0xe3f6965b145a49cb, 0x406eaa1217aefe69, 0x0777373638de456b,
0904         0xcde91853b592212b, 0x3faf7b46d7f79c18, 0x558d83afb7127381, 0x5f490259c7957aeb,
0905         0x76e6540e246d73cc, 0x5098a935a866dc75, 0xc50d9c29002d9e73, 0xcc8f8252faac0b7f,
0906         0xb759afb688f8251d, 0x6a2934d3036c85d3, 0x570eb3ce4c86407f, 0x036f2b68794754af,
0907         0x57661a5d6993fe2c, 0x6d07b7fabe546a80, 0x38efe4029259743c, 0x548f417ebaa61c6c,
0908         0xb0c31fa64a3fcc9e, 0x7dab825964fb7100, 0xd0c92ae8207d6f22, 0xf1e38a8a9c541144,
0909         0x2139951c68d0385b, 0x9d9e22c42f139287, 0x4fea4d670876b800, 0x35f293a9a62252d4,
0910         0x4b606b26f1922c5c, 0x8e5660b37505cb11, 0x868138391855da81, 0x6e95f6c9b45c7aa2,
0911         0x425ff75e14fc31a1, 0x258379a94d028d18, 0xdf2ccd1fe00a03b6, 0x398471c1ff970f83,
0912         0x8c36b2214a3db8e7, 0x431dd42c3fe7f4fb, 0xb09bcf0fffb5b849, 0xc47dd13da60fb5a1,
0913         0x8fdad56516fe9d75, 0xc317e1025a7e1c63, 0x9ddcb98cbb384fda, 0x80adccda993bf70e,
0914         0x667f1622e4052ae4, 0xa41598d58f777363, 0x704b93d675808501, 0xaf046d3fd448aaf3,
0915         0x1dc4611873bf3f70, 0x834acdae9f0f4f53, 0x4f5d60585a5f1c1a, 0x3ced1b4be0d415c1,
0916         0x5d57f4de8ec12376, 0x51c0e7e72f799542, 0x46f7604940e6a510, 0x1a546a0f9345ed75,
0917         0x0df4097cab773ca2, 0x72b122774e4029e6, 0xae4a55b99aebd424, 0x04163a291bad2fa3,
0918         0x86ad58be322a49aa, 0x98f051614696e839, 0x64d08f241fc4ec58, 0xae41f23dca90dd5d,
0919         0x68bbd62f5af3107a, 0x7025f39ef241c56c, 0xd2e7c72fa9be33ac, 0x0aece66fd3e29a7d,
0920         0xd91241cebf3bd47c, 0x3ed7bfdee19ba2f6, 0x4bdf483194c7444e, 0xc99d83c931e8ab87,
0921         0x1732f416dbf7381f, 0x2ac88e244de13b96, 0x2cab688bd86c8bf8, 0x9f209787bb47d6b8,
0922         0x4c0678c5dbd23a49, 0xa0612c3c5ce15e55, 0x4dccc6ca29b3e9df, 0x0dc079c918022212,
0923         0x26be55a64c249495, 0x4da2c9789dd268b0, 0xe975528c76435158, 0xa6cb8a4d2356f9cf,
0924         0xdcafd2279c77d987, 0xaa9aff7904228690, 0xfb44d2f05d0842fb, 0x118fc9c217a1d2b2,
0925         0x04b3d9686f55b572, 0xbd9cb3625ef1cfc3, 0x2eba0e25e938e6c3, 0x1f48eaf234ad3a21,
0926         0xf2dc02fad2890f79, 0xace340325d4a7f9b, 0xe9e051f540b239dc, 0x221091f05abb8687,
0927         0x7e08deb014db8afe, 0x4711e1e9d9a094cc, 0x0b2d79bd90a9ef61, 0xb93d19bd45b82515,
0928         0x45e9e31d63c1afe1, 0x2c5f0a596005c216, 0xe687cc2331b14a12, 0x51963a2412b6f60c,
0929         0x91aeb77c8fe68eaa, 0xd6e18e8cc6841d68, 0x9391085cc2c933d9, 0x6e184be07e68df49,
0930         0x4fe4e52edb0dce60, 0x6cda31e8617f0ca2, 0xf8b9374fda7e7c95, 0x8032c603725e774d,
0931         0x222b6aa27e007612, 0xf7b7f47cf096afad, 0xe6a9fbafee77e77a, 0x3776ee406e63fbaa,
0932         0xde147932fcf78be6, 0x2ab9e031ffaa071e, 0x2169ad0e8a9b1256, 0xe33358135938b76a,
0933         0xcaec07e7a5373835, 0xef2863090a97c3ec, 0x6ccfb95f69c3adcc, 0x173e00da427cee4b,
0934         0x20f4ed58fcfb3040, 0x16f6fb326a60c32c, 0x2968fa04270ed545, 0x70673adfac0eabc4,
0935         0x6ff3c9364ff4e873, 0xde09ed35f13325d3, 0x2396e863b18c500f, 0xe22d253cc031e3ff,
0936         0x756d97a61247798d, 0xc9fc8d937e43c880, 0x0759ba59c08e14c7, 0xcd7aad86a4a45810,
0937         0x9f91c21c571dbe84, 0xd52d936f44abe8a3, 0xd5b48c100959d9d0, 0xb6cc856b3adc93b6,
0938         0x7aea8f8e067d2c8d, 0x04bc177f7b4287a6, 0xe3fcda36fa3b3342, 0xeaeb442e15d45095,
0939         0x2f4dd1ca5e89b18b, 0x602368385bb19cb1, 0x4bdfc434d3028181, 0x0b5a92cb80ac8150,
0940         0xb95953a97b1578ab, 0x46e6a18b01781b92, 0xdfd31585f38d7433, 0x0b1084b96009370b,
0941         0x9a81808e52462ba3, 0xff83368ace4af235, 0xb4e5d8a647e05e95, 0xf848cfc90df4b231,
0942         0x9919c68cf3576038, 0x1e89dad8a6790435, 0x7ac9361379139511, 0x7b5f9b6b937a7760,
0943         0x6e42e395fde0c1f7, 0x430cef1679799f8f, 0x0ad21cc1b4828074, 0x8982577d0ea42349,
0944         0xb1aca6185a7d0d0d, 0x4085c6db106c3d74, 0xba6f7a86e728a418, 0x0325a28758a974d2,
0945         0x57ea317f731817ed, 0xbd1e8e00b215a6eb, 0xb39f323742948e87, 0x9f9b0f873784cef4,
0946         0xa8c83d26585c5377, 0x837ba337bfcf893c, 0x0a7eeca62a23b805, 0xba4925a9e7f7346f,
0947         0xa574eebb90c8da6d, 0x5db7ff0e8d0b8d2d, 0x1562834c52c048d8, 0x0b2e577a853bcafc,
0948         0xdecef97a3524ff97, 0xeec053c8fd537066, 0xeaf2b1df83d600e4, 0x5be8b9ab7717eccf,
0949         0x05905b91ecbba038, 0xabacba5b373029ed, 0x22fb2283c0ee1267, 0x9c32b2ec3634c580,
0950         0x5186c586b6e5611c, 0x71eb0de5e91bb0a0, 0x89e969b42975ef08, 0x2ba0958bc44e322f,
0951         0x626d033cb828ba7d, 0xe5fbb65c7776509d, 0xb1403ae51ae9bc82, 0x5d773f0d9753a966,
0952         0x4a06feadd4ec8585, 0xda58a710fccd7b76, 0x6061ba4cd3d80d59, 0xf4824f5cfa2ba71c,
0953         0xfce622bba0ece756, 0x7d9c738486bc6842, 0x5f629d33c99db969, 0x855ff7c9b79362e6,
0954         0x892188a87c7de231, 0x85fea7caf30e2b5e, 0xbefeb221543782c5, 0x769ca33d280842f6,
0955         0x3974ebaf71353e52, 0xed0577283980f0cb, 0x7c37d689ab6b0662, 0x5037aeffcd3db52d,
0956         0x11bb0a5f64fbdcb5, 0xf5fd5aa5f2b7e974, 0xe1aa07ba7074367b, 0x4b5c14aa1c6a0d28,
0957         0xe9fc8c9c36f73953, 0x2609ad2cd0f99b76, 0x8d4f1d6bb589844f, 0xde09f066714fa909,
0958         0xe004c5d7adad3747, 0xd5ac81a94dfdefe3, 0xfd3e0083658a13c2, 0xf5512f25dd6e39a7,
0959         0xeb7204042ffa181d, 0x046d9254242d06e3, 0x91a5ca94f8706fab, 0xf5c58cc57af63c98,
0960         0x04e7ff1e23474908, 0xe4a9bec5c5818324, 0x1edfb105cc3084dd, 0x82431ec76e72a87a,
0961         0xe0b215be32c51083, 0x0d9942e3b5245098, 0xa49f1aad5723fd7e, 0xad45edba25a4bde8,
0962         0x241f0adc0cd56771, 0xf09bf2de59df3274, 0x090db856bbc020f2, 0x6aa4efb2d2ecb9bb,
0963         0xc6be4224ba04c233, 0x557a1760bde90850, 0x23090117938cb921, 0xcbec34da23f3e9c2,
0964         0xdfe2d55daad85c54, 0xa7932be700067f48, 0xfb7874535e2d76a4, 0x5161ba088056e74f,
0965         0xc275a8435be6cdb2, 0x05fcb771cab5aa15, 0x7f18a4382c9565a8, 0x4244c2cb833d6710,
0966         0x884e2b7a4a3db4d0, 0x08ded459d3edf2c2, 0x1616df531fee90cd, 0x9531c65800a97aaa,
0967         0x881ba77ab7e5d63a, 0x606d27428df4edd3, 0x294063ed78e305c7, 0x7de2b12f8a8cceb5,
0968         0xe6b01cc54a494437, 0x0cdecbe5ac90907c, 0xb88496c657d3e644, 0xf3eecf996f9c6b13,
0969         0x24aad7949edcde03, 0x304ca88ebfeaa534, 0x7b68a7bd3ef1916b, 0x3cc307a784d9060c,
0970         0x5dca03f19b213efd, 0xa380539c235f80c3, 0xf39756fc01d75bd7, 0x39ac6c7281739adb,
0971         0x4b606dc4aa036fda, 0x97126cd02a23b97c, 0x98c1e6906230aead, 0xe12d0f696a6bbc36,
0972         0x657a202bb6a89a33, 0x6421a07bda47e13d, 0x8d9d21b3c6b1dbee, 0x1f110f3744f13e0d,
0973         0x04d86fccb6e77ee8, 0x8c92852d9c9c14b3, 0x56be3cef19b19446, 0x57ceef0e2ebcbcf7,
0974         0x230a9328be0144bf, 0x3c1949b98a92aebc, 0x7ed2db80a62003f2, 0x84e609d13c7594f4,
0975         0xf8e81b9a9f35b4e8, 0xc2982fde1a087e4b, 0x84b0713cb3b18147, 0x3582530578d1ff08,
0976         0x0e5b6538cd61fce4, 0x46867abf4b6e72bc, 0x4fe9652832325e89, 0x7d141d065654745f,
0977         0x9bd5c0479188a53d, 0x4ccd47925108c00b, 0xfd3f6c8d961d47e3, 0x9c5c18a96093d2ad,
0978         0xa7d91bf008a358c3, 0x3ea3e5629f977d55, 0x80f0fed6a5f06003, 0x21f390e377ee4d68,
0979         0x73ed055ec082526b, 0x28482600c10f6ce2, 0x2bff1aaf94c11fe9, 0xde29cb7a943801b8,
0980         0x045b0493dd35af0e, 0xaeae25ff7a431c16, 0x78c9d3348f5364b7, 0xf973d1af84bc2476,
0981         0x4d2303e11baf18f3, 0xacebdb3fe5efbc7b, 0xd274a5cf5be50678, 0x2d60c40fdf53ac67,
0982         0x109592b606139855, 0x612f472a9c09925f, 0x701a035ccd4e7ab0, 0xac881f0db121a709,
0983         0xe1ed47438368366d, 0xde2faff8eeb2810a, 0x8eb2188044342ef9, 0x0e3c1aa7b6851548,
0984         0x7ce94a6ba4fd843f, 0x0da503676ee5ebb2, 0xf3bc7bb2cb8669e8, 0xd4b9e44de392fe64,
0985         0x81e470ebf207fdea, 0xdd53b09d49a0e5b5, 0xf78e23167a350d5a, 0x706470fc2d84423b,
0986         0x816ee82b19a29476, 0x35a9d218ba7cd4a1, 0xf590f12fb09b3fe3, 0x5e574140b302f8b7,
0987         0x6cb237a2021f77c3, 0x30a29037231a861e, 0xff4bb07af553a606, 0x831412ee2690d92c,
0988         0xf6d2d725ef14ff67, 0x2f79f810928a40ff, 0x2857d91ea9b04f71, 0xd063066f0ed78f3c,
0989         0xbf4b8dbc8a34017d, 0x6230f319f8b1f9c4, 0x061b0e25d8899834, 0x4071de32ef7ff0bf,
0990         0xbc546a0793fcfcd3, 0xd5881f5d968cf898, 0x0e21c0674cdda190, 0x0000000000000000};
0991 
0992     struct multiplier_index_info 
0993     {
0994         std::uint16_t first_cache_bit_index;
0995         std::uint16_t cache_bit_index_offset;
0996     };
0997 
0998     static constexpr multiplier_index_info multiplier_index_info_table[] = {
0999         {0, 0},         {171, 244},     {419, 565},     {740, 959},     {1135, 1427},
1000         {1604, 1969},   {2141, 2579},   {2750, 3261},   {3434, 4019},   {4191, 4849},
1001         {5019, 5750},   {5924, 6728},   {6904, 7781},   {7922, 8872},   {8993, 10016},
1002         {9026, 10122},  {9110, 10279},  {9245, 10487},  {9431, 10746},  {9668, 11056},
1003         {9956, 11418},  {10296, 11831}, {10687, 12295}, {11129, 12810}, {11622, 13376},
1004         {12166, 13993}, {12761, 14661}, {13407, 15380}, {14104, 16150}, {14852, 16902},
1005         {15582, 17627}, {16285, 18332}, {16968, 19019}, {17633, 19683}, {18275, 20326},
1006         {18896, 20947}, {19495, 21546}, {20072, 22122}, {20626, 22669}, {21151, 23202},
1007         {21662, 23713}, {22151, 24202}, {22618, 24669}, {23063, 25114}, {23486, 25535},
1008         {23885, 25936}, {24264, 26313}, {24619, 26670}, {24954, 27004}, {25266, 27316},
1009         {25556, 27603}, {25821, 27870}, {26066, 28117}, {26291, 28340}, {26492, 28543},
1010         {26673, 28723}, {26831, 28881}, {26967, 29018}, {27082, 29133}, {27175, 29225},
1011         {27245, 29296}, {27294, 29344}, {27320, 29370}, {27324, 0}};
1012 };
1013 
1014 #if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900)
1015 
1016 template <bool b> constexpr std::size_t extended_cache_long_impl<b>::max_cache_blocks;
1017 template <bool b> constexpr std::size_t extended_cache_long_impl<b>::cache_bits_unit;
1018 template <bool b> constexpr int extended_cache_long_impl<b>::segment_length;
1019 template <bool b> constexpr bool extended_cache_long_impl<b>::constant_block_count;
1020 template <bool b> constexpr int extended_cache_long_impl<b>::e_min;
1021 template <bool b> constexpr int extended_cache_long_impl<b>::k_min;
1022 template <bool b> constexpr int extended_cache_long_impl<b>::cache_bit_index_offset_base;
1023 template <bool b> constexpr std::uint64_t extended_cache_long_impl<b>::cache[];
1024 template <bool b> constexpr typename extended_cache_long_impl<b>::multiplier_index_info extended_cache_long_impl<b>::multiplier_index_info_table[];
1025 
1026 #endif
1027 
1028 using extended_cache_long = extended_cache_long_impl<true>;
1029 
1030 struct extended_cache_compact 
1031 {
1032     static constexpr std::size_t max_cache_blocks = 6;
1033     static constexpr std::size_t cache_bits_unit = 64;
1034     static constexpr int segment_length = 80;
1035     static constexpr bool constant_block_count = false;
1036     static constexpr int collapse_factor = 64;
1037     static constexpr int e_min = -1074;
1038     static constexpr int k_min = -211;
1039     static constexpr int cache_bit_index_offset_base = 967;
1040     static constexpr int cache_block_count_offset_base = 27;
1041 
1042     static constexpr std::uint64_t cache[] = {
1043         0x9faacf3df73609b1, 0x77b191618c54e9ac, 0xcbc0fe19cae9528c, 0x8164d034592c3d4e,
1044         0x04c42d46c9d7a229, 0x7ee39007a5bc8cc3, 0x5469cf7bb8b25e57, 0x2effce010198cb81,
1045         0x642eb5bc0d8169e0, 0x91356aed1f5cd514, 0xe1c8f30156868b8c, 0xd1201a2b857f5cc5,
1046         0x15c07ee55715eff8, 0x8530360cd386f94f, 0xeb706c10ea02c329, 0x3cb22680f921f59e,
1047         0x3231912d5bf60e61, 0x0e1fff697ed6c695, 0xa8bed97c2f3b63fc, 0xda96e93c07538a6d,
1048         0xc1c4e34ccd6fdbc5, 0x85c09fd1d0f79834, 0x485f3a5d03622bba, 0xe640b09cca5b9d50,
1049         0x19a80913a40927a9, 0x4d82d751a5cf886d, 0x325c9cd793b9977b, 0x4896c18501fb9e0c,
1050         0xa9993bfdf3ea7275, 0xcb7d257a3ee7c9d8, 0xcbf8fdb78849a5f9, 0x6de98520472bdd03,
1051         0x36efd14b69b311de, 0x694fa387dcf3e78f, 0xdccfbfc61d1662ef, 0xbe3a4d4104fb75a2,
1052         0x289ccaebae5c6d2d, 0x436915952987fa63, 0x830446728505ab75, 0x3ad8772923e4e0c0,
1053         0xca946600436f3894, 0x0faae7895e3885f0, 0xadf6b773b1ebf8e0, 0x52473dd5e8218647,
1054         0x5e6b5121ca3b747c, 0x217399923cd80bc0, 0x0a56ced144bb2f9f, 0xb856e82eea863c1f,
1055         0x5cdae42f9562104d, 0x3fa421962c8c4241, 0x63451ff73769a3d2, 0xb0895649e11affd6,
1056         0xe5dd7be415e5d3ef, 0x282a242e818f1668, 0xc8a86da5faf0b5cc, 0xf5176ecc7cbb19db,
1057         0x2a9a282e49b4da0e, 0x59e22f9ed2cb3a4b, 0xc010afa26505a7e7, 0xee47b3ab83a99c3e,
1058         0xc7eafae5fa385ec2, 0x3ec747e06293a148, 0x4b8a8260baf424a7, 0x63079a1ac7709a4e,
1059         0x7fd0cd567aa4a0fa, 0x6909d0e0cfc6ce8d, 0xe0c965770d1491dd, 0xa6d4449e3a3e13ea,
1060         0x73e06d2253c6b584, 0x9f95a4b69679998d, 0x0cc8cc76a8234060, 0xd3da311bb4fc0aae,
1061         0x670614382f45f33c, 0x21f68425f4189fbf, 0x557ce28d58d9a8bd, 0x1f16d908907d0a0e,
1062         0x929415f993b9a2c2, 0x95e0878748988052, 0xc4a104701f794a31, 0xe7d2d2b0c3c31b19,
1063         0x1e6a68d5574b3d9d, 0x5727ec70c7681154, 0xe4b2adae8ac5259e, 0x1cefff5ed639205f,
1064         0xf9410ba5daeb3af5, 0x21b0ad30acb4b8d2, 0xd324604028bf6fac, 0x349a5d2dc4bdc6e0,
1065         0xc77223714aff22d9, 0x5b18ce4aabb5b369, 0xb8a6d609b15ecab7, 0x2111dbce86023643,
1066         0x2a5717a571b96b6c, 0x8039783af28427bf, 0x5bbadd6a1a3fb931, 0xe8564a7a3e3ff2dc,
1067         0xd0868939e541158e, 0xc57d0b8a8af06dde, 0xf1706d329def96c1, 0xbe74f435713bb7d5,
1068         0x8dcdaef5bfb0242c, 0x73b5a1c8c8ec33c7, 0x4ab726d9dac95550, 0x210cf3b3ddfa00ae,
1069         0x559d5e65eefbfa04, 0xe5d1f67c5f9de0ec, 0x6ad4699ea2d0efd6, 0x9590c0f05024f29a,
1070         0x917d5715e6e20913, 0xb13124a40bffe5ba, 0x5248ce22e40406e5, 0xb844b16596551ded,
1071         0xad4c4c5140496c58, 0x458562ae335689b6, 0x269441e13a195ad3, 0x7a5e32a8baf53ea8,
1072         0x6d1469edb474b5f6, 0xe87b554829f6ee5b, 0xbf824a42bae3bdef, 0xed12ec6937744feb,
1073         0x2ca544e624e048f9, 0x1bab8d5ee0c61285, 0x8863eaef018d32d9, 0x98f37ac46669f7ea,
1074         0xa9a0573cb5501b2b, 0xf25c3a8e08a5694d, 0x42355a8000000000, 0x0000000000000000};
1075 
1076     struct multiplier_index_info 
1077     {
1078         std::uint16_t first_cache_bit_index;
1079         std::uint16_t cache_bit_index_offset;
1080         std::uint16_t cache_block_count_index_offset;
1081     };
1082 
1083     static constexpr multiplier_index_info multiplier_index_info_table[] = {
1084         {0, 0, 0},          {377, 643, 9},      {1020, 1551, 22},  {1924, 2721, 39},
1085         {3046, 4109, 60},   {3114, 4443, 70},   {3368, 4962, 84},  {3807, 5667, 98},
1086         {4432, 6473, 111},  {5158, 7199, 123},  {5804, 7845, 134}, {6370, 8411, 143},
1087         {6856, 8896, 151},  {7261, 9302, 158},  {7587, 9628, 164}, {7833, 9874, 168},
1088         {7999, 10039, 171}, {8084, 10124, 173}, {8089, 0, 0}};
1089 
1090     static constexpr std::uint8_t cache_block_counts[] = {
1091         0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
1092         0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x56, 0x34, 0x12, 0x66,
1093         0x66, 0x45, 0x23, 0x61, 0x66, 0x66, 0x66, 0x45, 0x23, 0x61, 0x66, 0x66, 0x66,
1094         0x56, 0x34, 0x12, 0x66, 0x66, 0x66, 0x56, 0x34, 0x12, 0x66, 0x66, 0x66, 0x45,
1095         0x23, 0x61, 0x66, 0x56, 0x34, 0x12, 0x66, 0x56, 0x34, 0x12, 0x66, 0x45, 0x23,
1096         0x61, 0x45, 0x23, 0x41, 0x23, 0x31, 0x12, 0x12, 0x01};
1097 };
1098 
1099 #ifdef BOOST_CXX17_INLINE_VARIABLES
1100 
1101 constexpr std::size_t extended_cache_compact::max_cache_blocks;
1102 constexpr std::size_t extended_cache_compact::cache_bits_unit;
1103 constexpr int extended_cache_compact::segment_length;
1104 constexpr bool extended_cache_compact::constant_block_count;
1105 constexpr int extended_cache_compact::collapse_factor;
1106 constexpr int extended_cache_compact::e_min;
1107 constexpr int extended_cache_compact::k_min;
1108 constexpr int extended_cache_compact::cache_bit_index_offset_base;
1109 constexpr int extended_cache_compact::cache_block_count_offset_base;
1110 constexpr extended_cache_compact::multiplier_index_info extended_cache_compact::multiplier_index_info_table[];
1111 constexpr std::uint8_t extended_cache_compact::cache_block_counts[];
1112 
1113 #endif
1114 
1115 struct extended_cache_super_compact 
1116 {
1117     static constexpr std::size_t max_cache_blocks = 15;
1118     static constexpr std::size_t cache_bits_unit = 64;
1119     static constexpr int segment_length = 252;
1120     static constexpr bool constant_block_count = false;
1121     static constexpr int collapse_factor = 128;
1122     static constexpr int e_min = -1074;
1123     static constexpr int k_min = -65;
1124     static constexpr int cache_bit_index_offset_base = 1054;
1125     static constexpr int cache_block_count_offset_base = 10;
1126 
1127     static constexpr std::uint64_t cache[] = {
1128         0xf712b443bbd52b7b, 0xa5e9ec7501d523e4, 0x6f99ee8b281c132a, 0x1c7262e905287f33,
1129         0xbf4f71a69f411989, 0xe95fb0bf35d5c518, 0x00d875ffe81c1457, 0x31f0fcb03c200323,
1130         0x6f64d6af592895a0, 0x45c073ee14c78fb0, 0x8744404cbdba226c, 0x8dbe2386885f0c74,
1131         0x279b6693e94ab813, 0x6df0a4a86ccbb52e, 0xa94baea98e947129, 0xfc2b4e9bb4cbe9a4,
1132         0x73bbc273e753c4ad, 0xc70c8ff8c19c1059, 0xb7da754b6db8b578, 0x5214cf7f2274988c,
1133         0x39b5c4db3b36b321, 0xda6f355441d9f234, 0x01ab018d850bd7e2, 0x36517c3f140b3bcf,
1134         0xd0e52375d8d125a7, 0xaf9709f49f3b8404, 0x022dd12dd219aa3f, 0x46e2ecebe43f459e,
1135         0xa428ebddeecd6636, 0x3a7d11bff7e2a722, 0xd35d40e9d3b97c7d, 0x60ef65c4478901f1,
1136         0x945301feb0da841a, 0x2028c054ab187f51, 0xbe94b1f686a8b684, 0x09c13fdc1c4868c9,
1137         0xf2325ac2bf88a4ce, 0x92980d8fa53b6888, 0x8f6e17c7572a3359, 0x2964c5bfdd7761f2,
1138         0xf60269fc4910b562, 0x3ca164c4a2183ab0, 0x13f4f9e5a06a95c9, 0xf75022e39380598a,
1139         0x0d3f3c870002ab76, 0x24a4beb4780b78ef, 0x17a59a8f5696d625, 0x0ad76de884cb489d,
1140         0x559d3d0681553d6a, 0x813dcf205788af76, 0xf42f9c3ad707bf72, 0x770d63ceb129026c,
1141         0xa604d413fc14c7c2, 0x3cfc19e01239c784, 0xec7ef19965cedd56, 0x7303dcb3b300b6fd,
1142         0x118059e1139c0f3c, 0x97097186308c91f7, 0x2ad91d77379dce42, 0xad396c61acbe15ec,
1143         0x728518461b5722b6, 0xb85c5bb1ed805ecd, 0x816abc04592a4974, 0x1866b17c7cfbd0d0,
1144         0x0000000000000000};
1145 
1146     struct multiplier_index_info 
1147     {
1148         std::uint16_t first_cache_bit_index;
1149         std::uint16_t cache_bit_index_offset;
1150         std::uint16_t cache_block_count_index_offset;
1151     };
1152 
1153     static constexpr multiplier_index_info multiplier_index_info_table[] = {
1154         {0, 0, 0},        {860, 1698, 13},  {2506, 4181, 29}, {2941, 5069, 36},
1155         {3577, 5705, 41}, {3961, 6088, 44}, {4092, 0, 0}};
1156 
1157     static constexpr std::uint8_t cache_block_counts[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xee,
1158                                                             0xee, 0xee, 0xee, 0xee, 0xac, 0x68,
1159                                                             0x24, 0x8a, 0x46, 0x62, 0x24, 0x13};
1160 };
1161 
1162 #ifdef BOOST_CXX17_INLINE_VARIABLES
1163 
1164 constexpr std::size_t extended_cache_super_compact::max_cache_blocks;
1165 constexpr std::size_t extended_cache_super_compact::cache_bits_unit;
1166 constexpr int extended_cache_super_compact::segment_length;
1167 constexpr bool extended_cache_super_compact::constant_block_count;
1168 constexpr int extended_cache_super_compact::collapse_factor;
1169 constexpr int extended_cache_super_compact::e_min;
1170 constexpr int extended_cache_super_compact::k_min;
1171 constexpr int extended_cache_super_compact::cache_bit_index_offset_base;
1172 constexpr int extended_cache_super_compact::cache_block_count_offset_base;
1173 constexpr std::uint64_t extended_cache_super_compact::cache[];
1174 constexpr extended_cache_super_compact::multiplier_index_info extended_cache_super_compact::multiplier_index_info_table[];
1175 constexpr std::uint8_t extended_cache_super_compact::cache_block_counts[];
1176 
1177 #endif
1178 
1179 #ifdef BOOST_MSVC
1180 # pragma warning(push)
1181 # pragma warning(disable: 4100) // MSVC 14.0 warning of unused formal parameter is incorrect
1182 #endif
1183 
1184 template <unsigned v1, unsigned v2, typename ExtendedCache>
1185 bool has_further_digits(std::uint64_t significand, int exp2_base, int& k, boost::charconv::detail::uconst<v1> additional_neg_exp_of_2_c, boost::charconv::detail::uconst<v2> additional_neg_exp_of_10_c) noexcept
1186 {
1187     constexpr auto additional_neg_exp_of_2_v = static_cast<int>(decltype(additional_neg_exp_of_2_c)::value +
1188                                                decltype(additional_neg_exp_of_10_c)::value);
1189     
1190     constexpr auto additional_neg_exp_of_5_v = static_cast<int>(decltype(additional_neg_exp_of_10_c)::value);
1191 
1192     constexpr auto min_neg_exp_of_5 = (-ExtendedCache::k_min + additional_neg_exp_of_5_v) % ExtendedCache::segment_length;
1193 
1194     // k >= k_right_threshold iff k - k1 >= 0.
1195     static_assert(additional_neg_exp_of_5_v + ExtendedCache::segment_length >= 1 + ExtendedCache::k_min, 
1196     "additional_neg_exp_of_5_v + ExtendedCache::segment_length >= 1 + ExtendedCache::k_min");
1197 
1198     constexpr auto k_right_threshold = ExtendedCache::k_min + 
1199     ((additional_neg_exp_of_5_v + ExtendedCache::segment_length - 1 -
1200             ExtendedCache::k_min) /
1201             ExtendedCache::segment_length) *
1202             ExtendedCache::segment_length;
1203 
1204     // When the smallest absolute value of negative exponent for 5 is too big,
1205     // so whenever the exponent for 5 is negative, the result cannot be an
1206     // integer.
1207     BOOST_IF_CONSTEXPR (min_neg_exp_of_5 > 23)
1208     {
1209         return boost::charconv::detail::has_further_digits_impl::no_neg_k_can_be_integer<
1210             k_right_threshold, additional_neg_exp_of_2_v>(k, exp2_base);
1211     }
1212     // When the smallest absolute value of negative exponent for 5 is big enough, so
1213     // the only negative exponent for 5 that allows the result to be an integer is the
1214     // smallest one.
1215     else BOOST_IF_CONSTEXPR (min_neg_exp_of_5 + ExtendedCache::segment_length > 23)
1216     {
1217         // k < k_left_threshold iff k - k1 < -min_neg_exp_of_5.
1218         static_assert(additional_neg_exp_of_5_v + ExtendedCache::segment_length >= min_neg_exp_of_5 + 1 + ExtendedCache::k_min,
1219         "additional_neg_exp_of_5_v + ExtendedCache::segment_length >= min_neg_exp_of_5 + 1 + ExtendedCache::k_min");
1220 
1221         constexpr auto k_left_threshold =
1222             ExtendedCache::k_min +
1223             ((additional_neg_exp_of_5_v - min_neg_exp_of_5 +
1224                 ExtendedCache::segment_length - 1 - ExtendedCache::k_min) /
1225                 ExtendedCache::segment_length) *
1226                 ExtendedCache::segment_length;
1227 
1228         return boost::charconv::detail::has_further_digits_impl::only_one_neg_k_can_be_integer<
1229             k_left_threshold, k_right_threshold, additional_neg_exp_of_2_v,
1230             min_neg_exp_of_5>(k, exp2_base, significand);
1231     }
1232     // When the smallest absolute value of negative exponent for 5 is big enough, so
1233     // the only negative exponents for 5 that allows the result to be an integer are the
1234     // smallest one and the next smallest one.
1235     else
1236     {
1237         static_assert(min_neg_exp_of_5 + 2 * ExtendedCache::segment_length > 23,
1238                         "min_neg_exp_of_5 + 2 * ExtendedCache::segment_length > 23");
1239 
1240         constexpr auto k_left_threshold =
1241             ExtendedCache::k_min +
1242             ((additional_neg_exp_of_5_v - min_neg_exp_of_5 - 1 - ExtendedCache::k_min) /
1243                 ExtendedCache::segment_length) *
1244                 ExtendedCache::segment_length;
1245 
1246         constexpr auto k_middle_threshold =
1247             ExtendedCache::k_min +
1248             ((additional_neg_exp_of_5_v - min_neg_exp_of_5 +
1249                 ExtendedCache::segment_length - 1 - ExtendedCache::k_min) /
1250                 ExtendedCache::segment_length) *
1251                 ExtendedCache::segment_length;
1252 
1253         return boost::charconv::detail::has_further_digits_impl::only_two_neg_k_can_be_integer<
1254             k_left_threshold, k_middle_threshold, k_right_threshold,
1255             additional_neg_exp_of_2_v, min_neg_exp_of_5, ExtendedCache::segment_length>(
1256             k, exp2_base, significand);
1257     }
1258 }
1259 
1260 template <unsigned v1, unsigned v2, typename ExtendedCache>
1261 inline bool has_further_digits(std::uint64_t significand, int exp2_base, int& k)
1262 {
1263     boost::charconv::detail::uconst<v1> additional_neg_exp_of_2_c;
1264     boost::charconv::detail::uconst<v2> additional_neg_exp_of_10_c;
1265 
1266     return has_further_digits<v1, v2, ExtendedCache>(significand, exp2_base, k, additional_neg_exp_of_2_c, additional_neg_exp_of_10_c);
1267 }
1268 
1269 template <unsigned additional_neg_exp_of_2, unsigned additional_neg_exp_of_10, typename ExtendedCache>
1270 bool compute_has_further_digits(unsigned remaining_subsegment_pairs, std::uint64_t significand, int exp2_base, int& k) noexcept
1271 {
1272     #define BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(n)                                                        \
1273     case n:                                                                                            \
1274         return has_further_digits<additional_neg_exp_of_2, additional_neg_exp_of_10 + (n - 1) * 18, ExtendedCache>(significand, exp2_base, k)                                             
1275                                     switch (remaining_subsegment_pairs) {
1276                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(1);
1277                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(2);
1278                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(3);
1279                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(4);
1280                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(5);
1281                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(6);
1282                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(7);
1283                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(8);
1284                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(9);
1285                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(10);
1286                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(11);
1287                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(12);
1288                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(13);
1289                                         BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(14);
1290 
1291                                     default:
1292                                         BOOST_UNREACHABLE_RETURN(remaining_subsegment_pairs); // NOLINT
1293                                     }
1294     #undef BOOST_CHARCONV_252_HAS_FURTHER_DIGITS
1295 
1296     BOOST_UNREACHABLE_RETURN(false); // NOLINT
1297 }
1298 
1299 #ifdef BOOST_MSVC
1300 # pragma warning(pop)
1301 #endif
1302 
1303 // Print 0.000...0 where precision is the number of 0's after the decimal dot.
1304 inline to_chars_result print_zero_fixed(char* buffer, std::size_t buffer_size, const int precision) noexcept
1305 {
1306     // No trailing decimal dot.
1307     if (precision == 0)
1308     {
1309         *buffer = '0';
1310         return {buffer + 1, std::errc()};
1311     }
1312 
1313     if (buffer_size < static_cast<std::size_t>(precision) + 2U)
1314     {
1315         return {buffer + buffer_size, std::errc::value_too_large};
1316     }
1317 
1318     std::memcpy(buffer, "0.", 2); // NOLINT : Specifically not null-terminating
1319     std::memset(buffer + 2, '0', static_cast<std::size_t>(precision)); // NOLINT : Specifically not null-terminating
1320     return {buffer + 2 + precision, std::errc()};
1321 }
1322 
1323 // precision means the number of decimal significand digits minus 1.
1324 // Assumes round-to-nearest, tie-to-even rounding.
1325 template <typename MainCache = main_cache_full, typename ExtendedCache>
1326 BOOST_CHARCONV_SAFEBUFFERS to_chars_result floff(const double x, int precision, char* first, char* last,
1327                                                  boost::charconv::chars_format fmt) noexcept
1328 {
1329     if (first >= last)
1330     {
1331         return {last, std::errc::value_too_large};
1332     }
1333 
1334     auto buffer_size = static_cast<std::size_t>(last - first);
1335     auto buffer = first;
1336 
1337     BOOST_CHARCONV_ASSERT(precision >= 0);
1338     using namespace detail;
1339 
1340     std::uint64_t br = default_float_traits<double>::float_to_carrier(x);
1341     bool is_negative = ((br >> 63) != 0);
1342     br <<= 1;
1343     int e = static_cast<int>(br >> (ieee754_binary64::significand_bits + 1));
1344     auto significand = (br & ((UINT64_C(1) << (ieee754_binary64::significand_bits + 1)) - 1)); // shifted by 1-bit.
1345 
1346     if (is_negative)
1347     {
1348         *buffer = '-';
1349         ++buffer;
1350         --buffer_size;
1351 
1352         if (buffer_size == 0)
1353         {
1354             return {buffer, std::errc::value_too_large};
1355         }
1356     }
1357 
1358     // Infinities or NaN
1359     if (e == ((UINT32_C(1) << ieee754_binary64::exponent_bits) - 1)) 
1360     {
1361         if (significand == 0)
1362         {
1363             constexpr std::size_t inf_chars = 3;
1364 
1365             if (buffer_size < inf_chars)
1366             {
1367                 return {last, std::errc::value_too_large};
1368             }
1369 
1370             std::memcpy(buffer, "inf", inf_chars); // NOLINT : Specifically not null-terminating
1371             return {buffer + inf_chars, std::errc()};
1372         }
1373         else 
1374         {
1375             // Significand values for NaN by type
1376             // qNaN = 4503599627370496
1377             // sNaN = 2251799813685248
1378             //
1379             if (significand == UINT64_C(4503599627370496))
1380             {
1381                 if (!is_negative)
1382                 {
1383                     constexpr std::size_t nan_chars = 3;
1384 
1385                     if (buffer_size < nan_chars)
1386                     {
1387                         return {last, std::errc::value_too_large};
1388                     }
1389 
1390                     std::memcpy(buffer, "nan", nan_chars); // NOLINT : Specifically not null-terminating
1391                     return {buffer + nan_chars, std::errc()};
1392                 }
1393                 else
1394                 {
1395                     constexpr std::size_t neg_nan_chars = 8;
1396 
1397                     if (buffer_size < neg_nan_chars)
1398                     {
1399                         return {last, std::errc::value_too_large};
1400                     }
1401 
1402                     std::memcpy(buffer, "nan(ind)", neg_nan_chars); // NOLINT : Specifically not null-terminating
1403                     return {buffer + neg_nan_chars, std::errc()};
1404                 }
1405             }
1406             else
1407             {
1408                 constexpr std::size_t snan_chars = 9;
1409 
1410                 if (buffer_size < snan_chars)
1411                 {
1412                     return {last, std::errc::value_too_large};
1413                 }
1414 
1415                 std::memcpy(buffer, "nan(snan)", snan_chars); // NOLINT : Specifically not null-terminating
1416                 return {buffer + snan_chars, std::errc()};
1417             }
1418         }
1419     }
1420     else
1421     {
1422         // Normal numbers.
1423         if (e != 0)
1424         {
1425             significand |= (decltype(significand)(1) << (ieee754_binary64::significand_bits + 1));
1426             e += (ieee754_binary64::exponent_bias - ieee754_binary64::significand_bits);
1427         }
1428         // Subnormal numbers.
1429         else 
1430         {
1431             // Zero
1432             if (significand == 0) 
1433             {
1434                 if (fmt == boost::charconv::chars_format::general)
1435                 {
1436                     // For the case of chars_format::general, 0 is always printed as 0.
1437                     *buffer = '0';
1438                     return {buffer + 1, std::errc()};
1439                 }
1440                 else if (fmt == boost::charconv::chars_format::fixed)
1441                 {
1442                     return print_zero_fixed(buffer, buffer_size, precision);
1443                 }
1444                 // For the case of chars_format::scientific, print as many 0's as requested after the decimal dot, and then print e+00.
1445                 if (precision == 0) 
1446                 {
1447                     constexpr std::size_t zero_chars = 5;
1448 
1449                     if (buffer_size < zero_chars)
1450                     {
1451                         return {last, std::errc::value_too_large};
1452                     }
1453 
1454                     std::memcpy(buffer, "0e+00", zero_chars);
1455                     return {buffer + zero_chars, std::errc()};
1456                 }
1457                 else 
1458                 {
1459                     if (buffer_size < static_cast<std::size_t>(precision) + 6U)
1460                     {
1461                         return {last, std::errc::value_too_large};
1462                     }
1463 
1464                     std::memcpy(buffer, "0.", 2); // NOLINT : Specifically not null-terminating
1465                     std::memset(buffer + 2, '0', static_cast<std::size_t>(precision)); // NOLINT : Specifically not null-terminating
1466                     std::memcpy(buffer + 2 + precision, "e+00", 4); // NOLINT : Specifically not null-terminating
1467                     return {buffer + precision + 6, std::errc()};
1468                 }
1469             }
1470             // Nonzero
1471             e = ieee754_binary64::min_exponent - ieee754_binary64::significand_bits;
1472         }
1473     }
1474 
1475     constexpr int kappa = 2;
1476     int k = kappa - log::floor_log10_pow2(e);
1477     std::uint32_t current_digits {};
1478     char* const buffer_starting_pos = buffer;
1479     char* decimal_dot_pos = buffer; // decimal_dot_pos == buffer_starting_pos indicates that there should be no decimal dot.
1480     int decimal_exponent_normalized {};
1481 
1482     // Number of digits to be printed.
1483     int remaining_digits {};
1484 
1485     /////////////////////////////////////////////////////////////////////////////////////////////////
1486     /// Phase 1 - Print the first digit segment computed with the Dragonbox table.
1487     /////////////////////////////////////////////////////////////////////////////////////////////////
1488 
1489     {
1490         // Compute the first digit segment.
1491         const auto main_cache = MainCache::template get_cache<ieee754_binary64>(k);
1492         const int beta = e + log::floor_log2_pow10(k);
1493 
1494         // Integer check is okay for binary64.
1495         //auto [first_segment, has_more_segments] 
1496         compute_mul_result segments = [&] {
1497             const auto r = umul192_upper128(significand << beta, main_cache);
1498             return compute_mul_result{r.high, r.low == 0};
1499         }();
1500 
1501         auto first_segment = segments.result;
1502         auto has_more_segments = !segments.is_integer;
1503 
1504         // The first segment can be up to 19 digits. It is in fact always of either 18 or 19
1505         // digits except when the input is a subnormal number. For subnormal numbers, the
1506         // smallest possible value of the first segment is 10^kappa, so it is of at least
1507         // kappa+1 digits (i.e., 3 in this case).
1508 
1509         int first_segment_length = 19;
1510         auto first_segment_aligned = first_segment; // Aligned to have 19 digits.
1511         while (first_segment_aligned < UINT64_C(10000000000000000))
1512         {
1513             first_segment_aligned *= 100;
1514             first_segment_length -= 2;
1515         }
1516         if (first_segment_aligned < UINT64_C(1000000000000000000))
1517         {
1518             first_segment_aligned *= 10;
1519             first_segment_length -= 1;
1520         }
1521         // The decimal exponent when written as X.XXXX.... x 10^XX.
1522         decimal_exponent_normalized = first_segment_length - k - 1;
1523 
1524         // Figure out the correct value of remaining_digits.
1525         if (fmt == boost::charconv::chars_format::scientific)
1526         {
1527             remaining_digits = precision + 1;
1528             int exponent_print_length =
1529                 decimal_exponent_normalized >= 100 ? 5 :
1530                 decimal_exponent_normalized <= -100 ? 6 :
1531                 decimal_exponent_normalized >= 0 ? 4 : 5;
1532 
1533             // No trailing decimal dot.
1534             auto minimum_required_buffer_size =
1535                 static_cast<std::size_t>(remaining_digits + exponent_print_length + (precision != 0 ? 1 : 0));
1536             if (buffer_size < minimum_required_buffer_size)
1537             {
1538                 return {last, std::errc::value_too_large};
1539             }
1540 
1541             if (precision != 0)
1542             {
1543                 // Reserve a place for the decimal dot.
1544                 *buffer = '0';
1545                 ++buffer;
1546                 ++decimal_dot_pos;
1547             }
1548         }
1549         else if (fmt == boost::charconv::chars_format::fixed)
1550         {
1551             if (decimal_exponent_normalized >= 0)
1552             {
1553                 remaining_digits = precision + decimal_exponent_normalized + 1;
1554                 
1555                 // No trailing decimal dot.
1556                 auto minimum_required_buffer_size =
1557                     static_cast<std::size_t>(remaining_digits + (precision != 0 ? 1 : 0));
1558 
1559                 // We need one more space if the rounding changes the exponent,
1560                 // but since we don't know at this point if that will actually happen, handle such a case later.
1561 
1562                 if (buffer_size < minimum_required_buffer_size)
1563                 {
1564                     return {last, std::errc::value_too_large};
1565                 }
1566 
1567                 if (precision != 0)
1568                 {
1569                     // Reserve a place for the decimal dot.
1570                     *buffer = '0';
1571                     ++buffer;
1572                     decimal_dot_pos += decimal_exponent_normalized + 1;
1573                 }
1574             }
1575             else
1576             {
1577                 int number_of_leading_zeros = -decimal_exponent_normalized - 1;
1578 
1579                 // When there are more than precision number of leading zeros,
1580                 // all the digits we need to print are 0.
1581                 if (number_of_leading_zeros > precision)
1582                 {
1583                     return print_zero_fixed(buffer, buffer_size, precision);
1584                 }
1585                 // When the number of leading zeros is exactly precision,
1586                 // then we might need to print 1 at the last digit due to rounding.
1587                 if (number_of_leading_zeros == precision)
1588                 {
1589                     // Since the last digit before rounding is 0,
1590                     // according to the "round-to-nearest, tie-to-even" rule, we round-up
1591                     // if and only if the input is strictly larger than the midpoint.
1592                     bool round_up = (first_segment_aligned + (has_more_segments ? 1 : 0)) > UINT64_C(5000000000000000000);
1593                     if (!round_up)
1594                     {
1595                         return print_zero_fixed(buffer, buffer_size, precision);
1596                     }
1597 
1598                     // No trailing decimal dot.
1599                     if (precision == 0)
1600                     {
1601                         *buffer = '1';
1602                         return {buffer + 1, std::errc()};
1603                     }
1604 
1605                     if (buffer_size < static_cast<std::size_t>(precision) + 2U)
1606                     {
1607                         return {buffer + buffer_size, std::errc::value_too_large};
1608                     }
1609 
1610                     std::memcpy(buffer, "0.", 2); // NOLINT : Specifically not null-terminating
1611                     std::memset(buffer + 2, '0', static_cast<std::size_t>(precision - 1)); // NOLINT : Specifically not null-terminating
1612                     buffer[1 + precision] = '1';
1613                     return {buffer + 2 + precision, std::errc()};
1614                 }
1615 
1616                 remaining_digits = precision - number_of_leading_zeros;
1617                 
1618                 // Always have decimal dot.
1619                 BOOST_CHARCONV_ASSERT(precision > 0);
1620                 auto minimum_required_buffer_size = static_cast<std::size_t>(precision + 2);
1621                 if (buffer_size < minimum_required_buffer_size)
1622                 {
1623                     return {last, std::errc::value_too_large};
1624                 }
1625 
1626                 // Print leading zeros.
1627                 std::memset(buffer, '0', static_cast<std::size_t>(number_of_leading_zeros + 2));
1628                 buffer += number_of_leading_zeros + 2;
1629                 ++decimal_dot_pos;
1630             }
1631         }
1632         else
1633         {
1634             // fmt == boost::charconv::chars_format::general
1635             if (precision == 0)
1636             {
1637                 // For general format, precision = 0 is interpreted as precision = 1.
1638                 precision = 1;
1639             }
1640             remaining_digits = precision;
1641 
1642             // Use scientific format if decimal_exponent_normalized <= -6 or decimal_exponent_normalized >= precision.
1643             // Use fixed format if -4 <= decimal_exponent_normalized <= precision - 2.
1644             // If decimal_exponent_normalized == -5, use fixed format if and only if the rounding increases the exponent.
1645             // If decimal_exponent_normalized == precision - 1, use scientific format if and only if the rounding increases the exponent.
1646             // Since we cannot reliably decide which format to use, necessary corrections will be made in the last phase.
1647 
1648             // We may end up not printing the decimal dot if fixed format is chosen, but reserve a place anyway.
1649             *buffer = '0';
1650             ++buffer;
1651             decimal_dot_pos += (0 < decimal_exponent_normalized && decimal_exponent_normalized < precision)
1652                                 ? decimal_exponent_normalized + 1 : 1;
1653         }
1654 
1655         if (remaining_digits <= 2) 
1656         {
1657             uint128 prod;
1658             std::uint64_t fractional_part64;
1659             std::uint64_t fractional_part_rounding_threshold64;
1660 
1661             // Convert to fixed-point form with 64/32-bit boundary for the fractional part.
1662 
1663             if (remaining_digits == 1)
1664             {
1665                 prod = umul128(first_segment_aligned, UINT64_C(1329227995784915873));
1666                 // ceil(2^63 + 2^64/10^18)
1667                 fractional_part_rounding_threshold64 = additional_static_data_holder::fractional_part_rounding_thresholds64[17];
1668             }
1669             else
1670             {
1671                 prod = umul128(first_segment_aligned, UINT64_C(13292279957849158730));
1672                 // ceil(2^63 + 2^64/10^17)
1673                 fractional_part_rounding_threshold64 = additional_static_data_holder::
1674                     fractional_part_rounding_thresholds64[16];
1675             }
1676             fractional_part64 = (prod.low >> 56) | (prod.high << 8);
1677             current_digits = static_cast<std::uint32_t>(prod.high >> 56);
1678 
1679             // Perform rounding, print the digit, and return.
1680             if (remaining_digits == 1)
1681             {
1682                 if (fractional_part64 >= fractional_part_rounding_threshold64 ||
1683                     ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0) 
1684                 {
1685                     goto round_up_one_digit;
1686                 }
1687 
1688                 print_1_digit(current_digits, buffer);
1689                 ++buffer;
1690             }
1691             else 
1692             {
1693                 if (fractional_part64 >= fractional_part_rounding_threshold64 ||
1694                     ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0)
1695                 {
1696                     goto round_up_two_digits;
1697                 }
1698 
1699                 print_2_digits(current_digits, buffer);
1700                 buffer += 2;
1701             }
1702 
1703             goto insert_decimal_dot;
1704         } // remaining_digits <= 2
1705 
1706         // At this point, there are at least 3 digits to print.
1707         // We split the segment into three chunks, each consisting of 9 digits, 8 digits,
1708         // and 2 digits.
1709 
1710         // MSVC doesn't know how to do Grandlund-Montgomery for large 64-bit integers.
1711         // 7922816251426433760 = ceil(2^96/10^10) = floor(2^96*(10^9/(10^19 - 1)))
1712         const auto first_subsegment =
1713             static_cast<std::uint32_t>(umul128_upper64(first_segment, UINT64_C(7922816251426433760)) >> 32);
1714 
1715         const auto second_third_subsegments =
1716             first_segment - first_subsegment * UINT64_C(10000000000);
1717 
1718         BOOST_CHARCONV_ASSERT(first_subsegment < UINT64_C(1000000000));
1719         BOOST_CHARCONV_ASSERT(second_third_subsegments < UINT64_C(10000000000));
1720 
1721         int remaining_digits_in_the_current_subsegment;
1722         std::uint64_t prod; // holds intermediate values for digit generation.
1723 
1724         // Print the first subsegment.
1725         if (first_subsegment != 0)
1726         {
1727             // 9 digits (19 digits in total).
1728             if (first_subsegment >= 100000000) 
1729             {
1730                 // 1441151882 = ceil(2^57 / 10^8) + 1
1731                 prod = first_subsegment * UINT64_C(1441151882);
1732                 prod >>= 25;
1733                 remaining_digits_in_the_current_subsegment = 8;
1734             }
1735             // 7 or 8 digits (17 or 18 digits in total).
1736             else if (first_subsegment >= 1000000)
1737             {
1738                 // 281474978 = ceil(2^48 / 10^6) + 1
1739                 prod = first_subsegment * UINT64_C(281474978);
1740                 prod >>= 16;
1741                 remaining_digits_in_the_current_subsegment = 6;
1742             }
1743             // 5 or 6 digits (15 or 16 digits in total).
1744             else if (first_subsegment >= 10000)
1745             {
1746                 // 429497 = ceil(2^32 / 10^4)
1747                 prod = first_subsegment * UINT64_C(429497);
1748                 remaining_digits_in_the_current_subsegment = 4;
1749             }
1750             // 3 or 4 digits (13 or 14 digits in total).
1751             else if (first_subsegment >= 100)
1752             {
1753                 // 42949673 = ceil(2^32 / 10^2)
1754                 prod = first_subsegment * UINT64_C(42949673);
1755                 remaining_digits_in_the_current_subsegment = 2;
1756             }
1757             // 1 or 2 digits (11 or 12 digits in total).
1758             else
1759             {
1760                 prod = std::uint64_t(first_subsegment) << 32;
1761                 remaining_digits_in_the_current_subsegment = 0;
1762             }
1763 
1764             const auto initial_digits = static_cast<std::uint32_t>(prod >> 32);
1765 
1766             buffer -= (initial_digits < 10 && buffer != first ? 1 : 0);
1767             remaining_digits -= (2 - (initial_digits < 10 ? 1 : 0));
1768 
1769             // Avoid the situation where we have a leading 0 that we don't need
1770             // Typically used to account for inserting a decimal, but we know
1771             // we won't need that in the 0 precision case
1772             if (precision == 0 && initial_digits < 10)
1773             {
1774                 print_1_digit(initial_digits, buffer);
1775                 ++buffer;
1776             }
1777             else
1778             {
1779                 print_2_digits(initial_digits, buffer);
1780                 buffer += 2;
1781             }
1782 
1783             if (remaining_digits > remaining_digits_in_the_current_subsegment) 
1784             {
1785                 remaining_digits -= remaining_digits_in_the_current_subsegment;
1786                 
1787                 for (; remaining_digits_in_the_current_subsegment > 0; remaining_digits_in_the_current_subsegment -= 2) 
1788                 {
1789                     // Write next two digits.
1790                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
1791                     print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
1792                     buffer += 2;
1793                 }
1794             }
1795             else 
1796             {
1797                 for (int i = 0; i < (remaining_digits - 1) / 2; ++i) 
1798                 {
1799                     // Write next two digits.
1800                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
1801                     print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
1802                     buffer += 2;
1803                 }
1804 
1805                 // Distinguish two cases of rounding.
1806                 if (remaining_digits_in_the_current_subsegment > remaining_digits)
1807                 {
1808                     if ((remaining_digits & 1) != 0) 
1809                     {
1810                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
1811                     }
1812                     else 
1813                     {
1814                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
1815                     }
1816                     
1817                     current_digits = static_cast<std::uint32_t>(prod >> 32);
1818 
1819                     if (check_rounding_condition_inside_subsegment(
1820                             current_digits, static_cast<std::uint32_t>(prod),
1821                             remaining_digits_in_the_current_subsegment - remaining_digits,
1822                             second_third_subsegments != 0 || has_more_segments)) 
1823                     {
1824                         goto round_up;
1825                     }
1826 
1827                     goto print_last_digits;
1828                 }
1829                 else 
1830                 {
1831                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
1832                     current_digits = static_cast<std::uint32_t>(prod >> 32);
1833 
1834                     if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
1835                             current_digits,
1836                             uint_with_known_number_of_digits<10>{second_third_subsegments},
1837                             has_more_segments)) 
1838                     {
1839                         goto round_up_two_digits;
1840                     }
1841 
1842                     goto print_last_two_digits;
1843                 }
1844             }
1845         }
1846 
1847         // Print the second subsegment.
1848         // The second subsegment cannot be zero even for subnormal numbers.
1849 
1850         if (remaining_digits <= 2) 
1851         {
1852             // In this case the first subsegment must be nonzero.
1853 
1854             if (remaining_digits == 1) 
1855             {
1856                 const auto prod128 = umul128(second_third_subsegments, UINT64_C(18446744074));
1857 
1858                 current_digits = static_cast<std::uint32_t>(prod128.high);
1859                 const auto fractional_part64 = prod128.low + 1;
1860                 // 18446744074 is even, so prod.low cannot be equal to 2^64 - 1.
1861                 BOOST_CHARCONV_ASSERT(fractional_part64 != 0);
1862 
1863                 if (fractional_part64 >= additional_static_data_holder::fractional_part_rounding_thresholds64[8] ||
1864                     ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0) 
1865                 {
1866                     goto round_up_one_digit;
1867                 }
1868 
1869                 goto print_last_one_digit;
1870             } // remaining_digits == 1
1871             else 
1872             {
1873                 const auto prod128 = umul128(second_third_subsegments, UINT64_C(184467440738));
1874 
1875                 current_digits = static_cast<std::uint32_t>(prod128.high);
1876                 const auto fractional_part64 = prod128.low + 1;
1877                 // 184467440738 is even, so prod.low cannot be equal to 2^64 - 1.
1878                 BOOST_CHARCONV_ASSERT(fractional_part64 != 0);
1879 
1880                 if (fractional_part64 >= additional_static_data_holder::fractional_part_rounding_thresholds64[7] ||
1881                     ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0) 
1882                 {
1883                     goto round_up_two_digits;
1884                 }
1885 
1886                 goto print_last_two_digits;
1887             }
1888         } // remaining_digits <= 2
1889 
1890         // Compilers are not aware of how to leverage the maximum value of
1891         // second_third_subsegments to find out a better magic number which allows us to
1892         // eliminate an additional shift.
1893         // 184467440737095517 = ceil(2^64/100) < floor(2^64*(10^8/(10^10 - 1))).
1894         const auto second_subsegment = static_cast<std::uint32_t>(
1895             umul128_upper64(second_third_subsegments, UINT64_C(184467440737095517)));
1896 
1897         // Since the final result is of 2 digits, we can do the computation in 32-bits.
1898         const auto third_subsegment =
1899             static_cast<std::uint32_t>(second_third_subsegments) - second_subsegment * 100;
1900 
1901         BOOST_CHARCONV_ASSERT(second_subsegment < 100000000);
1902         BOOST_CHARCONV_ASSERT(third_subsegment < 100);
1903 
1904         {
1905             std::uint32_t initial_digits;
1906             if (first_subsegment != 0) 
1907             {
1908                 prod = ((second_subsegment * UINT64_C(281474977)) >> 16) + 1;
1909                 remaining_digits_in_the_current_subsegment = 6;
1910 
1911                 initial_digits = static_cast<std::uint32_t>(prod >> 32);
1912                 remaining_digits -= 2;
1913             }
1914             else 
1915             {
1916                 // 7 or 8 digits (9 or 10 digits in total).
1917                 if (second_subsegment >= 1000000) 
1918                 {
1919                     prod = (second_subsegment * UINT64_C(281474978)) >> 16;
1920                     remaining_digits_in_the_current_subsegment = 6;
1921                 }
1922                 // 5 or 6 digits (7 or 8 digits in total).
1923                 else if (second_subsegment >= 10000)
1924                 {
1925                     prod = second_subsegment * UINT64_C(429497);
1926                     remaining_digits_in_the_current_subsegment = 4;
1927                 }
1928                 // 3 or 4 digits (5 or 6 digits in total).
1929                 else if (second_subsegment >= 100)
1930                 {
1931                     prod = second_subsegment * UINT64_C(42949673);
1932                     remaining_digits_in_the_current_subsegment = 2;
1933                 }
1934                 // 1 or 2 digits (3 or 4 digits in total).
1935                 else
1936                 {
1937                     prod = std::uint64_t(second_subsegment) << 32;
1938                     remaining_digits_in_the_current_subsegment = 0;
1939                 }
1940 
1941                 initial_digits = static_cast<std::uint32_t>(prod >> 32);
1942                 buffer -= (initial_digits < 10 ? 1 : 0);
1943                 remaining_digits -= (2 - (initial_digits < 10 ? 1 : 0));
1944             }
1945 
1946             print_2_digits(initial_digits, buffer);
1947             buffer += 2;
1948 
1949             if (remaining_digits > remaining_digits_in_the_current_subsegment)
1950             {
1951                 remaining_digits -= remaining_digits_in_the_current_subsegment;
1952                 for (; remaining_digits_in_the_current_subsegment > 0; remaining_digits_in_the_current_subsegment -= 2) 
1953                 {
1954                     // Write next two digits.
1955                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
1956                     print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
1957                     buffer += 2;
1958                 }
1959             }
1960             else 
1961             {
1962                 for (int i = 0; i < (remaining_digits - 1) / 2; ++i) 
1963                 {
1964                     // Write next two digits.
1965                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
1966                     print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
1967                     buffer += 2;
1968                 }
1969 
1970                 // Distinguish two cases of rounding.
1971                 if (remaining_digits_in_the_current_subsegment > remaining_digits) 
1972                 {
1973                     if ((remaining_digits & 1) != 0) 
1974                     {
1975                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
1976                     }
1977                     else 
1978                     {
1979                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
1980                     }
1981                     current_digits = static_cast<std::uint32_t>(prod >> 32);
1982 
1983                     if (check_rounding_condition_inside_subsegment(
1984                             current_digits, static_cast<std::uint32_t>(prod),
1985                             remaining_digits_in_the_current_subsegment - remaining_digits,
1986                             third_subsegment != 0 || has_more_segments)) 
1987                     {
1988                         goto round_up;
1989                     }
1990 
1991                     goto print_last_digits;
1992                 }
1993                 else 
1994                 {
1995                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
1996                     current_digits = static_cast<std::uint32_t>(prod >> 32);
1997 
1998                     if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
1999                             current_digits,
2000                             uint_with_known_number_of_digits<2>{third_subsegment},
2001                             has_more_segments)) 
2002                     {
2003                         goto round_up_two_digits;
2004                     }
2005 
2006                     goto print_last_two_digits;
2007                 }
2008             }
2009         }
2010 
2011         // Print the third subsegment.
2012         {
2013             if (remaining_digits > 2) 
2014             {
2015                 print_2_digits(third_subsegment, buffer);
2016                 buffer += 2;
2017                 remaining_digits -= 2;
2018 
2019                 // If there is no more segment, then fill remaining digits with 0's and return.
2020                 if (!has_more_segments) 
2021                 {
2022                     goto fill_remaining_digits_with_0s;
2023                 }
2024             }
2025             else if (remaining_digits == 1) 
2026             {
2027                 prod = third_subsegment * UINT64_C(429496730);
2028                 current_digits = static_cast<std::uint32_t>(prod >> 32);
2029 
2030                 if (check_rounding_condition_inside_subsegment(
2031                         current_digits, static_cast<std::uint32_t>(prod), 1, has_more_segments)) 
2032                 {
2033                     goto round_up_one_digit;
2034                 }
2035 
2036                 goto print_last_one_digit;
2037             }
2038             else 
2039             {
2040                 // remaining_digits == 2.
2041                 // If there is no more segment, then print the current two digits and return.
2042                 if (!has_more_segments)
2043                 {
2044                     print_2_digits(third_subsegment, buffer);
2045                     buffer += 2;
2046                     goto insert_decimal_dot;
2047                 }
2048 
2049                 // Otherwise, for performing the rounding, we have to wait until the next
2050                 // segment becomes available. This state can be detected afterward by
2051                 // inspecting if remaining_digits == 0.
2052                 remaining_digits = 0;
2053                 current_digits = third_subsegment;
2054             }
2055         }
2056     }
2057 
2058     /////////////////////////////////////////////////////////////////////////////////////////////////
2059     /// Phase 2 - Print further digit segments computed with the extended cache table.
2060     /////////////////////////////////////////////////////////////////////////////////////////////////
2061 
2062     {
2063         auto multiplier_index =
2064             static_cast<std::uint32_t>(k + ExtendedCache::segment_length - ExtendedCache::k_min) /
2065             static_cast<std::uint32_t>(ExtendedCache::segment_length);
2066 
2067         int digits_in_the_second_segment;
2068         {
2069             const auto new_k =
2070                 ExtendedCache::k_min + static_cast<int>(multiplier_index) * ExtendedCache::segment_length;
2071             digits_in_the_second_segment = new_k - k;
2072             k = new_k;
2073         }
2074 
2075         const auto exp2_base = e + boost::core::countr_zero(significand);
2076 
2077         using cache_block_type = typename std::decay<decltype(ExtendedCache::cache[0])>::type;
2078         
2079         cache_block_type blocks[ExtendedCache::max_cache_blocks];
2080         cache_block_count_t<ExtendedCache::constant_block_count, ExtendedCache::max_cache_blocks> cache_block_count;
2081 
2082         // Deal with the second segment. The second segment is special because it can have
2083         // overlapping digits with the first segment. Note that we cannot just move the buffer
2084         // pointer backward and print the whole segment from there, because it may contain
2085         // leading zeros.
2086         {
2087             cache_block_count =
2088                 load_extended_cache<ExtendedCache, ExtendedCache::constant_block_count>(
2089                     blocks, e, k, multiplier_index);
2090 
2091             // Compute nm mod 2^Q.
2092             fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(significand, blocks, cache_block_count);
2093 
2094             BOOST_CHARCONV_IF_CONSTEXPR (ExtendedCache::segment_length == 22)
2095             {
2096                 // No rounding, continue.
2097                 if (remaining_digits > digits_in_the_second_segment)
2098                 {
2099                     remaining_digits -= digits_in_the_second_segment;
2100 
2101                     if (digits_in_the_second_segment <= 2)
2102                     {
2103                         BOOST_CHARCONV_ASSERT(digits_in_the_second_segment != 0);
2104 
2105                         fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(
2106                             power_of_10[19], blocks, cache_block_count);
2107 
2108                         auto subsegment =
2109                             fixed_point_calculator<ExtendedCache::max_cache_blocks>::
2110                                 generate_and_discard_lower(power_of_10[3], blocks,
2111                                                             cache_block_count);
2112 
2113                         if (digits_in_the_second_segment == 1)
2114                         {
2115                             auto prod = subsegment * UINT64_C(429496730);
2116                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2117                             print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
2118                             ++buffer;
2119                         }
2120                         else 
2121                         {
2122                             auto prod = subsegment * UINT64_C(42949673);
2123                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2124                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2125                             buffer += 2;
2126                         }
2127                     } // digits_in_the_second_segment <= 2
2128                     else if (digits_in_the_second_segment <= 16)
2129                     {
2130                         BOOST_CHARCONV_ASSERT(22 - digits_in_the_second_segment <= 19);
2131                         
2132                         fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(
2133                             compute_power(UINT64_C(10), 22 - digits_in_the_second_segment),
2134                             blocks, cache_block_count);
2135 
2136                         // When there are at most 9 digits, we can store them in 32-bits.
2137                         if (digits_in_the_second_segment <= 9) 
2138                         {
2139                             // The number of overlapping digits is in the range 13 ~ 19.
2140                             const auto subsegment =
2141                                 fixed_point_calculator<ExtendedCache::max_cache_blocks>::
2142                                     generate_and_discard_lower(power_of_10[9], blocks,
2143                                                                 cache_block_count);
2144 
2145                             std::uint64_t prod;
2146                             if ((digits_in_the_second_segment & 1) != 0)
2147                             {
2148                                 prod = ((subsegment * UINT64_C(720575941)) >> 24) + 1;
2149                                 print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
2150                                 ++buffer;
2151                             }
2152                             else
2153                             {
2154                                 prod = ((subsegment * UINT64_C(450359963)) >> 20) + 1;
2155                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2156                                 buffer += 2;
2157                             }
2158 
2159                             for (; digits_in_the_second_segment > 2; digits_in_the_second_segment -= 2)
2160                             {
2161                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2162                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2163                                 buffer += 2;
2164                             }
2165                         } // digits_in_the_second_segment <= 9
2166                         else 
2167                         {
2168                             // The number of digits in the segment is in the range 10 ~ 16.
2169                             const auto first_second_subsegments =
2170                                 fixed_point_calculator<ExtendedCache::max_cache_blocks>::
2171                                     generate_and_discard_lower(power_of_10[16], blocks,
2172                                                                 cache_block_count);
2173 
2174                             // The first segment is of 8 digits, and the second segment is of
2175                             // 2 ~ 8 digits.
2176                             // ceil(2^(64+14)/10^8) = 3022314549036573
2177                             // = floor(2^(64+14)*(10^8/(10^16 - 1)))
2178                             const auto first_subsegment =
2179                                 static_cast<std::uint32_t>(umul128_upper64(first_second_subsegments,
2180                                                                         UINT64_C(3022314549036573)) >>
2181                                                 14);
2182                             const auto second_subsegment =
2183                                 static_cast<std::uint32_t>(first_second_subsegments) -
2184                                 UINT32_C(100000000) * first_subsegment;
2185 
2186                             // Print the first subsegment.
2187                             print_8_digits(first_subsegment, buffer);
2188                             buffer += 8;
2189 
2190                             // Print the second subsegment.
2191                             // There are at least 2 digits in the second subsegment.
2192                             auto prod = ((second_subsegment * UINT64_C(140737489)) >> 15) + 1;
2193                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2194                             buffer += 2;
2195                             digits_in_the_second_segment -= 10;
2196 
2197                             for (; digits_in_the_second_segment > 1; digits_in_the_second_segment -= 2)
2198                             {
2199                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2200                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2201                                 buffer += 2;
2202                             }
2203 
2204                             if (digits_in_the_second_segment != 0)
2205                             {
2206                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2207                                 print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
2208                                 ++buffer;
2209                             }
2210                         }
2211                     } // digits_in_the_second_segment <= 16
2212                     else 
2213                     {
2214                         // The number of digits in the segment is in the range 17 ~ 22.
2215                         const auto first_subsegment =
2216                             fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(
2217                                 power_of_10[6], blocks, cache_block_count);
2218 
2219                         const auto second_third_subsegments =
2220                             fixed_point_calculator<ExtendedCache::max_cache_blocks>::
2221                                 generate_and_discard_lower(power_of_10[16], blocks,
2222                                                             cache_block_count);
2223 
2224                         // ceil(2^(64+14)/10^8) = 3022314549036573
2225                         // = floor(2^(64+14)*(10^8/(10^16 - 1)))
2226                         const auto second_subsegment =
2227                             static_cast<std::uint32_t>(umul128_upper64(second_third_subsegments,
2228                                                                     UINT64_C(3022314549036573)) >>
2229                                             14);
2230                         const auto third_subsegment = static_cast<std::uint32_t>(second_third_subsegments) -
2231                                                         UINT32_C(100000000) * second_subsegment;
2232 
2233                         // Print the first subsegment (1 ~ 6 digits).
2234                         std::uint64_t prod {};
2235                         auto remaining_digits_in_the_current_subsegment =
2236                             digits_in_the_second_segment - 16;
2237 
2238                         switch (remaining_digits_in_the_current_subsegment)
2239                         {
2240                         case 1:
2241                             prod = first_subsegment * UINT64_C(429496730);
2242                             goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining;
2243 
2244                         case 2:
2245                             prod = first_subsegment * UINT64_C(42949673);
2246                             goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining;
2247 
2248                         case 3:
2249                             prod = first_subsegment * UINT64_C(4294968);
2250                             goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining;
2251 
2252                         case 4:
2253                             prod = first_subsegment * UINT64_C(429497);
2254                             goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining;
2255 
2256                         case 5:
2257                             prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1;
2258                             goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining;
2259 
2260                         case 6:
2261                             prod = first_subsegment * UINT64_C(429497);
2262                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2263                             buffer += 2;
2264                             remaining_digits_in_the_current_subsegment = 4;
2265                             goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining;
2266 
2267                         default:
2268                             BOOST_UNREACHABLE_RETURN(prod); // NOLINT
2269                         }
2270 
2271                     second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining
2272                         :
2273                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2274                         print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
2275                         ++buffer;
2276 
2277                     second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining
2278                         :
2279                         for (; remaining_digits_in_the_current_subsegment > 1;
2280                                 remaining_digits_in_the_current_subsegment -= 2)
2281                         {
2282                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2283                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2284                             buffer += 2;
2285                         }
2286 
2287                         // Print the second and third subsegments (8 digits each).
2288                         print_8_digits(second_subsegment, buffer);
2289                         print_8_digits(third_subsegment, buffer + 8);
2290                         buffer += 16;
2291                     }
2292                 } // remaining_digits > digits_in_the_second_segment
2293 
2294                 // Perform rounding and return.
2295                 else
2296                 {
2297                     if (digits_in_the_second_segment <= 2)
2298                     {
2299                         fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(
2300                             power_of_10[19], blocks, cache_block_count);
2301 
2302                         // Get one more bit for potential rounding on the segment boundary.
2303                         auto subsegment =
2304                             fixed_point_calculator<ExtendedCache::max_cache_blocks>::
2305                                 generate_and_discard_lower(2000, blocks, cache_block_count);
2306 
2307                         bool segment_boundary_rounding_bit = ((subsegment & 1) != 0);
2308                         subsegment >>= 1;
2309 
2310                         if (digits_in_the_second_segment == 2)
2311                         {
2312                             // Convert subsegment into fixed-point fractional form where the
2313                             // integer part is of one digit. The integer part is ignored.
2314                             // 42949673 = ceil(2^32/10^2)
2315                             auto prod = static_cast<std::uint64_t>(subsegment) * UINT64_C(42949673);
2316 
2317                             if (remaining_digits == 1)
2318                             {
2319                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2320                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
2321                                 const bool has_further_digits_v = has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0);
2322                                 if (check_rounding_condition_inside_subsegment(current_digits, static_cast<std::uint32_t>(prod), 1, has_further_digits_v))
2323                                 {
2324                                     goto round_up_one_digit;
2325                                 }
2326                                 goto print_last_one_digit;
2327                             }
2328 
2329                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2330                             const auto next_digits = static_cast<std::uint32_t>(prod >> 32);
2331 
2332                             if (remaining_digits == 0)
2333                             {
2334                                 if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
2335                                         current_digits,
2336                                         uint_with_known_number_of_digits<2>{next_digits},
2337                                         has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) 
2338                                 {
2339                                     goto round_up_two_digits;
2340                                 }
2341                                 goto print_last_two_digits;
2342                             }
2343 
2344                             current_digits = next_digits;
2345                             BOOST_CHARCONV_ASSERT(remaining_digits == 2);
2346                         }
2347                         else
2348                         {
2349                             BOOST_CHARCONV_ASSERT(digits_in_the_second_segment == 1);
2350                             // Convert subsegment into fixed-point fractional form where the
2351                             // integer part is of two digits. The integer part is ignored.
2352                             // 429496730 = ceil(2^32/10^1)
2353                             auto prod = static_cast<std::uint64_t>(subsegment) * UINT64_C(429496730);
2354                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2355                             const auto next_digits = static_cast<std::uint32_t>(prod >> 32);
2356 
2357                             if (remaining_digits == 0) 
2358                             {
2359                                 if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
2360                                         current_digits,
2361                                         uint_with_known_number_of_digits<1>{next_digits},
2362                                         has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0)))
2363                                 {
2364                                     goto round_up_two_digits;
2365                                 }
2366                                 goto print_last_two_digits;
2367                             }
2368 
2369                             current_digits = next_digits;
2370                             BOOST_CHARCONV_ASSERT(remaining_digits == 1);
2371                         }
2372 
2373                         if (check_rounding_condition_with_next_bit(
2374                                 current_digits, segment_boundary_rounding_bit,
2375                                 has_further_digits<0, 0, ExtendedCache>(significand, exp2_base, k, uconst0, uconst0))) 
2376                         {
2377                             goto round_up;
2378                         }
2379 
2380                         goto print_last_digits;
2381                     } // digits_in_the_second_segment <= 2
2382 
2383                     // When there are at most 9 digits in the segment.
2384                     if (digits_in_the_second_segment <= 9)
2385                     {
2386                         // Throw away all overlapping digits.
2387                         BOOST_CHARCONV_ASSERT(22 - digits_in_the_second_segment <= 19);
2388 
2389                         fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(
2390                             compute_power(UINT64_C(10), 22 - digits_in_the_second_segment),
2391                             blocks, cache_block_count);
2392 
2393                         // Get one more bit for potential rounding on the segment boundary.
2394                         auto segment = fixed_point_calculator<ExtendedCache::max_cache_blocks>::
2395                             generate_and_discard_lower(power_of_10[9] << 1, blocks,
2396                                                         cache_block_count);
2397 
2398                         std::uint64_t prod;
2399                         digits_in_the_second_segment -= remaining_digits;
2400 
2401                         if ((remaining_digits & 1) != 0)
2402                         {
2403                             prod = ((segment * UINT64_C(1441151881)) >> 26) + 1;
2404                             current_digits = static_cast<std::uint32_t>(prod >> 32);
2405 
2406                             if (remaining_digits == 1)
2407                             {
2408                                 goto second_segment22_at_most_9_digits_rounding;
2409                             }
2410 
2411                             print_1_digit(current_digits, buffer);
2412                             ++buffer;
2413                         }
2414                         else 
2415                         {
2416                             prod = ((segment * UINT64_C(1801439851)) >> 23) + 1;
2417                             const auto next_digits = static_cast<std::uint32_t>(prod >> 32);
2418 
2419                             if (remaining_digits == 0)
2420                             {
2421                                 if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
2422                                         current_digits,
2423                                         uint_with_known_number_of_digits<2>{next_digits}, [&] {
2424                                             return static_cast<std::uint32_t>(prod) >=
2425                                                         (additional_static_data_holder::
2426                                                             fractional_part_rounding_thresholds32[digits_in_the_second_segment - 3] & UINT32_C(0x7fffffff))
2427                                                     || has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0);
2428                                         })) 
2429                                 {
2430                                     goto round_up_two_digits;
2431                                 }
2432                                 goto print_last_two_digits;
2433                             }
2434                             else if (remaining_digits == 2)
2435                             {
2436                                 current_digits = next_digits;
2437                                 goto second_segment22_at_most_9_digits_rounding;
2438                             }
2439 
2440                             print_2_digits(next_digits, buffer);
2441                             buffer += 2;
2442                         }
2443 
2444                         BOOST_CHARCONV_ASSERT(remaining_digits >= 3);
2445 
2446                         for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
2447                         {
2448                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2449                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2450                             buffer += 2;
2451                         }
2452 
2453                         if (digits_in_the_second_segment != 0) 
2454                         {
2455                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2456                             current_digits = static_cast<std::uint32_t>(prod >> 32);
2457                             remaining_digits = 0;
2458 
2459                         second_segment22_at_most_9_digits_rounding:
2460                             if (check_rounding_condition_inside_subsegment(
2461                                     current_digits, static_cast<std::uint32_t>(prod),
2462                                     digits_in_the_second_segment, has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1,
2463                                     uconst0))) 
2464                             {
2465                                 goto round_up;
2466                             }
2467 
2468                             goto print_last_digits;
2469                         }
2470                         else
2471                         {
2472                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(200);
2473                             current_digits = static_cast<std::uint32_t>(prod >> 32);
2474                             const auto segment_boundary_rounding_bit = (current_digits & 1) != 0;
2475                             current_digits >>= 1;
2476 
2477                             if (check_rounding_condition_with_next_bit(
2478                                     current_digits, segment_boundary_rounding_bit,
2479                                     has_further_digits<0, 1, ExtendedCache>(significand, exp2_base, k, uconst0, uconst1)))
2480                             {
2481                                 goto round_up_two_digits;
2482                             }
2483                             goto print_last_two_digits;
2484                         }
2485                     } // digits_in_the_second_segment <= 9
2486 
2487                     // first_second_subsegments is of 1 ~ 13 digits, and third_subsegment is
2488                     // of 9 digits.
2489                     // Get one more bit for potential rounding condition check.
2490                     auto first_second_subsegments =
2491                         fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(
2492                             power_of_10[13] << 1, blocks, cache_block_count);
2493                     
2494                     bool first_bit_of_third_subsegment = ((first_second_subsegments & 1) != 0);
2495                     first_second_subsegments >>= 1;
2496 
2497                     // Compilers are not aware of how to leverage the maximum value of
2498                     // first_second_subsegments to find out a better magic number which
2499                     // allows us to eliminate an additional shift.
2500                     // 1844674407371 = ceil(2^64/10^7) = floor(2^64*(10^6/(10^13 - 1))).
2501                     const auto first_subsegment =
2502                         static_cast<std::uint32_t>(boost::charconv::detail::umul128_upper64(
2503                             first_second_subsegments, 1844674407371));
2504 
2505                     const auto second_subsegment =
2506                         static_cast<std::uint32_t>(first_second_subsegments) - 10000000 * first_subsegment;
2507 
2508                     int digits_in_the_second_subsegment;
2509 
2510                     // Print the first subsegment (0 ~ 6 digits) if exists.
2511                     if (digits_in_the_second_segment > 16)
2512                     {
2513                         std::uint64_t prod;
2514                         int remaining_digits_in_the_current_subsegment = digits_in_the_second_segment - 16;
2515 
2516                         // No rounding, continue.
2517                         if (remaining_digits > remaining_digits_in_the_current_subsegment)
2518                         {
2519                             remaining_digits -= remaining_digits_in_the_current_subsegment;
2520 
2521                             // There is no overlap in the second subsegment.
2522                             digits_in_the_second_subsegment = 7;
2523 
2524                             // When there is no overlapping digit.
2525                             if (remaining_digits_in_the_current_subsegment == 6)
2526                             {
2527                                 prod = (first_subsegment * UINT64_C(429497)) + 1;
2528                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2529                                 buffer += 2;
2530                                 remaining_digits_in_the_current_subsegment -= 2;
2531                             }
2532                             // If there are overlapping digits, move all overlapping digits
2533                             // into the integer part.
2534                             else 
2535                             {
2536                                 prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1;
2537                                 prod *= compute_power(UINT64_C(10), 5 - remaining_digits_in_the_current_subsegment);
2538 
2539                                 if ((remaining_digits_in_the_current_subsegment & 1) != 0) 
2540                                 {
2541                                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2542                                     print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
2543                                     ++buffer;
2544                                 }
2545                             }
2546 
2547                             for (; remaining_digits_in_the_current_subsegment > 1; remaining_digits_in_the_current_subsegment -= 2) 
2548                             {
2549                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2550                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2551                                 buffer += 2;
2552                             }
2553                         }
2554                         // The first subsegment is the last subsegment to print.
2555                         else
2556                         {
2557                             if ((remaining_digits & 1) != 0)
2558                             {
2559                                 prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1;
2560 
2561                                 // If there are overlapping digits, move all overlapping digits
2562                                 // into the integer part and then get the next digit.
2563                                 if (remaining_digits_in_the_current_subsegment < 6)
2564                                 {
2565                                     prod *= compute_power(UINT64_C(10), 5 - remaining_digits_in_the_current_subsegment);
2566                                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2567                                 }
2568                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
2569                                 remaining_digits_in_the_current_subsegment -= remaining_digits;
2570 
2571                                 if (remaining_digits == 1) 
2572                                 {
2573                                     goto second_segment22_more_than_9_digits_first_subsegment_rounding;
2574                                 }
2575 
2576                                 print_1_digit(current_digits, buffer);
2577                                 ++buffer;
2578                             }
2579                             else 
2580                             {
2581                                 // When there is no overlapping digit.
2582                                 if (remaining_digits_in_the_current_subsegment == 6) 
2583                                 {
2584                                     if (remaining_digits == 0)
2585                                     {
2586                                         if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
2587                                                 current_digits,
2588                                                 uint_with_known_number_of_digits<6>{
2589                                                     first_subsegment},
2590                                                 has_further_digits<1, 16, ExtendedCache>(significand, exp2_base, k, uconst1, uconst16)))
2591                                         {
2592                                             goto round_up_two_digits;
2593                                         }
2594                                         goto print_last_two_digits;
2595                                     }
2596 
2597                                     prod = (first_subsegment * UINT64_C(429497)) + 1;
2598                                 }
2599                                 // Otherwise, convert the subsegment into a fixed-point
2600                                 // fraction form, move all overlapping digits into the
2601                                 // integer part, and then extract the next two digits.
2602                                 else 
2603                                 {
2604                                     prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1;
2605                                     prod *= compute_power(UINT64_C(10), 5 - remaining_digits_in_the_current_subsegment);
2606 
2607                                     if (remaining_digits == 0)
2608                                     {
2609                                         goto second_segment22_more_than_9_digits_first_subsegment_rounding_inside_subsegment;
2610                                     }
2611 
2612                                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2613                                 }
2614                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
2615                                 remaining_digits_in_the_current_subsegment -= remaining_digits;
2616 
2617                                 if (remaining_digits == 2)
2618                                 {
2619                                     goto second_segment22_more_than_9_digits_first_subsegment_rounding;
2620                                 }
2621 
2622                                 print_2_digits(current_digits, buffer);
2623                                 buffer += 2;
2624                             }
2625 
2626                             BOOST_CHARCONV_ASSERT(remaining_digits >= 3);
2627 
2628                             if (remaining_digits > 4)
2629                             {
2630                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2631                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2632                                 buffer += 2;
2633                             }
2634 
2635                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2636                             current_digits = static_cast<std::uint32_t>(prod >> 32);
2637                             remaining_digits = 0;
2638 
2639                         second_segment22_more_than_9_digits_first_subsegment_rounding:
2640                             if (remaining_digits_in_the_current_subsegment == 0) 
2641                             {
2642                                 if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
2643                                         current_digits,
2644                                         uint_with_known_number_of_digits<7>{second_subsegment},
2645                                         has_further_digits<1, 9, ExtendedCache>(significand, exp2_base, k, uconst1, uconst9))) 
2646                                 {
2647                                     goto round_up;
2648                                 }
2649                             }
2650                             else 
2651                             {
2652                             second_segment22_more_than_9_digits_first_subsegment_rounding_inside_subsegment
2653                                 :
2654                                 if (check_rounding_condition_inside_subsegment(
2655                                         current_digits, static_cast<std::uint32_t>(prod),
2656                                         remaining_digits_in_the_current_subsegment,
2657                                         has_further_digits<1, 16, ExtendedCache>(significand, exp2_base, k, uconst1, uconst16)))
2658                                 {
2659                                     goto round_up;
2660                                 }
2661                             }
2662                             goto print_last_digits;
2663                         }
2664                     }
2665                     else
2666                     {
2667                         digits_in_the_second_subsegment = digits_in_the_second_segment - 9;
2668                     }
2669 
2670                     // Print the second subsegment (1 ~ 7 digits).
2671                     {
2672                         // No rounding, continue.
2673                         if (remaining_digits > digits_in_the_second_subsegment) 
2674                         {
2675                             auto prod = ((second_subsegment * UINT64_C(17592187)) >> 12) + 1;
2676                             remaining_digits -= digits_in_the_second_subsegment;
2677 
2678                             // When there is no overlapping digit.
2679                             if (digits_in_the_second_subsegment == 7)
2680                             {
2681                                 print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
2682                                 ++buffer;
2683                             }
2684                             // If there are overlapping digits, move all overlapping digits
2685                             // into the integer part.
2686                             else
2687                             {
2688                                 prod *= compute_power(UINT64_C(10),
2689                                                         6 - digits_in_the_second_subsegment);
2690 
2691                                 if ((digits_in_the_second_subsegment & 1) != 0)
2692                                 {
2693                                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2694                                     print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
2695                                     ++buffer;
2696                                 }
2697                             }
2698 
2699                             for (; digits_in_the_second_subsegment > 1; digits_in_the_second_subsegment -= 2)
2700                             {
2701                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2702                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2703                                 buffer += 2;
2704                             }
2705                         }
2706                         // The second subsegment is the last subsegment to print.
2707                         else
2708                         {
2709                             std::uint64_t prod;
2710 
2711                             if ((remaining_digits & 1) != 0)
2712                             {
2713                                 prod = ((second_subsegment * UINT64_C(17592187)) >> 12) + 1;
2714 
2715                                 // If there are overlapping digits, move all overlapping digits
2716                                 // into the integer part and then get the next digit.
2717                                 if (digits_in_the_second_subsegment < 7) 
2718                                 {
2719                                     prod *= compute_power(UINT64_C(10), 6 - digits_in_the_second_subsegment);
2720                                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2721                                 }
2722                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
2723                                 digits_in_the_second_subsegment -= remaining_digits;
2724 
2725                                 if (remaining_digits == 1)
2726                                 {
2727                                     goto second_segment22_more_than_9_digits_second_subsegment_rounding;
2728                                 }
2729 
2730                                 print_1_digit(current_digits, buffer);
2731                                 ++buffer;
2732                             }
2733                             else
2734                             {
2735                                 // When there is no overlapping digit.
2736                                 if (digits_in_the_second_subsegment == 7)
2737                                 {
2738                                     if (remaining_digits == 0)
2739                                     {
2740                                         if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
2741                                                 current_digits,
2742                                                 uint_with_known_number_of_digits<7>{
2743                                                     second_subsegment},
2744                                                 has_further_digits<1, 9, ExtendedCache>(significand, exp2_base, k, uconst1, uconst9)))
2745                                         {
2746                                             goto round_up_two_digits;
2747                                         }
2748                                         goto print_last_two_digits;
2749                                     }
2750 
2751                                     prod = ((second_subsegment * UINT64_C(10995117)) >> 8) + 1;
2752                                 }
2753                                 // Otherwise, convert the subsegment into a fixed-point
2754                                 // fraction form, move all overlapping digits into the
2755                                 // integer part, and then extract the next two digits.
2756                                 else 
2757                                 {
2758                                     prod = ((second_subsegment * UINT64_C(17592187)) >> 12) + 1;
2759                                     prod *= compute_power(UINT64_C(10), 6 - digits_in_the_second_subsegment);
2760 
2761                                     if (remaining_digits == 0)
2762                                     {
2763                                         goto second_segment22_more_than_9_digits_second_subsegment_rounding_inside_subsegment;
2764                                     }
2765 
2766                                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2767                                 }
2768                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
2769                                 digits_in_the_second_subsegment -= remaining_digits;
2770 
2771                                 if (remaining_digits == 2)
2772                                 {
2773                                     goto second_segment22_more_than_9_digits_second_subsegment_rounding;
2774                                 }
2775 
2776                                 print_2_digits(current_digits, buffer);
2777                                 buffer += 2;
2778                             }
2779 
2780                             BOOST_CHARCONV_ASSERT(remaining_digits >= 3);
2781 
2782                             if (remaining_digits > 4)
2783                             {
2784                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2785                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2786                                 buffer += 2;
2787                             }
2788 
2789                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2790                             current_digits = static_cast<std::uint32_t>(prod >> 32);
2791                             remaining_digits = 0;
2792 
2793                         second_segment22_more_than_9_digits_second_subsegment_rounding:
2794                             if (digits_in_the_second_subsegment == 0)
2795                             {
2796                                 if (check_rounding_condition_with_next_bit(
2797                                         current_digits, first_bit_of_third_subsegment,
2798                                         has_further_digits<0, 9, ExtendedCache>(significand, exp2_base, k, uconst0, uconst9)))
2799                                 {
2800                                     goto round_up;
2801                                 }
2802                             }
2803                             else
2804                             {
2805                             second_segment22_more_than_9_digits_second_subsegment_rounding_inside_subsegment
2806                                 :
2807                                 if (check_rounding_condition_inside_subsegment(
2808                                         current_digits, static_cast<std::uint32_t>(prod),
2809                                         digits_in_the_second_subsegment, has_further_digits<1, 9, ExtendedCache>(significand, exp2_base, k,
2810                                         uconst1, uconst9)))
2811                                 {
2812                                     goto round_up;
2813                                 }
2814                             }
2815                             goto print_last_digits;
2816                         }
2817                     }
2818 
2819                     // Print the third subsegment (9 digits).
2820                     {
2821                         // Get one more bit if we need to check rounding conditions on
2822                         // the segment boundary. We already have shifted by 1-bit in the
2823                         // computation of first & second subsegments, so here we don't
2824                         // shift the multiplier.
2825                         auto third_subsegment =
2826                             fixed_point_calculator<ExtendedCache::max_cache_blocks>::
2827                                 generate_and_discard_lower(power_of_10[9], blocks,
2828                                                             cache_block_count);
2829 
2830                         bool segment_boundary_rounding_bit = ((third_subsegment & 1) != 0);
2831                         third_subsegment >>= 1;
2832                         third_subsegment += (first_bit_of_third_subsegment ? 500000000 : 0);
2833 
2834                         std::uint64_t prod;
2835                         if ((remaining_digits & 1) != 0)
2836                         {
2837                             prod = ((third_subsegment * UINT64_C(720575941)) >> 24) + 1;
2838                             current_digits = static_cast<std::uint32_t>(prod >> 32);
2839 
2840                             if (remaining_digits == 1) 
2841                             {
2842                                 if (check_rounding_condition_inside_subsegment(
2843                                         current_digits, static_cast<std::uint32_t>(prod), 8,
2844                                         has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) 
2845                                 {
2846                                     goto round_up_one_digit;
2847                                 }
2848                                 goto print_last_one_digit;
2849                             }
2850 
2851                             print_1_digit(current_digits, buffer);
2852                             ++buffer;
2853                         }
2854                         else 
2855                         {
2856                             prod = ((third_subsegment * UINT64_C(450359963)) >> 20) + 1;
2857                             current_digits = static_cast<std::uint32_t>(prod >> 32);
2858 
2859                             if (remaining_digits == 2) 
2860                             {
2861                                 goto second_segment22_more_than_9_digits_third_subsegment_rounding;
2862                             }
2863 
2864                             print_2_digits(current_digits, buffer);
2865                             buffer += 2;
2866                         }
2867 
2868                         for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
2869                         {
2870                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2871                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2872                             buffer += 2;
2873                         }
2874 
2875                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2876                         current_digits = static_cast<std::uint32_t>(prod >> 32);
2877 
2878                         if (remaining_digits < 9)
2879                         {
2880                         second_segment22_more_than_9_digits_third_subsegment_rounding:
2881                             if (check_rounding_condition_inside_subsegment(
2882                                     current_digits, static_cast<std::uint32_t>(prod), 9 - remaining_digits,
2883                                     has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0)))
2884                             {
2885                                 goto round_up_two_digits;
2886                             }
2887                         }
2888                         else 
2889                         {
2890                             if (check_rounding_condition_with_next_bit(
2891                                     current_digits, segment_boundary_rounding_bit,
2892                                     has_further_digits<0, 0, ExtendedCache>(significand, exp2_base, k, uconst0, uconst0))) 
2893                             {
2894                                 goto round_up_two_digits;
2895                             }
2896                         }
2897                         goto print_last_two_digits;
2898                     }
2899                 }
2900             } // ExtendedCache::segment_length == 22
2901 
2902             else BOOST_CHARCONV_IF_CONSTEXPR (ExtendedCache::segment_length == 252)
2903             {
2904                 int overlapping_digits = 252 - digits_in_the_second_segment;
2905                 int remaining_subsegment_pairs = 14;
2906 
2907                 while (overlapping_digits >= 18)
2908                 {
2909                     fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(
2910                         power_of_10[18], blocks, cache_block_count);
2911                     --remaining_subsegment_pairs;
2912                     overlapping_digits -= 18;
2913                 }
2914 
2915                 auto subsegment_pair = fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[18] << 1, blocks, cache_block_count);
2916                 auto subsegment_boundary_rounding_bit = (subsegment_pair & 1) != 0;
2917                 subsegment_pair >>= 1;
2918 
2919                 // Deal with the first subsegment pair.
2920                 {
2921                     // Divide it into two 9-digits subsegments.
2922                     const auto first_part = static_cast<std::uint32_t>(subsegment_pair / power_of_10[9]);
2923                     const auto second_part = static_cast<std::uint32_t>(subsegment_pair - power_of_10[9] * first_part);
2924 
2925                     auto print_subsegment = [&](std::uint32_t subsegment, int digits_in_the_subsegment)
2926                     {
2927                         remaining_digits -= digits_in_the_subsegment;
2928 
2929                         // Move all overlapping digits into the integer part.
2930                         auto prod = ((subsegment * UINT64_C(720575941)) >> 24) + 1;
2931                         if (digits_in_the_subsegment < 9) 
2932                         {
2933                             prod *= compute_power(UINT32_C(10), 8 - digits_in_the_subsegment);
2934 
2935                             if ((digits_in_the_subsegment & 1) != 0) 
2936                             {
2937                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
2938                                 print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
2939                                 ++buffer;
2940                             }
2941                         }
2942                         else 
2943                         {
2944                             print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer);
2945                             ++buffer;
2946                         }
2947 
2948                         for (; digits_in_the_subsegment > 1; digits_in_the_subsegment -= 2) 
2949                         {
2950                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
2951                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
2952                             buffer += 2;
2953                         }
2954                     };
2955 
2956                     // When the first part is not completely overlapping with the first segment.
2957                     int digits_in_the_second_part;
2958                     if (overlapping_digits < 9) 
2959                     {
2960                         int digits_in_the_first_part = 9 - overlapping_digits;
2961 
2962                         // No rounding, continue.
2963                         if (remaining_digits > digits_in_the_first_part) 
2964                         {
2965                             digits_in_the_second_part = 9;
2966                             print_subsegment(first_part, digits_in_the_first_part);
2967                         }
2968                         // Perform rounding and return.
2969                         else 
2970                         {
2971                             // When there is no overlapping digit.
2972                             std::uint64_t prod;
2973                             if (digits_in_the_first_part == 9)
2974                             {
2975                                 if ((remaining_digits & 1) != 0) 
2976                                 {
2977                                     prod = ((first_part * UINT64_C(720575941)) >> 24) + 1;
2978                                 }
2979                                 else 
2980                                 {
2981                                     if (remaining_digits == 0) 
2982                                     {
2983                                         if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
2984                                                 current_digits,
2985                                                 uint_with_known_number_of_digits<9>{first_part},
2986                                                 compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
2987                                         {
2988                                             goto round_up_two_digits;
2989                                         }
2990                                         goto print_last_two_digits;
2991                                     }
2992 
2993                                     prod = ((first_part * UINT64_C(450359963)) >> 20) + 1;
2994                                 }
2995                             }
2996                             else 
2997                             {
2998                                 prod = ((first_part * UINT64_C(720575941)) >> 24) + 1;
2999                                 prod *= compute_power(UINT32_C(10), 8 - digits_in_the_first_part);
3000 
3001                                 if ((remaining_digits & 1) != 0) 
3002                                 {
3003                                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
3004                                 }
3005                                 else 
3006                                 {
3007                                     if (remaining_digits == 0) 
3008                                     {
3009                                         goto second_segment252_first_subsegment_rounding_inside_subsegment;
3010                                     }
3011 
3012                                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3013                                 }
3014                             }
3015                             digits_in_the_first_part -= remaining_digits;
3016                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3017 
3018                             if (remaining_digits > 2) 
3019                             {
3020                                 if ((remaining_digits & 1) != 0) 
3021                                 {
3022                                     print_1_digit(current_digits, buffer);
3023                                     ++buffer;
3024                                 }
3025                                 else 
3026                                 {
3027                                     print_2_digits(current_digits, buffer);
3028                                     buffer += 2;
3029                                 }
3030 
3031                                 for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
3032                                 {
3033                                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3034                                     print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3035                                     buffer += 2;
3036                                 }
3037 
3038                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3039                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
3040                                 remaining_digits = 0;
3041                             }
3042 
3043                             if (digits_in_the_first_part != 0)
3044                             {
3045                             second_segment252_first_subsegment_rounding_inside_subsegment:
3046                                 if (check_rounding_condition_inside_subsegment(
3047                                         current_digits, static_cast<std::uint32_t>(prod),
3048                                         digits_in_the_first_part, compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) 
3049                                 {
3050                                     goto round_up;
3051                                 }
3052                             }
3053                             else 
3054                             {
3055                                 if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
3056                                         current_digits,
3057                                         uint_with_known_number_of_digits<9>{static_cast<std::uint32_t>(second_part)},
3058                                         compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3059                                 {
3060                                     goto round_up;
3061                                 }
3062                             }
3063                             goto print_last_digits;
3064                         }
3065                     }
3066                     else
3067                     {
3068                         digits_in_the_second_part = 18 - overlapping_digits;
3069                     }
3070 
3071                     // Print the second part.
3072                     // No rounding, continue.
3073                     if (remaining_digits > digits_in_the_second_part)
3074                     {
3075                         print_subsegment(second_part, digits_in_the_second_part);
3076                     }
3077                     // Perform rounding and return.
3078                     else
3079                     {
3080                         // When there is no overlapping digit.
3081                         std::uint64_t prod;
3082                         if (digits_in_the_second_part == 9)
3083                         {
3084                             if ((remaining_digits & 1) != 0)
3085                             {
3086                                 prod = ((second_part * UINT64_C(720575941)) >> 24) + 1;
3087                             }
3088                             else 
3089                             {
3090                                 if (remaining_digits == 0)
3091                                 {
3092                                     if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
3093                                             current_digits,
3094                                             uint_with_known_number_of_digits<9>{static_cast<std::uint32_t>(second_part)},
3095                                             compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) 
3096                                     {
3097                                         goto round_up_two_digits;
3098                                     }
3099                                     goto print_last_two_digits;
3100                                 }
3101 
3102                                 prod = ((second_part * UINT64_C(450359963)) >> 20) + 1;
3103                             }
3104                         }
3105                         else 
3106                         {
3107                             prod = ((second_part * UINT64_C(720575941)) >> 24) + 1;
3108                             prod *= compute_power(UINT32_C(10), 8 - digits_in_the_second_part);
3109 
3110                             if ((remaining_digits & 1) != 0)
3111                             {
3112                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
3113                             }
3114                             else 
3115                             {
3116                                 if (remaining_digits == 0) 
3117                                 {
3118                                     goto second_segment252_second_subsegment_rounding_inside_subsegment;
3119                                 }
3120 
3121                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3122                             }
3123                         }
3124                         digits_in_the_second_part -= remaining_digits;
3125                         current_digits = static_cast<std::uint32_t>(prod >> 32);
3126 
3127                         if (remaining_digits > 2)
3128                         {
3129                             if ((remaining_digits & 1) != 0) 
3130                             {
3131                                 print_1_digit(current_digits, buffer);
3132                                 ++buffer;
3133                             }
3134                             else 
3135                             {
3136                                 print_2_digits(current_digits, buffer);
3137                                 buffer += 2;
3138                             }
3139 
3140                             for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
3141                             {
3142                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3143                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3144                                 buffer += 2;
3145                             }
3146 
3147                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3148                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3149                             remaining_digits = 0;
3150                         }
3151 
3152                         if (digits_in_the_second_part != 0)
3153                         {
3154                         second_segment252_second_subsegment_rounding_inside_subsegment:
3155                             if (check_rounding_condition_inside_subsegment(
3156                                     current_digits, static_cast<std::uint32_t>(prod),
3157                                     digits_in_the_second_part, compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3158                             {
3159                                 goto round_up;
3160                             }
3161                         }
3162                         else 
3163                         {
3164                             if (check_rounding_condition_with_next_bit(
3165                                     current_digits, subsegment_boundary_rounding_bit,
3166                                     compute_has_further_digits<0, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3167                             {
3168                                 goto round_up;
3169                             }
3170                         }
3171                         goto print_last_digits;
3172                     }
3173                 }
3174 
3175                 // Remaining subsegment pairs do not have overlapping digits.
3176                 --remaining_subsegment_pairs;
3177                 for (; remaining_subsegment_pairs > 0; --remaining_subsegment_pairs) 
3178                 {
3179                     subsegment_pair = fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[18], blocks, cache_block_count);
3180 
3181                     subsegment_pair += (subsegment_boundary_rounding_bit ? power_of_10[18] : 0);
3182                     subsegment_boundary_rounding_bit = (subsegment_pair & 1) != 0;
3183                     subsegment_pair >>= 1;
3184 
3185                     const auto first_part = static_cast<std::uint32_t>(subsegment_pair / power_of_10[9]);
3186                     const auto second_part = static_cast<std::uint32_t>(subsegment_pair - power_of_10[9] * first_part);
3187 
3188                     // The first part can be printed without rounding.
3189                     if (remaining_digits > 9)
3190                     {
3191                         print_9_digits(first_part, buffer);
3192 
3193                         // The second part also can be printed without rounding.
3194                         if (remaining_digits > 18) 
3195                         {
3196                             print_9_digits(second_part, buffer + 9);
3197                         }
3198                         // Otherwise, perform rounding and return.
3199                         else
3200                         {
3201                             buffer += 9;
3202                             remaining_digits -= 9;
3203 
3204                             std::uint64_t prod;
3205                             int remaining_digits_in_the_current_subsegment = 9 - remaining_digits;
3206 
3207                             if ((remaining_digits & 1) != 0)
3208                             {
3209                                 prod = ((second_part * UINT64_C(720575941)) >> 24) + 1;
3210                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
3211 
3212                                 if (remaining_digits == 1)
3213                                 {
3214                                     goto second_segment252_loop_second_subsegment_rounding;
3215                                 }
3216 
3217                                 print_1_digit(current_digits, buffer);
3218                                 ++buffer;
3219                             }
3220                             else
3221                             {
3222                                 prod = ((second_part * UINT64_C(450359963)) >> 20) + 1;
3223                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
3224 
3225                                 if (remaining_digits == 2)
3226                                 {
3227                                     goto second_segment252_loop_second_subsegment_rounding;
3228                                 }
3229 
3230                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3231                                 buffer += 2;
3232                             }
3233 
3234                             for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
3235                             {
3236                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3237                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3238                                 buffer += 2;
3239                             }
3240 
3241                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3242                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3243                             remaining_digits = 0;
3244 
3245                             if (remaining_digits_in_the_current_subsegment != 0) 
3246                             {
3247                             second_segment252_loop_second_subsegment_rounding:
3248                                 if (check_rounding_condition_inside_subsegment(
3249                                         current_digits, static_cast<std::uint32_t>(prod),
3250                                         remaining_digits_in_the_current_subsegment,
3251                                         compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3252                                 {
3253                                     goto round_up;
3254                                 }
3255                                 goto print_last_digits;
3256                             }
3257                             else 
3258                             {
3259                                 if (check_rounding_condition_with_next_bit(
3260                                         current_digits, subsegment_boundary_rounding_bit,
3261                                         compute_has_further_digits<0, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3262                                 {
3263                                     goto round_up_two_digits;
3264                                 }
3265                                 goto print_last_two_digits;
3266                             }
3267                         }
3268                     }
3269                     // Otherwise, perform rounding and return.
3270                     else
3271                     {
3272                         std::uint64_t prod;
3273                         int remaining_digits_in_the_current_subsegment = 9 - remaining_digits;
3274                         if ((remaining_digits & 1) != 0) 
3275                         {
3276                             prod = ((first_part * UINT64_C(720575941)) >> 24) + 1;
3277                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3278 
3279                             if (remaining_digits == 1) 
3280                             {
3281                                 goto second_segment252_loop_first_subsegment_rounding;
3282                             }
3283 
3284                             print_1_digit(current_digits, buffer);
3285                             ++buffer;
3286                         }
3287                         else
3288                         {
3289                             prod = ((first_part * UINT64_C(450359963)) >> 20) + 1;
3290                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3291 
3292                             if (remaining_digits == 2)
3293                             {
3294                                 goto second_segment252_loop_first_subsegment_rounding;
3295                             }
3296 
3297                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3298                             buffer += 2;
3299                         }
3300 
3301                         for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
3302                         {
3303                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3304                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3305                             buffer += 2;
3306                         }
3307 
3308                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3309                         current_digits = static_cast<std::uint32_t>(prod >> 32);
3310                         remaining_digits = 0;
3311 
3312                         if (remaining_digits_in_the_current_subsegment != 0)
3313                         {
3314                         second_segment252_loop_first_subsegment_rounding:
3315                             if (check_rounding_condition_inside_subsegment(
3316                                     current_digits, static_cast<std::uint32_t>(prod),
3317                                     remaining_digits_in_the_current_subsegment,
3318                                     compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3319                             {
3320                                 goto round_up;
3321                             }
3322                             goto print_last_digits;
3323                         }
3324                         else
3325                         {
3326                             if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
3327                                     current_digits,
3328                                     uint_with_known_number_of_digits<9>{static_cast<std::uint32_t>(second_part)},
3329                                     compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3330                             {
3331                                 goto round_up_two_digits;
3332                             }
3333                             goto print_last_two_digits;
3334                         }
3335                     }
3336 
3337                     buffer += 18;
3338                     remaining_digits -= 18;
3339                 }
3340             } // ExtendedCache::segment_length == 252
3341         }
3342 
3343         // Print all remaining segments.
3344         while (has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))
3345         {
3346             // Get new segment.
3347             ++multiplier_index;
3348             k += ExtendedCache::segment_length;
3349 
3350             cache_block_count = load_extended_cache<ExtendedCache, ExtendedCache::constant_block_count>(blocks, e, k, multiplier_index);
3351 
3352             // Compute nm mod 2^Q.
3353             fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(significand, blocks, cache_block_count);
3354 
3355             BOOST_CHARCONV_IF_CONSTEXPR (ExtendedCache::segment_length == 22)
3356             {
3357                 // When at least two subsegments left.
3358                 if (remaining_digits > 16) 
3359                 {
3360                     std::uint64_t first_second_subsegments = fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[16], blocks, cache_block_count);
3361 
3362                     const auto first_subsegment =
3363                         static_cast<std::uint32_t>(boost::charconv::detail::umul128_upper64(first_second_subsegments, UINT64_C(3022314549036573)) >> 14);
3364                     
3365                     const std::uint32_t second_subsegment = static_cast<std::uint32_t>(first_second_subsegments) - UINT32_C(100000000) * first_subsegment;
3366 
3367                     print_8_digits(first_subsegment, buffer);
3368                     print_8_digits(second_subsegment, buffer + 8);
3369 
3370                     // When more segments left.
3371                     if (remaining_digits > 22)
3372                     {
3373                         const auto third_subsegment = static_cast<std::uint32_t>(
3374                             fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate_and_discard_lower(power_of_10[6], blocks,cache_block_count));
3375 
3376                         print_6_digits(third_subsegment, buffer + 16);
3377                         buffer += 22;
3378                         remaining_digits -= 22;
3379                     }
3380                     // When this is the last segment.
3381                     else
3382                     {
3383                         buffer += 16;
3384                         remaining_digits -= 16;
3385 
3386                         auto third_subsegment = fixed_point_calculator<ExtendedCache::max_cache_blocks>::
3387                             generate_and_discard_lower(power_of_10[6] << 1, blocks, cache_block_count);
3388 
3389                         bool segment_boundary_rounding_bit = ((third_subsegment & 1) != 0);
3390                         third_subsegment >>= 1;
3391 
3392                         std::uint64_t prod;
3393                         if ((remaining_digits & 1) != 0)
3394                         {
3395                             prod = ((third_subsegment * UINT64_C(687195)) >> 4) + 1;
3396                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3397 
3398                             if (remaining_digits == 1)
3399                             {
3400                                 if (check_rounding_condition_inside_subsegment(
3401                                         current_digits, static_cast<std::uint32_t>(prod), 5,
3402                                         has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) 
3403                                 {
3404                                     goto round_up_one_digit;
3405                                 }
3406                                 goto print_last_one_digit;
3407                             }
3408 
3409                             print_1_digit(current_digits, buffer);
3410                             ++buffer;
3411                         }
3412                         else
3413                         {
3414                             prod = (third_subsegment * UINT64_C(429497)) + 1;
3415                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3416 
3417                             if (remaining_digits == 2)
3418                             {
3419                                 goto segment_loop22_more_than_16_digits_rounding;
3420                             }
3421 
3422                             print_2_digits(current_digits, buffer);
3423                             buffer += 2;
3424                         }
3425 
3426                         if (remaining_digits > 4)
3427                         {
3428                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3429                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3430                             buffer += 2;
3431 
3432                             if (remaining_digits == 6)
3433                             {
3434                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3435                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
3436 
3437                                 if (check_rounding_condition_with_next_bit(
3438                                         current_digits, segment_boundary_rounding_bit,
3439                                         has_further_digits<0, 0, ExtendedCache>(significand, exp2_base, k, uconst0, uconst0)))
3440                                 {
3441                                     goto round_up_two_digits;
3442                                 }
3443                                 goto print_last_two_digits;
3444                             }
3445                         }
3446 
3447                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3448                         current_digits = static_cast<std::uint32_t>(prod >> 32);
3449 
3450                     segment_loop22_more_than_16_digits_rounding:
3451                         if (check_rounding_condition_inside_subsegment(
3452                                 current_digits, static_cast<std::uint32_t>(prod), 6 - remaining_digits,
3453                                 has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0)))
3454                         {
3455                             goto round_up_two_digits;
3456                         }
3457                         goto print_last_two_digits;
3458                     }
3459                 }
3460                 // When two subsegments left.
3461                 else if (remaining_digits > 8)
3462                 {
3463                     // Get one more bit for potential rounding conditions check.
3464                     auto first_second_subsegments =
3465                         fixed_point_calculator<ExtendedCache::max_cache_blocks>::
3466                             generate_and_discard_lower(power_of_10[16] << 1, blocks, cache_block_count);
3467 
3468                     bool first_bit_of_third_subsegment = ((first_second_subsegments & 1) != 0);
3469                     first_second_subsegments >>= 1;
3470 
3471                     // 3022314549036573 = ceil(2^78/10^8) = floor(2^78*(10^8/(10^16 -
3472                     // 1))).
3473                     const auto first_subsegment =
3474                         static_cast<std::uint32_t>(boost::charconv::detail::umul128_upper64(first_second_subsegments, UINT64_C(3022314549036573)) >> 14);
3475 
3476                     const auto second_subsegment = static_cast<std::uint32_t>(first_second_subsegments) - UINT32_C(100000000) * first_subsegment;
3477 
3478                     print_8_digits(first_subsegment, buffer);
3479                     buffer += 8;
3480                     remaining_digits -= 8;
3481 
3482                     // Second subsegment (8 digits).
3483                     std::uint64_t prod;
3484                     if ((remaining_digits & 1) != 0)
3485                     {
3486                         prod = ((second_subsegment * UINT64_C(112589991)) >> 18) + 1;
3487                         current_digits = static_cast<std::uint32_t>(prod >> 32);
3488 
3489                         if (remaining_digits == 1)
3490                         {
3491                             if (check_rounding_condition_inside_subsegment(
3492                                     current_digits, static_cast<std::uint32_t>(prod), 7, has_further_digits<1, 6, ExtendedCache>(significand, exp2_base, k,
3493                                     uconst1, uconst6)))
3494                             {
3495                                 goto round_up_one_digit;
3496                             }
3497                             goto print_last_one_digit;
3498                         }
3499 
3500                         print_1_digit(current_digits, buffer);
3501                         ++buffer;
3502                     }
3503                     else
3504                     {
3505                         prod = ((second_subsegment * UINT64_C(140737489)) >> 15) + 1;
3506                         current_digits = static_cast<std::uint32_t>(prod >> 32);
3507 
3508                         if (remaining_digits == 2)
3509                         {
3510                             goto segment_loop22_more_than_8_digits_rounding;
3511                         }
3512 
3513                         print_2_digits(current_digits, buffer);
3514                         buffer += 2;
3515                     }
3516 
3517                     for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
3518                     {
3519                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3520                         print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3521                         buffer += 2;
3522                     }
3523 
3524                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3525                     current_digits = static_cast<std::uint32_t>(prod >> 32);
3526 
3527                     if (remaining_digits < 8)
3528                     {
3529                     segment_loop22_more_than_8_digits_rounding:
3530                         if (check_rounding_condition_inside_subsegment(
3531                                 current_digits, static_cast<std::uint32_t>(prod), 8 - remaining_digits,
3532                                 has_further_digits<1, 6, ExtendedCache>(significand, exp2_base, k, uconst1, uconst6)))
3533                         {
3534                             goto round_up_two_digits;
3535                         }
3536                     }
3537                     else {
3538                         if (check_rounding_condition_with_next_bit(
3539                                 current_digits, first_bit_of_third_subsegment,
3540                                 has_further_digits<0, 6, ExtendedCache>(significand, exp2_base, k, uconst0, uconst6)))
3541                         {
3542                             goto round_up_two_digits;
3543                         }
3544                     }
3545                     goto print_last_two_digits;
3546                 }
3547                 // remaining_digits is at most 8.
3548                 else
3549                 {
3550                     // Get one more bit for potential rounding conditions check.
3551                     auto first_subsegment =
3552                         fixed_point_calculator<ExtendedCache::max_cache_blocks>::
3553                             generate_and_discard_lower(power_of_10[8] << 1, blocks, cache_block_count);
3554 
3555                     bool first_bit_of_second_subsegment = ((first_subsegment & 1) != 0);
3556                     first_subsegment >>= 1;
3557 
3558                     std::uint64_t prod;
3559                     if ((remaining_digits & 1) != 0)
3560                     {
3561                         prod = ((first_subsegment * UINT64_C(112589991)) >> 18) + 1;
3562                         current_digits = static_cast<std::uint32_t>(prod >> 32);
3563 
3564                         if (remaining_digits == 1)
3565                         {
3566                             if (check_rounding_condition_inside_subsegment(
3567                                     current_digits, static_cast<std::uint32_t>(prod), 7, has_further_digits<1, 14, ExtendedCache>(significand, exp2_base, k,
3568                                     uconst1, uconst14)))
3569                             {
3570                                 goto round_up_one_digit;
3571                             }
3572                             goto print_last_one_digit;
3573                         }
3574 
3575                         print_1_digit(current_digits, buffer);
3576                         ++buffer;
3577                     }
3578                     else
3579                     {
3580                         prod = ((first_subsegment * UINT64_C(140737489)) >> 15) + 1;
3581                         current_digits = static_cast<std::uint32_t>(prod >> 32);
3582 
3583                         if (remaining_digits == 2)
3584                         {
3585                             goto segment_loop22_at_most_8_digits_rounding;
3586                         }
3587 
3588                         print_2_digits(current_digits, buffer);
3589                         buffer += 2;
3590                     }
3591 
3592                     for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
3593                     {
3594                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3595                         print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3596                         buffer += 2;
3597                     }
3598 
3599                     prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3600                     current_digits = static_cast<std::uint32_t>(prod >> 32);
3601 
3602                     if (remaining_digits < 8)
3603                     {
3604                     segment_loop22_at_most_8_digits_rounding:
3605                         if (check_rounding_condition_inside_subsegment(
3606                                 current_digits, static_cast<std::uint32_t>(prod), 8 - remaining_digits,
3607                                 has_further_digits<1, 14, ExtendedCache>(significand, exp2_base, k, uconst1, uconst14)))
3608                         {
3609                             goto round_up_two_digits;
3610                         }
3611                     }
3612                     else
3613                     {
3614                         if (check_rounding_condition_with_next_bit(
3615                                 current_digits, first_bit_of_second_subsegment,
3616                                 has_further_digits<0, 14, ExtendedCache>(significand, exp2_base, k, uconst0, uconst14)))
3617                         {
3618                             goto round_up_two_digits;
3619                         }
3620                     }
3621                     goto print_last_two_digits;
3622                 }
3623             } // ExtendedCache::segment_length == 22
3624             else if (ExtendedCache::segment_length == 252)
3625             {
3626                 // Print as many 18-digits subsegment pairs as possible.
3627                 for (int remaining_subsegment_pairs = 14; remaining_subsegment_pairs > 0;
3628                         --remaining_subsegment_pairs)
3629                 {
3630                     // No rounding, continue.
3631                     if (remaining_digits > 18)
3632                     {
3633                         const auto subsegment_pair =
3634                             fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[18], blocks, cache_block_count);
3635 
3636                         const auto first_part = static_cast<std::uint32_t>(subsegment_pair / power_of_10[9]);
3637                         const auto second_part = static_cast<std::uint32_t>(subsegment_pair - power_of_10[9] * first_part);
3638 
3639                         print_9_digits(first_part, buffer);
3640                         print_9_digits(second_part, buffer + 9);
3641                         buffer += 18;
3642                         remaining_digits -= 18;
3643                     }
3644                     // Final subsegment pair.
3645                     else
3646                     {
3647                         auto last_subsegment_pair =
3648                             fixed_point_calculator<ExtendedCache::max_cache_blocks>::
3649                                 generate_and_discard_lower(power_of_10[18] << 1, blocks, cache_block_count);
3650 
3651                         const bool subsegment_boundary_rounding_bit = ((last_subsegment_pair & 1) != 0);
3652                         last_subsegment_pair >>= 1;
3653 
3654                         const auto first_part = static_cast<std::uint32_t>(last_subsegment_pair / power_of_10[9]);
3655                         const auto second_part = static_cast<std::uint32_t>(last_subsegment_pair) - power_of_10[9] * first_part;
3656 
3657                         if (remaining_digits <= 9)
3658                         {
3659                             std::uint64_t prod;
3660 
3661                             if ((remaining_digits & 1) != 0)
3662                             {
3663                                 prod = ((first_part * UINT64_C(1441151881)) >> 25) + 1;
3664                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
3665 
3666                                 if (remaining_digits == 1)
3667                                 {
3668                                     if (check_rounding_condition_inside_subsegment(
3669                                             current_digits, static_cast<std::uint32_t>(prod), 8,
3670                                             compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3671                                     {
3672                                         goto round_up_one_digit;
3673                                     }
3674                                     goto print_last_one_digit;
3675                                 }
3676 
3677                                 print_1_digit(current_digits, buffer);
3678                                 ++buffer;
3679                             }
3680                             else
3681                             {
3682                                 prod = ((first_part * UINT64_C(450359963)) >> 20) + 1;
3683                                 current_digits = static_cast<std::uint32_t>(prod >> 32);
3684 
3685                                 if (remaining_digits == 2)
3686                                 {
3687                                     goto segment_loop252_final18_first_part_rounding;
3688                                 }
3689 
3690                                 print_2_digits(current_digits, buffer);
3691                                 buffer += 2;
3692                             }
3693 
3694                             for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
3695                             {
3696                                 prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3697                                 print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3698                                 buffer += 2;
3699                             }
3700 
3701                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3702                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3703 
3704                             if (remaining_digits < 9)
3705                             {
3706                             segment_loop252_final18_first_part_rounding:
3707                                 if (check_rounding_condition_inside_subsegment(
3708                                         current_digits, static_cast<std::uint32_t>(prod),
3709                                         9 - remaining_digits, compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3710                                 {
3711                                     goto round_up_two_digits;
3712                                 }
3713                             }
3714                             else
3715                             {
3716                                 if (check_rounding_condition_subsegment_boundary_with_next_subsegment(
3717                                         current_digits,
3718                                         uint_with_known_number_of_digits<9>{static_cast<std::uint32_t>(second_part)},
3719                                         compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3720                                 {
3721                                     goto round_up_two_digits;
3722                                 }
3723                             }
3724                             goto print_last_two_digits;
3725                         } // remaining_digits <= 9
3726 
3727                         print_9_digits(first_part, buffer);
3728                         buffer += 9;
3729                         remaining_digits -= 9;
3730 
3731                         std::uint64_t prod;
3732 
3733                         if ((remaining_digits & 1) != 0)
3734                         {
3735                             prod = ((second_part * UINT64_C(1441151881)) >> 25) + 1;
3736                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3737 
3738                             if (remaining_digits == 1)
3739                             {
3740                                 if (check_rounding_condition_inside_subsegment(
3741                                         current_digits, static_cast<std::uint32_t>(prod), 8,
3742                                         compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3743                                 {
3744                                     goto round_up_one_digit;
3745                                 }
3746                                 goto print_last_one_digit;
3747                             }
3748 
3749                             print_1_digit(current_digits, buffer);
3750                             ++buffer;
3751                         }
3752                         else
3753                         {
3754                             prod = ((second_part * UINT64_C(450359963)) >> 20) + 1;
3755                             current_digits = static_cast<std::uint32_t>(prod >> 32);
3756 
3757                             if (remaining_digits == 2)
3758                             {
3759                                 goto segment_loop252_final18_second_part_rounding;
3760                             }
3761 
3762                             print_2_digits(current_digits, buffer);
3763                             buffer += 2;
3764                         }
3765 
3766                         for (int i = 0; i < (remaining_digits - 3) / 2; ++i)
3767                         {
3768                             prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3769                             print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer);
3770                             buffer += 2;
3771                         }
3772 
3773                         prod = static_cast<std::uint32_t>(prod) * UINT64_C(100);
3774                         current_digits = static_cast<std::uint32_t>(prod >> 32);
3775 
3776                         if (remaining_digits < 9)
3777                         {
3778                         segment_loop252_final18_second_part_rounding:
3779                             if (check_rounding_condition_inside_subsegment(
3780                                     current_digits, static_cast<std::uint32_t>(prod), 9 - remaining_digits,
3781                                     compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3782                             {
3783                                 goto round_up_two_digits;
3784                             }
3785                         }
3786                         else
3787                         {
3788                             if (check_rounding_condition_with_next_bit(
3789                                     current_digits, subsegment_boundary_rounding_bit,
3790                                     compute_has_further_digits<0, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k))
3791                             {
3792                                 goto round_up_two_digits;
3793                             }
3794                         }
3795                         goto print_last_two_digits;
3796                     }
3797                 }
3798             } // if (ExtendedCache::segment_length == 252)
3799         }
3800     }
3801 
3802 
3803     /////////////////////////////////////////////////////////////////////////////////////////////////
3804     /// Phase 3 - Fill remaining digits with 0's, insert decimal dot, print exponent, and
3805     /// return.
3806     /////////////////////////////////////////////////////////////////////////////////////////////////
3807 
3808 fill_remaining_digits_with_0s:
3809     // This is probably not needed for the general format, but currently I am not 100% sure.
3810     // (When fixed format is eventually chosen, we do not remove trailing zeros in the integer part.
3811     // I am not sure if those trailing zeros are guaranteed to be already printed or not.)
3812     std::memset(buffer, '0', static_cast<std::size_t>(remaining_digits));
3813     buffer += remaining_digits;
3814 
3815 insert_decimal_dot:
3816     if (fmt == chars_format::general)
3817     {
3818         // Decide between fixed vs scientific.
3819         if (-4 <= decimal_exponent_normalized && decimal_exponent_normalized < precision)
3820         {
3821             // Fixed.
3822             if (decimal_exponent_normalized >= 0)
3823             {
3824                 // Insert decimal dot.
3825                 decimal_dot_pos = buffer_starting_pos + decimal_exponent_normalized + 1;
3826                 std::memmove(buffer_starting_pos, buffer_starting_pos + 1,
3827                              static_cast<std::size_t>(decimal_dot_pos - buffer_starting_pos));
3828                 *decimal_dot_pos = '.';
3829             }
3830             else
3831             {
3832                 // Print leading zeros and insert decimal dot.
3833                 int number_of_leading_zeros = -decimal_exponent_normalized - 1;
3834                 std::memmove(buffer_starting_pos + number_of_leading_zeros + 2, buffer_starting_pos + 1,
3835                              static_cast<std::size_t>(buffer - buffer_starting_pos - 1));
3836                 std::memcpy(buffer_starting_pos, "0.", 2);
3837                 std::memset(buffer_starting_pos + 2, '0', static_cast<std::size_t>(number_of_leading_zeros));
3838                 buffer += number_of_leading_zeros + 1;
3839             }
3840             // Don't print exponent.
3841             fmt = chars_format::fixed;
3842         }
3843         else
3844         {
3845             // Scientific.
3846             // Insert decimal dot.
3847             *buffer_starting_pos = *(buffer_starting_pos + 1);
3848             *(buffer_starting_pos + 1) = '.';
3849         }
3850 
3851         // Remove trailing zeros.
3852         while (true)
3853         {
3854             auto prev = buffer - 1;
3855 
3856             // Remove decimal dot as well if there is no fractional digits.
3857             if (*prev == '.')
3858             {
3859                 buffer = prev;
3860                 break;
3861             }
3862             else if (*prev != '0')
3863             {
3864                 break;
3865             }
3866             buffer = prev;
3867         }
3868     }
3869     else if (decimal_dot_pos != buffer_starting_pos)
3870     {
3871         std::memmove(buffer_starting_pos, buffer_starting_pos + 1,
3872                      static_cast<std::size_t>(decimal_dot_pos - buffer_starting_pos));
3873         *decimal_dot_pos = '.';
3874     }
3875 
3876     if (fmt != chars_format::fixed)
3877     {
3878         if (decimal_exponent_normalized >= 0)
3879         {
3880             std::memcpy(buffer, "e+", 2); // NOLINT : Specifically not null-terminating
3881         }
3882         else
3883         {
3884             std::memcpy(buffer, "e-", 2); // NOLINT : Specifically not null-terminating
3885             decimal_exponent_normalized = -decimal_exponent_normalized;
3886         }
3887 
3888         buffer += 2;
3889         if (decimal_exponent_normalized >= 100)
3890         {
3891             // d1 = decimal_exponent / 10; d2 = decimal_exponent % 10;
3892             // 6554 = ceil(2^16 / 10)
3893             auto prod = static_cast<std::uint32_t>(decimal_exponent_normalized) * UINT32_C(6554);
3894             auto d1 = prod >> 16;
3895             prod = static_cast<std::uint16_t>(prod) * UINT16_C(5); // * 10
3896             auto d2 = prod >> 15;                                  // >> 16
3897             print_2_digits(d1, buffer);
3898             print_1_digit(d2, buffer + 2);
3899             buffer += 3;
3900         }
3901         else
3902         {
3903             print_2_digits(static_cast<std::uint32_t>(decimal_exponent_normalized), buffer);
3904             buffer += 2;
3905         }
3906     }    
3907 
3908     return {buffer, std::errc()};
3909 
3910 round_up:
3911     if ((remaining_digits & 1) != 0)
3912     {
3913     round_up_one_digit:
3914         if (++current_digits == 10)
3915         {
3916             goto round_up_all_9s;
3917         }
3918 
3919         goto print_last_one_digit;
3920     }
3921     else
3922     {
3923     round_up_two_digits:
3924         if (++current_digits == 100)
3925         {
3926             goto round_up_all_9s;
3927         }
3928 
3929         goto print_last_two_digits;
3930     }
3931 
3932 print_last_digits:
3933     if ((remaining_digits & 1) != 0) 
3934     {
3935     print_last_one_digit:
3936         print_1_digit(current_digits, buffer);
3937         ++buffer;
3938     }
3939     else
3940     {
3941     print_last_two_digits:
3942         print_2_digits(current_digits, buffer);
3943         buffer += 2;
3944     }
3945 
3946     goto insert_decimal_dot;
3947 
3948 round_up_all_9s:
3949     char* first_9_pos = buffer;
3950     buffer += (2 - (remaining_digits & 1));
3951     
3952     // Find the starting position of printed digits.
3953     char* digit_starting_pos = [&] {
3954         // For negative exponent & fixed format, we already printed leading zeros.
3955         if (fmt == chars_format::fixed && decimal_exponent_normalized < 0)
3956         {
3957             return buffer_starting_pos - decimal_exponent_normalized + 1;
3958         }
3959         // We reserved one slot for decimal dot, so the starting position of printed digits
3960         // is buffer_starting_pos + 1 if we need to print decimal dot.
3961         return buffer_starting_pos == decimal_dot_pos ? buffer_starting_pos
3962             : buffer_starting_pos + 1;
3963     }();
3964     // Find all preceding 9's.
3965     if ((first_9_pos - digit_starting_pos) % 2 != 0)
3966     {
3967         if (*(first_9_pos - 1) != '9')
3968         {
3969             ++*(first_9_pos - 1);
3970             if ((remaining_digits & 1) != 0)
3971             {
3972                 *first_9_pos = '0';
3973             }
3974             else
3975             {
3976                 std::memcpy(first_9_pos, "00", 2);
3977             }
3978             goto insert_decimal_dot;
3979         }
3980         --first_9_pos;
3981     }
3982     while (first_9_pos != digit_starting_pos)
3983     {
3984         if (std::memcmp(first_9_pos - 2, "99", 2) != 0)
3985         {
3986             if (*(first_9_pos - 1) != '9')
3987             {
3988                 ++*(first_9_pos - 1);
3989             }
3990             else
3991             {
3992                 ++*(first_9_pos - 2);
3993                 *(first_9_pos - 1) = '0';
3994             }
3995             std::memset(first_9_pos, '0', static_cast<std::size_t>(buffer - first_9_pos));
3996             goto insert_decimal_dot;
3997         }
3998         first_9_pos -= 2;
3999     }
4000 
4001     // Every digit we wrote so far are all 9's. In this case, we have to shift the whole thing by 1.
4002     ++decimal_exponent_normalized;
4003 
4004     if (fmt == chars_format::fixed)
4005     {
4006         if (decimal_exponent_normalized > 0)
4007         {
4008             // We need to print one more character.
4009             if (buffer == last)
4010             {
4011                 return {last, std::errc::value_too_large};
4012             }
4013             ++buffer;
4014             // If we were to print the decimal dot, we have to shift it to right
4015             // since we now have one more digit in the integer part.
4016             if (buffer_starting_pos != decimal_dot_pos)
4017             {
4018                 ++decimal_dot_pos;
4019             }
4020         }
4021         else if (decimal_exponent_normalized == 0)
4022         {
4023             // For the case 0.99...9 -> 1.00...0, the rounded digit is one before the first digit written.
4024             // Note: decimal_exponent_normalized was negative before the increment (++decimal_exponent_normalized),
4025             //       so we already have printed "00" onto the buffer.
4026             //       Hence, --digit_starting_pos doesn't go more than the starting position of the buffer.
4027             --digit_starting_pos;
4028         }
4029     }
4030 
4031     // Nolint is applied to the following two calls since we know they are not supposed to be null terminated
4032     *digit_starting_pos = '1';
4033     std::memset(digit_starting_pos + 1, '0', static_cast<std::size_t>(buffer - digit_starting_pos - 1)); // NOLINT
4034 
4035     goto insert_decimal_dot;
4036 }
4037 
4038 }}} // Namespaces 
4039 
4040 #ifdef BOOST_MSVC
4041 # pragma warning(pop)
4042 #endif
4043 
4044 #endif // BOOST_CHARCONV_DETAIL_FLOFF