| 1 | // Copyright 2020-2022 Junekey Jeon |
| 2 | // |
| 3 | // The contents of this file may be used under the terms of |
| 4 | // the Apache License v2.0 with LLVM Exceptions. |
| 5 | // |
| 6 | // (See accompanying file LICENSE-Apache or copy at |
| 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) |
| 8 | // |
| 9 | // Alternatively, the contents of this file may be used under the terms of |
| 10 | // the Boost Software License, Version 1.0. |
| 11 | // (See accompanying file LICENSE-Boost or copy at |
| 12 | // https://www.boost.org/LICENSE_1_0.txt) |
| 13 | // |
| 14 | // Unless required by applicable law or agreed to in writing, this software |
| 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 16 | // KIND, either express or implied. |
| 17 | // |
| 18 | // Some parts are copied from Dragonbox project. |
| 19 | // |
| 20 | // Copyright 2023 Matt Borland |
| 21 | // Distributed under the Boost Software License, Version 1.0. |
| 22 | // https://www.boost.org/LICENSE_1_0.txt |
| 23 | |
| 24 | #ifndef BOOST_CHARCONV_DETAIL_FLOFF |
| 25 | #define BOOST_CHARCONV_DETAIL_FLOFF |
| 26 | |
| 27 | #include <boost/charconv/detail/config.hpp> |
| 28 | #include <boost/charconv/detail/bit_layouts.hpp> |
| 29 | #include <boost/charconv/detail/emulated128.hpp> |
| 30 | #include <boost/charconv/detail/dragonbox/dragonbox_common.hpp> |
| 31 | #include <boost/charconv/detail/to_chars_result.hpp> |
| 32 | #include <boost/charconv/chars_format.hpp> |
| 33 | #include <boost/core/bit.hpp> |
| 34 | #include <type_traits> |
| 35 | #include <limits> |
| 36 | #include <cstdint> |
| 37 | #include <cstring> |
| 38 | #include <cstddef> |
| 39 | #include <climits> |
| 40 | |
| 41 | #ifdef BOOST_MSVC |
| 42 | # pragma warning(push) |
| 43 | # pragma warning(disable: 4127) // Extensive use of BOOST_IF_CONSTEXPR emits warnings under C++11 and 14 |
| 44 | # pragma warning(disable: 4554) // parentheses are used be warning is still emitted |
| 45 | #endif |
| 46 | |
| 47 | namespace boost { namespace charconv { namespace detail { |
| 48 | |
| 49 | #ifdef BOOST_MSVC |
| 50 | # pragma warning(push) |
| 51 | # pragma warning(disable: 4702) // use of BOOST_IF_CONSTEXPR can result in unreachable code if max_blocks is 3 |
| 52 | // Other older compilers will emit warnings if the unreachable code is wrapped |
| 53 | // in an else block (e.g. no return statment) |
| 54 | #endif |
| 55 | |
| 56 | template <std::size_t max_blocks> |
| 57 | struct fixed_point_calculator |
| 58 | { |
| 59 | static_assert(1 < max_blocks, "Max blocks must be greater than 1" ); |
| 60 | |
| 61 | // Multiply multiplier to the fractional blocks and take the resulting integer part. |
| 62 | // The fractional blocks are updated. |
| 63 | template <typename MultiplierType> |
| 64 | BOOST_FORCEINLINE static MultiplierType generate(MultiplierType multiplier, |
| 65 | std::uint64_t* blocks_ptr, |
| 66 | std::size_t number_of_blocks) noexcept |
| 67 | { |
| 68 | BOOST_CHARCONV_ASSERT(0 < number_of_blocks && number_of_blocks <= max_blocks); |
| 69 | |
| 70 | BOOST_IF_CONSTEXPR (max_blocks == 3) |
| 71 | { |
| 72 | uint128 mul_result; |
| 73 | std::uint64_t carry = 0; |
| 74 | |
| 75 | switch (number_of_blocks) |
| 76 | { |
| 77 | case 3: |
| 78 | mul_result = umul128(blocks_ptr[2], multiplier); |
| 79 | blocks_ptr[2] = mul_result.low; |
| 80 | carry = mul_result.high; |
| 81 | BOOST_FALLTHROUGH; |
| 82 | |
| 83 | case 2: |
| 84 | mul_result = umul128(blocks_ptr[1], multiplier); |
| 85 | mul_result += carry; |
| 86 | blocks_ptr[1] = mul_result.low; |
| 87 | carry = mul_result.high; |
| 88 | BOOST_FALLTHROUGH; |
| 89 | |
| 90 | case 1: |
| 91 | mul_result = umul128(blocks_ptr[0], multiplier); |
| 92 | mul_result += carry; |
| 93 | blocks_ptr[0] = mul_result.low; |
| 94 | return mul_result.high; |
| 95 | |
| 96 | default: |
| 97 | BOOST_UNREACHABLE_RETURN(carry); // NOLINT : Macro for unreachable can expand to be empty |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | auto mul_result = umul128(blocks_ptr[number_of_blocks - 1], multiplier); |
| 102 | blocks_ptr[number_of_blocks - 1] = mul_result.low; |
| 103 | auto carry = mul_result.high; |
| 104 | for (std::size_t i = 1; i < number_of_blocks; ++i) |
| 105 | { |
| 106 | mul_result = umul128(blocks_ptr[number_of_blocks - i - 1], multiplier); |
| 107 | mul_result += carry; |
| 108 | blocks_ptr[number_of_blocks - i - 1] = mul_result.low; |
| 109 | carry = mul_result.high; |
| 110 | } |
| 111 | |
| 112 | return MultiplierType(carry); |
| 113 | } |
| 114 | |
| 115 | // Multiply multiplier to the fractional blocks and discard the resulting integer part. |
| 116 | // The fractional blocks are updated. |
| 117 | template <typename MultiplierType> |
| 118 | BOOST_FORCEINLINE static void discard_upper(MultiplierType multiplier, |
| 119 | std::uint64_t* blocks_ptr, |
| 120 | std::size_t number_of_blocks) noexcept |
| 121 | { |
| 122 | BOOST_CHARCONV_ASSERT(0 < number_of_blocks && number_of_blocks <= max_blocks); |
| 123 | |
| 124 | blocks_ptr[0] *= multiplier; |
| 125 | if (number_of_blocks > 1) |
| 126 | { |
| 127 | BOOST_IF_CONSTEXPR (max_blocks == 3) |
| 128 | { |
| 129 | uint128 mul_result; |
| 130 | std::uint64_t carry = 0; |
| 131 | |
| 132 | if (number_of_blocks > 2) |
| 133 | { |
| 134 | mul_result = umul128(multiplier, blocks_ptr[2]); |
| 135 | blocks_ptr[2] = mul_result.low; |
| 136 | carry = mul_result.high; |
| 137 | } |
| 138 | |
| 139 | mul_result = umul128(multiplier, blocks_ptr[1]); |
| 140 | mul_result += carry; |
| 141 | blocks_ptr[1] = mul_result.low; |
| 142 | blocks_ptr[0] += mul_result.high; |
| 143 | } |
| 144 | else |
| 145 | { |
| 146 | auto mul_result = umul128(multiplier, blocks_ptr[number_of_blocks - 1]); |
| 147 | blocks_ptr[number_of_blocks - 1] = mul_result.low; |
| 148 | auto carry = mul_result.high; |
| 149 | |
| 150 | for (std::size_t i = 2; i < number_of_blocks; ++i) |
| 151 | { |
| 152 | mul_result = umul128(multiplier, blocks_ptr[number_of_blocks - i]); |
| 153 | mul_result += carry; |
| 154 | blocks_ptr[number_of_blocks - i] = mul_result.low; |
| 155 | carry = mul_result.high; |
| 156 | } |
| 157 | |
| 158 | blocks_ptr[0] += carry; |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | // Multiply multiplier to the fractional blocks and take the resulting integer part. |
| 164 | // Don't care about what happens to the fractional blocks. |
| 165 | template <typename MultiplierType> |
| 166 | BOOST_FORCEINLINE static MultiplierType |
| 167 | generate_and_discard_lower(MultiplierType multiplier, std::uint64_t* blocks_ptr, |
| 168 | std::size_t number_of_blocks) noexcept |
| 169 | { |
| 170 | BOOST_CHARCONV_ASSERT(0 < number_of_blocks && number_of_blocks <= max_blocks); |
| 171 | |
| 172 | BOOST_IF_CONSTEXPR (max_blocks == 3) |
| 173 | { |
| 174 | uint128 mul_result; |
| 175 | std::uint64_t carry = 0; |
| 176 | |
| 177 | switch (number_of_blocks) |
| 178 | { |
| 179 | case 3: |
| 180 | mul_result = umul128(x: blocks_ptr[2], y: static_cast<std::uint64_t>(multiplier)); |
| 181 | carry = mul_result.high; |
| 182 | BOOST_FALLTHROUGH; |
| 183 | |
| 184 | case 2: |
| 185 | mul_result = umul128(x: blocks_ptr[1], y: static_cast<std::uint64_t>(multiplier)); |
| 186 | mul_result += carry; |
| 187 | carry = mul_result.high; |
| 188 | BOOST_FALLTHROUGH; |
| 189 | |
| 190 | case 1: |
| 191 | mul_result = umul128(x: blocks_ptr[0], y: static_cast<std::uint64_t>(multiplier)); |
| 192 | mul_result += carry; |
| 193 | return static_cast<MultiplierType>(mul_result.high); |
| 194 | |
| 195 | default: |
| 196 | BOOST_UNREACHABLE_RETURN(carry); // NOLINT |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | auto mul_result = umul128(x: blocks_ptr[number_of_blocks - 1], y: static_cast<std::uint64_t>(multiplier)); |
| 201 | auto carry = mul_result.high; |
| 202 | for (std::size_t i = 1; i < number_of_blocks; ++i) |
| 203 | { |
| 204 | mul_result = umul128(x: blocks_ptr[number_of_blocks - i - 1], y: static_cast<std::uint64_t>(multiplier)); |
| 205 | mul_result += carry; |
| 206 | carry = mul_result.high; |
| 207 | } |
| 208 | |
| 209 | return static_cast<MultiplierType>(carry); |
| 210 | } |
| 211 | }; |
| 212 | |
| 213 | #ifdef BOOST_MSVC |
| 214 | # pragma warning(pop) |
| 215 | #endif |
| 216 | |
| 217 | template <bool b> |
| 218 | struct additional_static_data_holder_impl |
| 219 | { |
| 220 | static constexpr char radix_100_table[] = { |
| 221 | '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', // |
| 222 | '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', // |
| 223 | '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', // |
| 224 | '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', // |
| 225 | '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', // |
| 226 | '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', // |
| 227 | '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', // |
| 228 | '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', // |
| 229 | '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', // |
| 230 | '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', // |
| 231 | '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', // |
| 232 | '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', // |
| 233 | '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', // |
| 234 | '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', // |
| 235 | '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', // |
| 236 | '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', // |
| 237 | '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', // |
| 238 | '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', // |
| 239 | '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', // |
| 240 | '9', '5', '9', '6', '9', '7', '9', '8', '9', '9' // |
| 241 | }; |
| 242 | |
| 243 | static constexpr std::uint32_t fractional_part_rounding_thresholds32[] = { |
| 244 | UINT32_C(2576980378), UINT32_C(2190433321), UINT32_C(2151778616), UINT32_C(2147913145), |
| 245 | UINT32_C(2147526598), UINT32_C(2147487943), UINT32_C(2147484078), UINT32_C(2147483691) |
| 246 | }; |
| 247 | |
| 248 | static constexpr std::uint64_t fractional_part_rounding_thresholds64[] = { |
| 249 | UINT64_C(11068046444225730970), UINT64_C(9407839477591871325), UINT64_C(9241818780928485360), |
| 250 | UINT64_C(9225216711262146764), UINT64_C(9223556504295512904), UINT64_C(9223390483598849518), |
| 251 | UINT64_C(9223373881529183179), UINT64_C(9223372221322216546), UINT64_C(9223372055301519882), |
| 252 | UINT64_C(9223372038699450216), UINT64_C(9223372037039243249), UINT64_C(9223372036873222553), |
| 253 | UINT64_C(9223372036856620483), UINT64_C(9223372036854960276), UINT64_C(9223372036854794255), |
| 254 | UINT64_C(9223372036854777653), UINT64_C(9223372036854775993), UINT64_C(9223372036854775827) |
| 255 | }; |
| 256 | }; |
| 257 | |
| 258 | #if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) |
| 259 | |
| 260 | template <bool b> constexpr char additional_static_data_holder_impl<b>::radix_100_table[]; |
| 261 | template <bool b> constexpr std::uint32_t additional_static_data_holder_impl<b>::fractional_part_rounding_thresholds32[]; |
| 262 | template <bool b> constexpr std::uint64_t additional_static_data_holder_impl<b>::fractional_part_rounding_thresholds64[]; |
| 263 | |
| 264 | #endif |
| 265 | |
| 266 | using additional_static_data_holder = additional_static_data_holder_impl<true>; |
| 267 | |
| 268 | struct compute_mul_result |
| 269 | { |
| 270 | std::uint64_t result; |
| 271 | bool is_integer; |
| 272 | }; |
| 273 | |
| 274 | // Load the necessary bits into blocks_ptr and then return the number of cache blocks |
| 275 | // loaded. The most significant block is loaded into blocks_ptr[0]. |
| 276 | template <typename ExtendedCache, bool zero_out, |
| 277 | typename CacheBlockType = typename std::decay<decltype(ExtendedCache::cache[0])>::type, |
| 278 | typename std::enable_if<(ExtendedCache::constant_block_count), bool>::type = true> |
| 279 | inline std::uint8_t cache_block_count_helper(CacheBlockType*, int, int, std::uint32_t) noexcept |
| 280 | { |
| 281 | return static_cast<std::uint8_t>(ExtendedCache::max_cache_blocks); |
| 282 | } |
| 283 | |
| 284 | template <typename ExtendedCache, bool zero_out, |
| 285 | typename CacheBlockType = typename std::decay<decltype(ExtendedCache::cache[0])>::type, |
| 286 | typename std::enable_if<!(ExtendedCache::constant_block_count), bool>::type = true> |
| 287 | inline std::uint8_t cache_block_count_helper(CacheBlockType*, int e, int, std::uint32_t multiplier_index) noexcept |
| 288 | { |
| 289 | const auto mul_info = ExtendedCache::multiplier_index_info_table[multiplier_index]; |
| 290 | |
| 291 | const auto cache_block_count_index = |
| 292 | mul_info.cache_block_count_index_offset + |
| 293 | static_cast<std::uint32_t>(e - ExtendedCache::e_min) / ExtendedCache::collapse_factor - |
| 294 | ExtendedCache::cache_block_count_offset_base; |
| 295 | |
| 296 | BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks < 3) |
| 297 | { |
| 298 | // 1-bit packing. |
| 299 | return static_cast<std::uint8_t>( |
| 300 | (ExtendedCache::cache_block_counts[cache_block_count_index / |
| 301 | 8] >> |
| 302 | (cache_block_count_index % 8)) & |
| 303 | 0x1) + |
| 304 | 1; |
| 305 | } |
| 306 | else BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks < 4) |
| 307 | { |
| 308 | // 2-bit packing. |
| 309 | return static_cast<std::uint8_t>( |
| 310 | (ExtendedCache::cache_block_counts[cache_block_count_index / 4] >> |
| 311 | (2 * (cache_block_count_index % 4))) & |
| 312 | 0x3); |
| 313 | } |
| 314 | else |
| 315 | { |
| 316 | // 4-bit packing. |
| 317 | return std::uint8_t( |
| 318 | (ExtendedCache::cache_block_counts[cache_block_count_index / 2] >> |
| 319 | (4 * (cache_block_count_index % 2))) & |
| 320 | 0xf); |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | template <typename ExtendedCache, bool zero_out, |
| 325 | typename CacheBlockType = typename std::decay<decltype(ExtendedCache::cache[0])>::type> |
| 326 | BOOST_FORCEINLINE std::uint8_t load_extended_cache(CacheBlockType* blocks_ptr, int e, int k, |
| 327 | std::uint32_t multiplier_index) noexcept |
| 328 | { |
| 329 | BOOST_IF_CONSTEXPR (zero_out) |
| 330 | { |
| 331 | std::memset(s: blocks_ptr, c: 0, n: sizeof(CacheBlockType) * ExtendedCache::max_cache_blocks); |
| 332 | } |
| 333 | |
| 334 | const auto mul_info = ExtendedCache::multiplier_index_info_table[multiplier_index]; |
| 335 | |
| 336 | std::uint32_t number_of_leading_zero_blocks; |
| 337 | std::uint32_t first_cache_block_index; |
| 338 | std::uint32_t bit_offset; |
| 339 | std::uint32_t excessive_bits_to_left; |
| 340 | std::uint32_t excessive_bits_to_right; |
| 341 | std::uint8_t cache_block_count = cache_block_count_helper<ExtendedCache, zero_out, CacheBlockType>(blocks_ptr, e, k, multiplier_index); |
| 342 | |
| 343 | // The request window starting/ending positions. |
| 344 | auto start_bit_index = static_cast<int>(mul_info.cache_bit_index_offset) + e - ExtendedCache::cache_bit_index_offset_base; |
| 345 | auto end_bit_index = start_bit_index + cache_block_count * static_cast<int>(ExtendedCache::cache_bits_unit); |
| 346 | |
| 347 | // The source window starting/ending positions. |
| 348 | const auto src_start_bit_index = static_cast<int>(mul_info.first_cache_bit_index); |
| 349 | const auto src_end_bit_index = static_cast<int>(ExtendedCache::multiplier_index_info_table[multiplier_index + 1].first_cache_bit_index); |
| 350 | |
| 351 | // If the request window goes further than the left boundary of the source window, |
| 352 | if (start_bit_index < src_start_bit_index) |
| 353 | { |
| 354 | number_of_leading_zero_blocks = |
| 355 | static_cast<std::uint32_t>(src_start_bit_index - start_bit_index) / |
| 356 | static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); |
| 357 | excessive_bits_to_left = static_cast<std::uint32_t>(src_start_bit_index - start_bit_index) % |
| 358 | static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); |
| 359 | |
| 360 | BOOST_IF_CONSTEXPR (!zero_out) |
| 361 | { |
| 362 | std::memset(s: blocks_ptr, c: 0, n: number_of_leading_zero_blocks * sizeof(CacheBlockType)); |
| 363 | } |
| 364 | |
| 365 | start_bit_index += static_cast<int>(number_of_leading_zero_blocks * ExtendedCache::cache_bits_unit); |
| 366 | |
| 367 | const auto src_start_block_index = |
| 368 | static_cast<int>(static_cast<std::uint32_t>(src_start_bit_index) / |
| 369 | static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit)); |
| 370 | |
| 371 | const auto src_start_block_bit_index = |
| 372 | src_start_block_index * static_cast<int>(ExtendedCache::cache_bits_unit); |
| 373 | |
| 374 | first_cache_block_index = static_cast<std::uint32_t>(src_start_block_index); |
| 375 | |
| 376 | if (start_bit_index < src_start_block_bit_index) |
| 377 | { |
| 378 | auto shift_amount = src_start_block_bit_index - start_bit_index; |
| 379 | BOOST_CHARCONV_ASSERT(shift_amount >= 0 && shift_amount < static_cast<int>(ExtendedCache::cache_bits_unit)); |
| 380 | |
| 381 | blocks_ptr[number_of_leading_zero_blocks] = |
| 382 | ((ExtendedCache::cache[src_start_block_index] >> shift_amount) & |
| 383 | (CacheBlockType(CacheBlockType(0) - CacheBlockType(1)) >> |
| 384 | excessive_bits_to_left)); |
| 385 | |
| 386 | ++number_of_leading_zero_blocks; |
| 387 | bit_offset = static_cast<std::uint32_t>(static_cast<int>(ExtendedCache::cache_bits_unit) - shift_amount); |
| 388 | excessive_bits_to_left = 0; |
| 389 | } |
| 390 | else |
| 391 | { |
| 392 | bit_offset = static_cast<std::uint32_t>(start_bit_index - src_start_block_bit_index); |
| 393 | } |
| 394 | } |
| 395 | else |
| 396 | { |
| 397 | number_of_leading_zero_blocks = 0; |
| 398 | first_cache_block_index = |
| 399 | static_cast<std::uint32_t>(start_bit_index) / static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); |
| 400 | bit_offset = |
| 401 | static_cast<std::uint32_t>(start_bit_index) % static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); |
| 402 | excessive_bits_to_left = 0; |
| 403 | } |
| 404 | |
| 405 | // If the request window goes further than the right boundary of the source window, |
| 406 | if (end_bit_index > src_end_bit_index) |
| 407 | { |
| 408 | const std::uint8_t number_of_trailing_zero_blocks = |
| 409 | static_cast<std::uint8_t>(end_bit_index - src_end_bit_index) / ExtendedCache::cache_bits_unit; |
| 410 | excessive_bits_to_right = static_cast<std::uint32_t>(end_bit_index - src_end_bit_index) % |
| 411 | static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); |
| 412 | |
| 413 | cache_block_count -= number_of_trailing_zero_blocks; |
| 414 | } |
| 415 | else |
| 416 | { |
| 417 | excessive_bits_to_right = 0; |
| 418 | } |
| 419 | |
| 420 | // Load blocks. |
| 421 | const auto number_of_blocks_to_load = cache_block_count - number_of_leading_zero_blocks; |
| 422 | auto* const dst_ptr = blocks_ptr + number_of_leading_zero_blocks; |
| 423 | if (bit_offset == 0) |
| 424 | { |
| 425 | BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks == 3) |
| 426 | { |
| 427 | switch (number_of_blocks_to_load) |
| 428 | { |
| 429 | case 3: |
| 430 | std::memcpy(dest: dst_ptr, src: ExtendedCache::cache + first_cache_block_index, n: 3 * sizeof(CacheBlockType)); |
| 431 | break; |
| 432 | case 2: |
| 433 | std::memcpy(dest: dst_ptr, src: ExtendedCache::cache + first_cache_block_index, n: 2 * sizeof(CacheBlockType)); |
| 434 | break; |
| 435 | case 1: |
| 436 | std::memcpy(dest: dst_ptr, src: ExtendedCache::cache + first_cache_block_index, n: 1 * sizeof(CacheBlockType)); |
| 437 | break; |
| 438 | case 0: |
| 439 | break; |
| 440 | default: |
| 441 | BOOST_UNREACHABLE_RETURN(dst_ptr); // NOLINT |
| 442 | } |
| 443 | } |
| 444 | else |
| 445 | { |
| 446 | std::memcpy(dest: dst_ptr, src: ExtendedCache::cache + first_cache_block_index, n: number_of_blocks_to_load * sizeof(CacheBlockType)); |
| 447 | } |
| 448 | } |
| 449 | else |
| 450 | { |
| 451 | BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks == 3) |
| 452 | { |
| 453 | switch (number_of_blocks_to_load) |
| 454 | { |
| 455 | case 3: |
| 456 | *(dst_ptr + 2) = |
| 457 | (ExtendedCache::cache[first_cache_block_index + 2] << bit_offset) | |
| 458 | (ExtendedCache::cache[first_cache_block_index + 3] >> |
| 459 | (ExtendedCache::cache_bits_unit - bit_offset)); |
| 460 | BOOST_FALLTHROUGH; |
| 461 | case 2: |
| 462 | *(dst_ptr + 1) = |
| 463 | (ExtendedCache::cache[first_cache_block_index + 1] << bit_offset) | |
| 464 | (ExtendedCache::cache[first_cache_block_index + 2] >> |
| 465 | (ExtendedCache::cache_bits_unit - bit_offset)); |
| 466 | BOOST_FALLTHROUGH; |
| 467 | case 1: |
| 468 | *dst_ptr = (ExtendedCache::cache[first_cache_block_index] << bit_offset) | |
| 469 | (ExtendedCache::cache[first_cache_block_index + 1] >> |
| 470 | (ExtendedCache::cache_bits_unit - bit_offset)); |
| 471 | case 0: |
| 472 | break; |
| 473 | default: |
| 474 | BOOST_UNREACHABLE_RETURN(dst_ptr); // NOLINT |
| 475 | } |
| 476 | } |
| 477 | else |
| 478 | { |
| 479 | for (std::uint8_t i = 0; i < number_of_blocks_to_load; ++i) |
| 480 | { |
| 481 | *(dst_ptr + i) = |
| 482 | (ExtendedCache::cache[first_cache_block_index + i] << bit_offset) | |
| 483 | (ExtendedCache::cache[first_cache_block_index + i + 1] >> |
| 484 | (ExtendedCache::cache_bits_unit - bit_offset)); |
| 485 | } |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | // Remove possible flooding bits from adjacent entries. |
| 490 | *dst_ptr &= (CacheBlockType(CacheBlockType(0) - CacheBlockType(1)) >> excessive_bits_to_left); |
| 491 | |
| 492 | blocks_ptr[cache_block_count - 1] &= (CacheBlockType(CacheBlockType(0) - CacheBlockType(1)) << excessive_bits_to_right); |
| 493 | |
| 494 | // To compute ceil(2^Q * x / D), we need to check if |
| 495 | // 2^Q * x / D = 2^(Q + e + k - eta - 1) * 5^(k - eta) is an integer or not. |
| 496 | if (k < ExtendedCache::segment_length || |
| 497 | e + k + static_cast<int>(cache_block_count * ExtendedCache::cache_bits_unit) - |
| 498 | static_cast<int>(excessive_bits_to_right) < |
| 499 | ExtendedCache::segment_length + 1) { |
| 500 | blocks_ptr[cache_block_count - 1] += (CacheBlockType(1) << excessive_bits_to_right); |
| 501 | BOOST_CHARCONV_ASSERT(blocks_ptr[cache_block_count - 1] != 0); |
| 502 | } |
| 503 | |
| 504 | return cache_block_count; |
| 505 | } |
| 506 | |
| 507 | template <bool constant_block_count, std::uint8_t max_cache_blocks> |
| 508 | struct cache_block_count_t; |
| 509 | |
| 510 | template <std::uint8_t max_cache_blocks> |
| 511 | struct cache_block_count_t<false, max_cache_blocks> |
| 512 | { |
| 513 | std::uint8_t value; |
| 514 | |
| 515 | operator std::uint8_t() const noexcept { return value; } // NOLINT : implicit conversions are ok for block count |
| 516 | cache_block_count_t& operator=(std::uint8_t new_value) noexcept |
| 517 | { |
| 518 | value = new_value; |
| 519 | return *this; |
| 520 | } |
| 521 | }; |
| 522 | |
| 523 | template <std::uint8_t max_cache_blocks> |
| 524 | struct cache_block_count_t<true, max_cache_blocks> |
| 525 | { |
| 526 | static constexpr std::uint8_t value = max_cache_blocks; |
| 527 | operator std::uint8_t() const noexcept { return value; } // NOLINT : implicit conversions are ok for block count |
| 528 | cache_block_count_t& operator=(std::uint8_t) noexcept |
| 529 | { |
| 530 | // Don't do anything. |
| 531 | return *this; |
| 532 | } |
| 533 | }; |
| 534 | |
| 535 | template <unsigned n> |
| 536 | struct uconst |
| 537 | { |
| 538 | constexpr uconst() {}; // NOLINT : Clang 3.x does not support = default |
| 539 | static constexpr unsigned value = n; |
| 540 | }; |
| 541 | |
| 542 | BOOST_INLINE_VARIABLE constexpr uconst<0> uconst0; |
| 543 | BOOST_INLINE_VARIABLE constexpr uconst<1> uconst1; |
| 544 | BOOST_INLINE_VARIABLE constexpr uconst<6> uconst6; |
| 545 | BOOST_INLINE_VARIABLE constexpr uconst<9> uconst9; |
| 546 | BOOST_INLINE_VARIABLE constexpr uconst<14> uconst14; |
| 547 | BOOST_INLINE_VARIABLE constexpr uconst<16> uconst16; |
| 548 | |
| 549 | #ifdef __clang__ |
| 550 | # pragma clang diagnostic push |
| 551 | # pragma clang diagnostic ignored "-Wsign-conversion" |
| 552 | #elif defined(__GNUC__) |
| 553 | # pragma GCC diagnostic push |
| 554 | # pragma GCC diagnostic ignored "-Wsign-conversion" |
| 555 | #elif defined(BOOST_MSVC) |
| 556 | # pragma warning(push) |
| 557 | # pragma warning(disable: 4365 4267) |
| 558 | #endif |
| 559 | |
| 560 | template <unsigned digits, bool dummy = (digits <= 9)> |
| 561 | struct uint_with_known_number_of_digits; |
| 562 | |
| 563 | template <unsigned digits_> |
| 564 | struct uint_with_known_number_of_digits<digits_, true> |
| 565 | { |
| 566 | static constexpr auto digits = digits_; |
| 567 | std::uint32_t value; |
| 568 | }; |
| 569 | |
| 570 | template <unsigned digits_> |
| 571 | struct uint_with_known_number_of_digits<digits_, false> |
| 572 | { |
| 573 | static constexpr auto digits = digits_; |
| 574 | std::uint64_t value; |
| 575 | }; |
| 576 | |
| 577 | template <typename HasFurtherDigits, typename... Args, typename std::enable_if<std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> |
| 578 | static BOOST_FORCEINLINE bool check_rounding_condition_inside_subsegment( |
| 579 | std::uint32_t current_digits, std::uint32_t fractional_part, |
| 580 | int remaining_digits_in_the_current_subsegment, HasFurtherDigits has_further_digits, |
| 581 | Args...) noexcept |
| 582 | { |
| 583 | if (fractional_part >= additional_static_data_holder::fractional_part_rounding_thresholds32[remaining_digits_in_the_current_subsegment - 1]) |
| 584 | { |
| 585 | return true; |
| 586 | } |
| 587 | |
| 588 | return ((fractional_part >> 31) & ((current_digits & 1) | has_further_digits)) != 0; |
| 589 | } |
| 590 | |
| 591 | template <typename HasFurtherDigits, typename... Args, |
| 592 | typename std::enable_if<!std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> |
| 593 | static BOOST_FORCEINLINE bool check_rounding_condition_inside_subsegment( |
| 594 | std::uint32_t current_digits, std::uint32_t fractional_part, |
| 595 | int remaining_digits_in_the_current_subsegment, HasFurtherDigits has_further_digits, |
| 596 | Args... args) noexcept |
| 597 | { |
| 598 | if (fractional_part >= additional_static_data_holder::fractional_part_rounding_thresholds32[remaining_digits_in_the_current_subsegment - 1]) |
| 599 | { |
| 600 | return true; |
| 601 | } |
| 602 | |
| 603 | return fractional_part >= 0x80000000 && ((current_digits & 1) != 0 || has_further_digits(args...)); |
| 604 | } |
| 605 | |
| 606 | template <typename HasFurtherDigits, typename... Args, |
| 607 | typename std::enable_if<std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> |
| 608 | static BOOST_FORCEINLINE bool check_rounding_condition_with_next_bit(std::uint32_t current_digits, bool next_bit, |
| 609 | HasFurtherDigits has_further_digits, Args...) noexcept |
| 610 | { |
| 611 | if (!next_bit) |
| 612 | { |
| 613 | return false; |
| 614 | } |
| 615 | |
| 616 | return ((current_digits & 1) | has_further_digits) != 0; |
| 617 | } |
| 618 | |
| 619 | template <typename HasFurtherDigits, typename... Args, |
| 620 | typename std::enable_if<!std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> |
| 621 | static BOOST_FORCEINLINE bool check_rounding_condition_with_next_bit(std::uint32_t current_digits, bool next_bit, |
| 622 | HasFurtherDigits has_further_digits, Args... args) noexcept |
| 623 | { |
| 624 | if (!next_bit) |
| 625 | { |
| 626 | return false; |
| 627 | } |
| 628 | |
| 629 | return (current_digits & 1) != 0 || has_further_digits(args...); |
| 630 | } |
| 631 | |
| 632 | template <typename UintWithKnownDigits, typename HasFurtherDigits, typename... Args, |
| 633 | typename std::enable_if<std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> |
| 634 | static BOOST_FORCEINLINE bool check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 635 | std::uint32_t current_digits, UintWithKnownDigits next_subsegment, |
| 636 | HasFurtherDigits has_further_digits, Args...) noexcept |
| 637 | { |
| 638 | if (next_subsegment.value > power_of_10[decltype(next_subsegment)::digits] / 2) |
| 639 | { |
| 640 | return true; |
| 641 | } |
| 642 | |
| 643 | return next_subsegment.value == power_of_10[decltype(next_subsegment)::digits] / 2 && |
| 644 | ((current_digits & 1) | has_further_digits) != 0; |
| 645 | } |
| 646 | |
| 647 | template <typename UintWithKnownDigits, typename HasFurtherDigits, typename... Args, |
| 648 | typename std::enable_if<!std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> |
| 649 | static BOOST_FORCEINLINE bool check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 650 | std::uint32_t current_digits, UintWithKnownDigits next_subsegment, |
| 651 | HasFurtherDigits has_further_digits, Args... args) noexcept |
| 652 | { |
| 653 | if (next_subsegment.value > power_of_10[decltype(next_subsegment)::digits] / 2) |
| 654 | { |
| 655 | return true; |
| 656 | } |
| 657 | |
| 658 | return next_subsegment.value == power_of_10[decltype(next_subsegment)::digits] / 2 && |
| 659 | ((current_digits & 1) != 0 || has_further_digits(args...)); |
| 660 | } |
| 661 | |
| 662 | #ifdef __clang__ |
| 663 | # pragma clang diagnostic pop |
| 664 | #elif defined(__GNUC__) |
| 665 | # pragma GCC diagnostic pop |
| 666 | #elif defined(BOOST_MSVC) |
| 667 | # pragma warning(pop) |
| 668 | #endif |
| 669 | |
| 670 | #ifdef BOOST_MSVC |
| 671 | # pragma warning(push) |
| 672 | # pragma warning(disable: 4307) // MSVC 14.1 emits warnings for uint64_t constants |
| 673 | #endif |
| 674 | |
| 675 | namespace has_further_digits_impl { |
| 676 | template <int k_right_threshold, int additional_neg_exp_of_2> |
| 677 | bool no_neg_k_can_be_integer(int k, int exp2_base) noexcept |
| 678 | { |
| 679 | return k < k_right_threshold || exp2_base + k < additional_neg_exp_of_2; |
| 680 | } |
| 681 | |
| 682 | template <int k_left_threshold, int k_right_threshold, int additional_neg_exp_of_2, int min_neg_exp_of_5, typename SignificandType> |
| 683 | bool only_one_neg_k_can_be_integer(int k, int exp2_base, SignificandType significand) noexcept |
| 684 | { |
| 685 | // Supposed to be k - additional_neg_exp_of_5_v < -min_neg_exp_of_5 || ... |
| 686 | if (k < k_left_threshold || exp2_base + k < additional_neg_exp_of_2) |
| 687 | { |
| 688 | return true; |
| 689 | } |
| 690 | // Supposed to be k - additional_neg_exp_of_5_v >= 0. |
| 691 | if (k >= k_right_threshold) |
| 692 | { |
| 693 | return false; |
| 694 | } |
| 695 | |
| 696 | BOOST_CXX14_CONSTEXPR std::uint64_t mod_inv = compute_power(UINT64_C(0xcccccccccccccccd), exp: static_cast<unsigned>(min_neg_exp_of_5)); |
| 697 | BOOST_CXX14_CONSTEXPR std::uint64_t max_quot = UINT64_C(0xffffffffffffffff) / compute_power(UINT64_C(5), exp: static_cast<unsigned>(min_neg_exp_of_5)); |
| 698 | |
| 699 | return (significand * mod_inv) > max_quot; |
| 700 | } |
| 701 | |
| 702 | template <int k_left_threshold, int k_middle_threshold, int k_right_threshold, |
| 703 | int additional_neg_exp_of_2, int min_neg_exp_of_5, int segment_length, |
| 704 | typename SignificandType> |
| 705 | bool only_two_neg_k_can_be_integer(int k, int exp2_base, |
| 706 | SignificandType significand) noexcept { |
| 707 | // Supposed to be k - additional_neg_exp_of_5_v < -min_neg_exp_of_5 - segment_length |
| 708 | // || ... |
| 709 | if (k < k_left_threshold || exp2_base + k < additional_neg_exp_of_2) { |
| 710 | return true; |
| 711 | } |
| 712 | // Supposed to be k - additional_neg_exp_of_5_v >= 0. |
| 713 | if (k >= k_right_threshold) { |
| 714 | return false; |
| 715 | } |
| 716 | |
| 717 | if (k >= k_middle_threshold) { |
| 718 | BOOST_CXX14_CONSTEXPR std::uint64_t mod_inv = |
| 719 | compute_power(UINT64_C(0xcccccccccccccccd), exp: static_cast<unsigned>(min_neg_exp_of_5)); |
| 720 | BOOST_CXX14_CONSTEXPR std::uint64_t max_quot = |
| 721 | UINT64_C(0xffffffffffffffff) / |
| 722 | compute_power(UINT64_C(5), exp: static_cast<unsigned>(min_neg_exp_of_5)); |
| 723 | |
| 724 | return (significand * mod_inv) > max_quot; |
| 725 | } |
| 726 | else { |
| 727 | BOOST_CXX14_CONSTEXPR std::uint64_t mod_inv = compute_power( |
| 728 | UINT64_C(0xcccccccccccccccd), exp: static_cast<unsigned>(min_neg_exp_of_5 + segment_length)); |
| 729 | BOOST_CXX14_CONSTEXPR std::uint64_t max_quot = |
| 730 | UINT64_C(0xffffffffffffffff) / |
| 731 | compute_power(UINT64_C(5), |
| 732 | exp: static_cast<unsigned>(min_neg_exp_of_5 + segment_length)); |
| 733 | |
| 734 | return (significand * mod_inv) > max_quot; |
| 735 | } |
| 736 | } |
| 737 | } // Namespace has_further_digits_impl |
| 738 | |
| 739 | #ifdef BOOST_MSVC |
| 740 | #pragma warning(pop) |
| 741 | #endif |
| 742 | |
| 743 | inline void print_1_digit(std::uint32_t n, char* buffer) noexcept |
| 744 | { |
| 745 | *buffer = char('0' + n); |
| 746 | } |
| 747 | |
| 748 | inline void print_2_digits(std::uint32_t n, char* buffer) noexcept |
| 749 | { |
| 750 | std::memcpy(dest: buffer, src: additional_static_data_holder::radix_100_table + n * 2, n: 2); |
| 751 | } |
| 752 | |
| 753 | inline void print_6_digits(std::uint32_t n, char* buffer) noexcept |
| 754 | { |
| 755 | // 429497 = ceil(2^32/10^4) |
| 756 | auto prod = (n * UINT64_C(429497)) + 1; |
| 757 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 758 | |
| 759 | for (int i = 0; i < 2; ++i) |
| 760 | { |
| 761 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 762 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer: buffer + 2 + i * 2); |
| 763 | } |
| 764 | } |
| 765 | |
| 766 | inline void print_7_digits(std::uint32_t n, char* buffer) noexcept |
| 767 | { |
| 768 | // 17592187 = ceil(2^(32+12)/10^6) |
| 769 | auto prod = ((n * UINT64_C(17592187)) >> 12) + 1; |
| 770 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 771 | |
| 772 | for (int i = 0; i < 3; ++i) |
| 773 | { |
| 774 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 775 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer: buffer + 1 + i * 2); |
| 776 | } |
| 777 | } |
| 778 | |
| 779 | inline void print_8_digits(std::uint32_t n, char* buffer) noexcept |
| 780 | { |
| 781 | // 140737489 = ceil(2^(32+15)/10^6) |
| 782 | auto prod = ((n * UINT64_C(140737489)) >> 15) + 1; |
| 783 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 784 | |
| 785 | for (int i = 0; i < 3; ++i) |
| 786 | { |
| 787 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 788 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer: buffer + 2 + i * 2); |
| 789 | } |
| 790 | } |
| 791 | |
| 792 | inline void print_9_digits(std::uint32_t n, char* buffer) noexcept |
| 793 | { |
| 794 | // 1441151881 = ceil(2^(32+25)/10^8) |
| 795 | auto prod = ((n * UINT64_C(1441151881)) >> 25) + 1; |
| 796 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 797 | |
| 798 | for (int i = 0; i < 4; ++i) |
| 799 | { |
| 800 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 801 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer: buffer + 1 + i * 2); |
| 802 | } |
| 803 | } |
| 804 | |
| 805 | struct main_cache_full |
| 806 | { |
| 807 | template <typename FloatFormat> |
| 808 | static constexpr typename main_cache_holder::cache_entry_type get_cache(int k) noexcept |
| 809 | { |
| 810 | return main_cache_holder::cache[std::size_t(k - main_cache_holder::min_k)]; |
| 811 | } |
| 812 | }; |
| 813 | |
| 814 | struct main_cache_compressed |
| 815 | { |
| 816 | template <typename FloatFormat> |
| 817 | static BOOST_CHARCONV_CXX14_CONSTEXPR typename main_cache_holder::cache_entry_type get_cache(int k) noexcept |
| 818 | { |
| 819 | BOOST_CHARCONV_ASSERT(k >= main_cache_holder::min_k && k <= main_cache_holder::max_k); |
| 820 | |
| 821 | BOOST_IF_CONSTEXPR (std::is_same<FloatFormat, ieee754_binary64>::value) |
| 822 | { |
| 823 | // Compute the base index. |
| 824 | const auto cache_index = |
| 825 | static_cast<int>(static_cast<std::uint32_t>(k - main_cache_holder::min_k) / |
| 826 | compressed_cache_detail::compression_ratio); |
| 827 | |
| 828 | const auto kb = cache_index * compressed_cache_detail::compression_ratio + |
| 829 | main_cache_holder::min_k; |
| 830 | |
| 831 | const auto offset = k - kb; |
| 832 | |
| 833 | // Get the base cache. |
| 834 | const auto base_cache = compressed_cache_detail::cache_holder_t::table[cache_index]; |
| 835 | |
| 836 | if (offset == 0) |
| 837 | { |
| 838 | return base_cache; |
| 839 | } |
| 840 | else |
| 841 | { |
| 842 | |
| 843 | // Compute the required amount of bit-shift. |
| 844 | const auto alpha = log::floor_log2_pow10(e: kb + offset) - log::floor_log2_pow10(e: kb) - offset; |
| 845 | BOOST_CHARCONV_ASSERT(alpha > 0 && alpha < 64); |
| 846 | |
| 847 | // Try to recover the real cache. |
| 848 | const auto pow5 = compressed_cache_detail::pow5_holder_t::table[offset]; |
| 849 | auto recovered_cache = umul128(x: base_cache.high, y: pow5); |
| 850 | const auto middle_low = umul128(x: base_cache.low, y: pow5); |
| 851 | |
| 852 | recovered_cache += middle_low.high; |
| 853 | |
| 854 | const auto high_to_middle = recovered_cache.high << (64 - alpha); |
| 855 | const auto middle_to_low = recovered_cache.low << (64 - alpha); |
| 856 | |
| 857 | recovered_cache = uint128{(recovered_cache.low >> alpha) | high_to_middle, ((middle_low.low >> alpha) | middle_to_low)}; |
| 858 | |
| 859 | BOOST_CHARCONV_ASSERT(recovered_cache.low + 1 != 0); |
| 860 | recovered_cache = uint128(recovered_cache.high, recovered_cache.low + 1); |
| 861 | |
| 862 | return recovered_cache; |
| 863 | } |
| 864 | } |
| 865 | else |
| 866 | { |
| 867 | // Just use the full cache for anything other than binary64 |
| 868 | return main_cache_holder::cache[std::size_t(k - main_cache_holder::min_k)]; |
| 869 | } |
| 870 | } |
| 871 | }; |
| 872 | |
| 873 | template <bool b> |
| 874 | struct extended_cache_long_impl |
| 875 | { |
| 876 | static constexpr std::size_t max_cache_blocks = 3; |
| 877 | static constexpr std::size_t cache_bits_unit = 64; |
| 878 | static constexpr int segment_length = 22; |
| 879 | static constexpr bool constant_block_count = true; |
| 880 | static constexpr int e_min = -1074; |
| 881 | static constexpr int k_min = -272; |
| 882 | static constexpr int cache_bit_index_offset_base = 977; |
| 883 | static constexpr std::uint64_t cache[] = { |
| 884 | 0xa37fce126597973c, 0xe50ff107bab528a0, 0x8f1ba3f17395a391, 0xd56bdc876cdb4648, |
| 885 | 0x6ca000bdd9e33bd4, 0x23cf34bbf983f78b, 0x8737d87296e93f5d, 0xa2824ba6d9df301d, |
| 886 | 0x8ce3eccf7cfb42ab, 0xe5ecdc0b78109f00, 0xa620c9995c9c5c3a, 0xa0f79c97ac210943, |
| 887 | 0x64dfb5636985915f, 0xc12f542e4c7ea6ee, 0x34de81232784ea17, 0xd0cbde7fac4643f2, |
| 888 | 0x5d9400de8fef7552, 0x81214f68696d9af2, 0xb7d0e0a2ccaccf20, 0x5c4ed9243f16193d, |
| 889 | 0xf71838486e60b926, 0x48892047ec1a8bf4, 0x14ff2faa9c32befa, 0x666fbaa24ddbb8e9, |
| 890 | 0x436682c807652a58, 0xed98ddaee19068c7, 0x63badd624dd9b095, 0x72dbb637d5b77493, |
| 891 | 0xd01998fb8d9e8861, 0xacb39418dce017b9, 0x8db8f2f13eed81cf, 0xfd699fbb7d0a737a, |
| 892 | 0x011cd67160923d91, 0x9a66fd7732c14d98, 0x235857d065a52d18, 0x895288951dab0d8e, |
| 893 | 0x59041cb66e4f0e68, 0x5e7c68240249e750, 0x8881a2a6ab00987b, 0x5fc8c32c863aaeac, |
| 894 | 0x3bafbe662a7f81a8, 0xd47692705ae76b64, 0xeb1cc7d99143fb53, 0xcf8be24f7b0fc499, |
| 895 | 0x6a276e8f0fbf33eb, 0x63b2d61966fa7243, 0x0970327d2cc58011, 0x43ff09410ec24aae, |
| 896 | 0x0bdb6f345ea1851d, 0x409c37132c5836ff, 0xf3150f74a6190324, 0x5c358d6c07453d23, |
| 897 | 0x7207012ad7846ba7, 0x61ad5d0772604733, 0x19a20a6e21c2018d, 0x5f568fd497ef18b2, |
| 898 | 0xeda5815eed00749f, 0x029531461bc483d8, 0xb8789d7784875911, 0x6fc40572236f2ba5, |
| 899 | 0x9c2a50a76ace3168, 0xbf4815c2bea56741, 0xf84e8f2fe9b211f5, 0x689033182d2ea7ed, |
| 900 | 0x5bcb3a3230a68f47, 0xa848403d116805ef, 0xfaeaa73623b79604, 0x31d76828d2181b64, |
| 901 | 0x7c4eabddc7dd634b, 0xc2b13231eeff6fda, 0x8094743db32bf251, 0x2df07391bde052d2, |
| 902 | 0xffd9bdbf321ad8ae, 0x06b2c6d1cf6cf742, 0xf32a54ce1598fe8f, 0x1cc2e3082d28897e, |
| 903 | 0x0485f2e46b488584, 0xe3f6965b145a49cb, 0x406eaa1217aefe69, 0x0777373638de456b, |
| 904 | 0xcde91853b592212b, 0x3faf7b46d7f79c18, 0x558d83afb7127381, 0x5f490259c7957aeb, |
| 905 | 0x76e6540e246d73cc, 0x5098a935a866dc75, 0xc50d9c29002d9e73, 0xcc8f8252faac0b7f, |
| 906 | 0xb759afb688f8251d, 0x6a2934d3036c85d3, 0x570eb3ce4c86407f, 0x036f2b68794754af, |
| 907 | 0x57661a5d6993fe2c, 0x6d07b7fabe546a80, 0x38efe4029259743c, 0x548f417ebaa61c6c, |
| 908 | 0xb0c31fa64a3fcc9e, 0x7dab825964fb7100, 0xd0c92ae8207d6f22, 0xf1e38a8a9c541144, |
| 909 | 0x2139951c68d0385b, 0x9d9e22c42f139287, 0x4fea4d670876b800, 0x35f293a9a62252d4, |
| 910 | 0x4b606b26f1922c5c, 0x8e5660b37505cb11, 0x868138391855da81, 0x6e95f6c9b45c7aa2, |
| 911 | 0x425ff75e14fc31a1, 0x258379a94d028d18, 0xdf2ccd1fe00a03b6, 0x398471c1ff970f83, |
| 912 | 0x8c36b2214a3db8e7, 0x431dd42c3fe7f4fb, 0xb09bcf0fffb5b849, 0xc47dd13da60fb5a1, |
| 913 | 0x8fdad56516fe9d75, 0xc317e1025a7e1c63, 0x9ddcb98cbb384fda, 0x80adccda993bf70e, |
| 914 | 0x667f1622e4052ae4, 0xa41598d58f777363, 0x704b93d675808501, 0xaf046d3fd448aaf3, |
| 915 | 0x1dc4611873bf3f70, 0x834acdae9f0f4f53, 0x4f5d60585a5f1c1a, 0x3ced1b4be0d415c1, |
| 916 | 0x5d57f4de8ec12376, 0x51c0e7e72f799542, 0x46f7604940e6a510, 0x1a546a0f9345ed75, |
| 917 | 0x0df4097cab773ca2, 0x72b122774e4029e6, 0xae4a55b99aebd424, 0x04163a291bad2fa3, |
| 918 | 0x86ad58be322a49aa, 0x98f051614696e839, 0x64d08f241fc4ec58, 0xae41f23dca90dd5d, |
| 919 | 0x68bbd62f5af3107a, 0x7025f39ef241c56c, 0xd2e7c72fa9be33ac, 0x0aece66fd3e29a7d, |
| 920 | 0xd91241cebf3bd47c, 0x3ed7bfdee19ba2f6, 0x4bdf483194c7444e, 0xc99d83c931e8ab87, |
| 921 | 0x1732f416dbf7381f, 0x2ac88e244de13b96, 0x2cab688bd86c8bf8, 0x9f209787bb47d6b8, |
| 922 | 0x4c0678c5dbd23a49, 0xa0612c3c5ce15e55, 0x4dccc6ca29b3e9df, 0x0dc079c918022212, |
| 923 | 0x26be55a64c249495, 0x4da2c9789dd268b0, 0xe975528c76435158, 0xa6cb8a4d2356f9cf, |
| 924 | 0xdcafd2279c77d987, 0xaa9aff7904228690, 0xfb44d2f05d0842fb, 0x118fc9c217a1d2b2, |
| 925 | 0x04b3d9686f55b572, 0xbd9cb3625ef1cfc3, 0x2eba0e25e938e6c3, 0x1f48eaf234ad3a21, |
| 926 | 0xf2dc02fad2890f79, 0xace340325d4a7f9b, 0xe9e051f540b239dc, 0x221091f05abb8687, |
| 927 | 0x7e08deb014db8afe, 0x4711e1e9d9a094cc, 0x0b2d79bd90a9ef61, 0xb93d19bd45b82515, |
| 928 | 0x45e9e31d63c1afe1, 0x2c5f0a596005c216, 0xe687cc2331b14a12, 0x51963a2412b6f60c, |
| 929 | 0x91aeb77c8fe68eaa, 0xd6e18e8cc6841d68, 0x9391085cc2c933d9, 0x6e184be07e68df49, |
| 930 | 0x4fe4e52edb0dce60, 0x6cda31e8617f0ca2, 0xf8b9374fda7e7c95, 0x8032c603725e774d, |
| 931 | 0x222b6aa27e007612, 0xf7b7f47cf096afad, 0xe6a9fbafee77e77a, 0x3776ee406e63fbaa, |
| 932 | 0xde147932fcf78be6, 0x2ab9e031ffaa071e, 0x2169ad0e8a9b1256, 0xe33358135938b76a, |
| 933 | 0xcaec07e7a5373835, 0xef2863090a97c3ec, 0x6ccfb95f69c3adcc, 0x173e00da427cee4b, |
| 934 | 0x20f4ed58fcfb3040, 0x16f6fb326a60c32c, 0x2968fa04270ed545, 0x70673adfac0eabc4, |
| 935 | 0x6ff3c9364ff4e873, 0xde09ed35f13325d3, 0x2396e863b18c500f, 0xe22d253cc031e3ff, |
| 936 | 0x756d97a61247798d, 0xc9fc8d937e43c880, 0x0759ba59c08e14c7, 0xcd7aad86a4a45810, |
| 937 | 0x9f91c21c571dbe84, 0xd52d936f44abe8a3, 0xd5b48c100959d9d0, 0xb6cc856b3adc93b6, |
| 938 | 0x7aea8f8e067d2c8d, 0x04bc177f7b4287a6, 0xe3fcda36fa3b3342, 0xeaeb442e15d45095, |
| 939 | 0x2f4dd1ca5e89b18b, 0x602368385bb19cb1, 0x4bdfc434d3028181, 0x0b5a92cb80ac8150, |
| 940 | 0xb95953a97b1578ab, 0x46e6a18b01781b92, 0xdfd31585f38d7433, 0x0b1084b96009370b, |
| 941 | 0x9a81808e52462ba3, 0xff83368ace4af235, 0xb4e5d8a647e05e95, 0xf848cfc90df4b231, |
| 942 | 0x9919c68cf3576038, 0x1e89dad8a6790435, 0x7ac9361379139511, 0x7b5f9b6b937a7760, |
| 943 | 0x6e42e395fde0c1f7, 0x430cef1679799f8f, 0x0ad21cc1b4828074, 0x8982577d0ea42349, |
| 944 | 0xb1aca6185a7d0d0d, 0x4085c6db106c3d74, 0xba6f7a86e728a418, 0x0325a28758a974d2, |
| 945 | 0x57ea317f731817ed, 0xbd1e8e00b215a6eb, 0xb39f323742948e87, 0x9f9b0f873784cef4, |
| 946 | 0xa8c83d26585c5377, 0x837ba337bfcf893c, 0x0a7eeca62a23b805, 0xba4925a9e7f7346f, |
| 947 | 0xa574eebb90c8da6d, 0x5db7ff0e8d0b8d2d, 0x1562834c52c048d8, 0x0b2e577a853bcafc, |
| 948 | 0xdecef97a3524ff97, 0xeec053c8fd537066, 0xeaf2b1df83d600e4, 0x5be8b9ab7717eccf, |
| 949 | 0x05905b91ecbba038, 0xabacba5b373029ed, 0x22fb2283c0ee1267, 0x9c32b2ec3634c580, |
| 950 | 0x5186c586b6e5611c, 0x71eb0de5e91bb0a0, 0x89e969b42975ef08, 0x2ba0958bc44e322f, |
| 951 | 0x626d033cb828ba7d, 0xe5fbb65c7776509d, 0xb1403ae51ae9bc82, 0x5d773f0d9753a966, |
| 952 | 0x4a06feadd4ec8585, 0xda58a710fccd7b76, 0x6061ba4cd3d80d59, 0xf4824f5cfa2ba71c, |
| 953 | 0xfce622bba0ece756, 0x7d9c738486bc6842, 0x5f629d33c99db969, 0x855ff7c9b79362e6, |
| 954 | 0x892188a87c7de231, 0x85fea7caf30e2b5e, 0xbefeb221543782c5, 0x769ca33d280842f6, |
| 955 | 0x3974ebaf71353e52, 0xed0577283980f0cb, 0x7c37d689ab6b0662, 0x5037aeffcd3db52d, |
| 956 | 0x11bb0a5f64fbdcb5, 0xf5fd5aa5f2b7e974, 0xe1aa07ba7074367b, 0x4b5c14aa1c6a0d28, |
| 957 | 0xe9fc8c9c36f73953, 0x2609ad2cd0f99b76, 0x8d4f1d6bb589844f, 0xde09f066714fa909, |
| 958 | 0xe004c5d7adad3747, 0xd5ac81a94dfdefe3, 0xfd3e0083658a13c2, 0xf5512f25dd6e39a7, |
| 959 | 0xeb7204042ffa181d, 0x046d9254242d06e3, 0x91a5ca94f8706fab, 0xf5c58cc57af63c98, |
| 960 | 0x04e7ff1e23474908, 0xe4a9bec5c5818324, 0x1edfb105cc3084dd, 0x82431ec76e72a87a, |
| 961 | 0xe0b215be32c51083, 0x0d9942e3b5245098, 0xa49f1aad5723fd7e, 0xad45edba25a4bde8, |
| 962 | 0x241f0adc0cd56771, 0xf09bf2de59df3274, 0x090db856bbc020f2, 0x6aa4efb2d2ecb9bb, |
| 963 | 0xc6be4224ba04c233, 0x557a1760bde90850, 0x23090117938cb921, 0xcbec34da23f3e9c2, |
| 964 | 0xdfe2d55daad85c54, 0xa7932be700067f48, 0xfb7874535e2d76a4, 0x5161ba088056e74f, |
| 965 | 0xc275a8435be6cdb2, 0x05fcb771cab5aa15, 0x7f18a4382c9565a8, 0x4244c2cb833d6710, |
| 966 | 0x884e2b7a4a3db4d0, 0x08ded459d3edf2c2, 0x1616df531fee90cd, 0x9531c65800a97aaa, |
| 967 | 0x881ba77ab7e5d63a, 0x606d27428df4edd3, 0x294063ed78e305c7, 0x7de2b12f8a8cceb5, |
| 968 | 0xe6b01cc54a494437, 0x0cdecbe5ac90907c, 0xb88496c657d3e644, 0xf3eecf996f9c6b13, |
| 969 | 0x24aad7949edcde03, 0x304ca88ebfeaa534, 0x7b68a7bd3ef1916b, 0x3cc307a784d9060c, |
| 970 | 0x5dca03f19b213efd, 0xa380539c235f80c3, 0xf39756fc01d75bd7, 0x39ac6c7281739adb, |
| 971 | 0x4b606dc4aa036fda, 0x97126cd02a23b97c, 0x98c1e6906230aead, 0xe12d0f696a6bbc36, |
| 972 | 0x657a202bb6a89a33, 0x6421a07bda47e13d, 0x8d9d21b3c6b1dbee, 0x1f110f3744f13e0d, |
| 973 | 0x04d86fccb6e77ee8, 0x8c92852d9c9c14b3, 0x56be3cef19b19446, 0x57ceef0e2ebcbcf7, |
| 974 | 0x230a9328be0144bf, 0x3c1949b98a92aebc, 0x7ed2db80a62003f2, 0x84e609d13c7594f4, |
| 975 | 0xf8e81b9a9f35b4e8, 0xc2982fde1a087e4b, 0x84b0713cb3b18147, 0x3582530578d1ff08, |
| 976 | 0x0e5b6538cd61fce4, 0x46867abf4b6e72bc, 0x4fe9652832325e89, 0x7d141d065654745f, |
| 977 | 0x9bd5c0479188a53d, 0x4ccd47925108c00b, 0xfd3f6c8d961d47e3, 0x9c5c18a96093d2ad, |
| 978 | 0xa7d91bf008a358c3, 0x3ea3e5629f977d55, 0x80f0fed6a5f06003, 0x21f390e377ee4d68, |
| 979 | 0x73ed055ec082526b, 0x28482600c10f6ce2, 0x2bff1aaf94c11fe9, 0xde29cb7a943801b8, |
| 980 | 0x045b0493dd35af0e, 0xaeae25ff7a431c16, 0x78c9d3348f5364b7, 0xf973d1af84bc2476, |
| 981 | 0x4d2303e11baf18f3, 0xacebdb3fe5efbc7b, 0xd274a5cf5be50678, 0x2d60c40fdf53ac67, |
| 982 | 0x109592b606139855, 0x612f472a9c09925f, 0x701a035ccd4e7ab0, 0xac881f0db121a709, |
| 983 | 0xe1ed47438368366d, 0xde2faff8eeb2810a, 0x8eb2188044342ef9, 0x0e3c1aa7b6851548, |
| 984 | 0x7ce94a6ba4fd843f, 0x0da503676ee5ebb2, 0xf3bc7bb2cb8669e8, 0xd4b9e44de392fe64, |
| 985 | 0x81e470ebf207fdea, 0xdd53b09d49a0e5b5, 0xf78e23167a350d5a, 0x706470fc2d84423b, |
| 986 | 0x816ee82b19a29476, 0x35a9d218ba7cd4a1, 0xf590f12fb09b3fe3, 0x5e574140b302f8b7, |
| 987 | 0x6cb237a2021f77c3, 0x30a29037231a861e, 0xff4bb07af553a606, 0x831412ee2690d92c, |
| 988 | 0xf6d2d725ef14ff67, 0x2f79f810928a40ff, 0x2857d91ea9b04f71, 0xd063066f0ed78f3c, |
| 989 | 0xbf4b8dbc8a34017d, 0x6230f319f8b1f9c4, 0x061b0e25d8899834, 0x4071de32ef7ff0bf, |
| 990 | 0xbc546a0793fcfcd3, 0xd5881f5d968cf898, 0x0e21c0674cdda190, 0x0000000000000000}; |
| 991 | |
| 992 | struct multiplier_index_info |
| 993 | { |
| 994 | std::uint16_t first_cache_bit_index; |
| 995 | std::uint16_t cache_bit_index_offset; |
| 996 | }; |
| 997 | |
| 998 | static constexpr multiplier_index_info multiplier_index_info_table[] = { |
| 999 | {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 | {.first_cache_bit_index: 0, .cache_bit_index_offset: 0, .cache_block_count_index_offset: 0}, {.first_cache_bit_index: 377, .cache_bit_index_offset: 643, .cache_block_count_index_offset: 9}, {.first_cache_bit_index: 1020, .cache_bit_index_offset: 1551, .cache_block_count_index_offset: 22}, {.first_cache_bit_index: 1924, .cache_bit_index_offset: 2721, .cache_block_count_index_offset: 39}, |
| 1085 | {.first_cache_bit_index: 3046, .cache_bit_index_offset: 4109, .cache_block_count_index_offset: 60}, {.first_cache_bit_index: 3114, .cache_bit_index_offset: 4443, .cache_block_count_index_offset: 70}, {.first_cache_bit_index: 3368, .cache_bit_index_offset: 4962, .cache_block_count_index_offset: 84}, {.first_cache_bit_index: 3807, .cache_bit_index_offset: 5667, .cache_block_count_index_offset: 98}, |
| 1086 | {.first_cache_bit_index: 4432, .cache_bit_index_offset: 6473, .cache_block_count_index_offset: 111}, {.first_cache_bit_index: 5158, .cache_bit_index_offset: 7199, .cache_block_count_index_offset: 123}, {.first_cache_bit_index: 5804, .cache_bit_index_offset: 7845, .cache_block_count_index_offset: 134}, {.first_cache_bit_index: 6370, .cache_bit_index_offset: 8411, .cache_block_count_index_offset: 143}, |
| 1087 | {.first_cache_bit_index: 6856, .cache_bit_index_offset: 8896, .cache_block_count_index_offset: 151}, {.first_cache_bit_index: 7261, .cache_bit_index_offset: 9302, .cache_block_count_index_offset: 158}, {.first_cache_bit_index: 7587, .cache_bit_index_offset: 9628, .cache_block_count_index_offset: 164}, {.first_cache_bit_index: 7833, .cache_bit_index_offset: 9874, .cache_block_count_index_offset: 168}, |
| 1088 | {.first_cache_bit_index: 7999, .cache_bit_index_offset: 10039, .cache_block_count_index_offset: 171}, {.first_cache_bit_index: 8084, .cache_bit_index_offset: 10124, .cache_block_count_index_offset: 173}, {.first_cache_bit_index: 8089, .cache_bit_index_offset: 0, .cache_block_count_index_offset: 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 | {.first_cache_bit_index: 0, .cache_bit_index_offset: 0, .cache_block_count_index_offset: 0}, {.first_cache_bit_index: 860, .cache_bit_index_offset: 1698, .cache_block_count_index_offset: 13}, {.first_cache_bit_index: 2506, .cache_bit_index_offset: 4181, .cache_block_count_index_offset: 29}, {.first_cache_bit_index: 2941, .cache_bit_index_offset: 5069, .cache_block_count_index_offset: 36}, |
| 1155 | {.first_cache_bit_index: 3577, .cache_bit_index_offset: 5705, .cache_block_count_index_offset: 41}, {.first_cache_bit_index: 3961, .cache_bit_index_offset: 6088, .cache_block_count_index_offset: 44}, {.first_cache_bit_index: 4092, .cache_bit_index_offset: 0, .cache_block_count_index_offset: 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 {.ptr: buffer + 1, .ec: std::errc()}; |
| 1311 | } |
| 1312 | |
| 1313 | if (buffer_size < static_cast<std::size_t>(precision) + 2U) |
| 1314 | { |
| 1315 | return {.ptr: buffer + buffer_size, .ec: std::errc::value_too_large}; |
| 1316 | } |
| 1317 | |
| 1318 | std::memcpy(dest: buffer, src: "0." , n: 2); // NOLINT : Specifically not null-terminating |
| 1319 | std::memset(s: buffer + 2, c: '0', n: static_cast<std::size_t>(precision)); // NOLINT : Specifically not null-terminating |
| 1320 | return {.ptr: buffer + 2 + precision, .ec: 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 {.ptr: last, .ec: 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 {.ptr: buffer, .ec: 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 {.ptr: last, .ec: std::errc::value_too_large}; |
| 1368 | } |
| 1369 | |
| 1370 | std::memcpy(dest: buffer, src: "inf" , n: inf_chars); // NOLINT : Specifically not null-terminating |
| 1371 | return {.ptr: buffer + inf_chars, .ec: 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 {.ptr: last, .ec: std::errc::value_too_large}; |
| 1388 | } |
| 1389 | |
| 1390 | std::memcpy(dest: buffer, src: "nan" , n: nan_chars); // NOLINT : Specifically not null-terminating |
| 1391 | return {.ptr: buffer + nan_chars, .ec: 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 {.ptr: last, .ec: std::errc::value_too_large}; |
| 1400 | } |
| 1401 | |
| 1402 | std::memcpy(dest: buffer, src: "nan(ind)" , n: neg_nan_chars); // NOLINT : Specifically not null-terminating |
| 1403 | return {.ptr: buffer + neg_nan_chars, .ec: 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 {.ptr: last, .ec: std::errc::value_too_large}; |
| 1413 | } |
| 1414 | |
| 1415 | std::memcpy(dest: buffer, src: "nan(snan)" , n: snan_chars); // NOLINT : Specifically not null-terminating |
| 1416 | return {.ptr: buffer + snan_chars, .ec: 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 {.ptr: buffer + 1, .ec: 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 {.ptr: last, .ec: std::errc::value_too_large}; |
| 1452 | } |
| 1453 | |
| 1454 | std::memcpy(dest: buffer, src: "0e+00" , n: zero_chars); |
| 1455 | return {.ptr: buffer + zero_chars, .ec: std::errc()}; |
| 1456 | } |
| 1457 | else |
| 1458 | { |
| 1459 | if (buffer_size < static_cast<std::size_t>(precision) + 6U) |
| 1460 | { |
| 1461 | return {.ptr: last, .ec: std::errc::value_too_large}; |
| 1462 | } |
| 1463 | |
| 1464 | std::memcpy(dest: buffer, src: "0." , n: 2); // NOLINT : Specifically not null-terminating |
| 1465 | std::memset(s: buffer + 2, c: '0', n: static_cast<std::size_t>(precision)); // NOLINT : Specifically not null-terminating |
| 1466 | std::memcpy(dest: buffer + 2 + precision, src: "e+00" , n: 4); // NOLINT : Specifically not null-terminating |
| 1467 | return {.ptr: buffer + precision + 6, .ec: 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(e: 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 {.ptr: last, .ec: 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 {.ptr: last, .ec: 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 {.ptr: buffer + 1, .ec: std::errc()}; |
| 1603 | } |
| 1604 | |
| 1605 | if (buffer_size < static_cast<std::size_t>(precision) + 2U) |
| 1606 | { |
| 1607 | return {.ptr: buffer + buffer_size, .ec: std::errc::value_too_large}; |
| 1608 | } |
| 1609 | |
| 1610 | std::memcpy(dest: buffer, src: "0." , n: 2); // NOLINT : Specifically not null-terminating |
| 1611 | std::memset(s: buffer + 2, c: '0', n: static_cast<std::size_t>(precision - 1)); // NOLINT : Specifically not null-terminating |
| 1612 | buffer[1 + precision] = '1'; |
| 1613 | return {.ptr: buffer + 2 + precision, .ec: 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 {.ptr: last, .ec: std::errc::value_too_large}; |
| 1624 | } |
| 1625 | |
| 1626 | // Print leading zeros. |
| 1627 | std::memset(s: buffer, c: '0', n: 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(x: 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(x: 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(n: 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(n: 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(x: 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 ? 1 : 0); |
| 1767 | remaining_digits -= (2 - (initial_digits < 10 ? 1 : 0)); |
| 1768 | print_2_digits(n: initial_digits, buffer); |
| 1769 | buffer += 2; |
| 1770 | |
| 1771 | if (remaining_digits > remaining_digits_in_the_current_subsegment) |
| 1772 | { |
| 1773 | remaining_digits -= remaining_digits_in_the_current_subsegment; |
| 1774 | |
| 1775 | for (; remaining_digits_in_the_current_subsegment > 0; remaining_digits_in_the_current_subsegment -= 2) |
| 1776 | { |
| 1777 | // Write next two digits. |
| 1778 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 1779 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 1780 | buffer += 2; |
| 1781 | } |
| 1782 | } |
| 1783 | else |
| 1784 | { |
| 1785 | for (int i = 0; i < (remaining_digits - 1) / 2; ++i) |
| 1786 | { |
| 1787 | // Write next two digits. |
| 1788 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 1789 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 1790 | buffer += 2; |
| 1791 | } |
| 1792 | |
| 1793 | // Distinguish two cases of rounding. |
| 1794 | if (remaining_digits_in_the_current_subsegment > remaining_digits) |
| 1795 | { |
| 1796 | if ((remaining_digits & 1) != 0) |
| 1797 | { |
| 1798 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 1799 | } |
| 1800 | else |
| 1801 | { |
| 1802 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 1803 | } |
| 1804 | |
| 1805 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 1806 | |
| 1807 | if (check_rounding_condition_inside_subsegment( |
| 1808 | current_digits, fractional_part: static_cast<std::uint32_t>(prod), |
| 1809 | remaining_digits_in_the_current_subsegment: remaining_digits_in_the_current_subsegment - remaining_digits, |
| 1810 | has_further_digits: second_third_subsegments != 0 || has_more_segments)) |
| 1811 | { |
| 1812 | goto round_up; |
| 1813 | } |
| 1814 | |
| 1815 | goto print_last_digits; |
| 1816 | } |
| 1817 | else |
| 1818 | { |
| 1819 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 1820 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 1821 | |
| 1822 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 1823 | current_digits, |
| 1824 | next_subsegment: uint_with_known_number_of_digits<10>{.value: second_third_subsegments}, |
| 1825 | has_further_digits: has_more_segments)) |
| 1826 | { |
| 1827 | goto round_up_two_digits; |
| 1828 | } |
| 1829 | |
| 1830 | goto print_last_two_digits; |
| 1831 | } |
| 1832 | } |
| 1833 | } |
| 1834 | |
| 1835 | // Print the second subsegment. |
| 1836 | // The second subsegment cannot be zero even for subnormal numbers. |
| 1837 | |
| 1838 | if (remaining_digits <= 2) |
| 1839 | { |
| 1840 | // In this case the first subsegment must be nonzero. |
| 1841 | |
| 1842 | if (remaining_digits == 1) |
| 1843 | { |
| 1844 | const auto prod128 = umul128(x: second_third_subsegments, UINT64_C(18446744074)); |
| 1845 | |
| 1846 | current_digits = static_cast<std::uint32_t>(prod128.high); |
| 1847 | const auto fractional_part64 = prod128.low + 1; |
| 1848 | // 18446744074 is even, so prod.low cannot be equal to 2^64 - 1. |
| 1849 | BOOST_CHARCONV_ASSERT(fractional_part64 != 0); |
| 1850 | |
| 1851 | if (fractional_part64 >= additional_static_data_holder::fractional_part_rounding_thresholds64[8] || |
| 1852 | ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0) |
| 1853 | { |
| 1854 | goto round_up_one_digit; |
| 1855 | } |
| 1856 | |
| 1857 | goto print_last_one_digit; |
| 1858 | } // remaining_digits == 1 |
| 1859 | else |
| 1860 | { |
| 1861 | const auto prod128 = umul128(x: second_third_subsegments, UINT64_C(184467440738)); |
| 1862 | |
| 1863 | current_digits = static_cast<std::uint32_t>(prod128.high); |
| 1864 | const auto fractional_part64 = prod128.low + 1; |
| 1865 | // 184467440738 is even, so prod.low cannot be equal to 2^64 - 1. |
| 1866 | BOOST_CHARCONV_ASSERT(fractional_part64 != 0); |
| 1867 | |
| 1868 | if (fractional_part64 >= additional_static_data_holder::fractional_part_rounding_thresholds64[7] || |
| 1869 | ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0) |
| 1870 | { |
| 1871 | goto round_up_two_digits; |
| 1872 | } |
| 1873 | |
| 1874 | goto print_last_two_digits; |
| 1875 | } |
| 1876 | } // remaining_digits <= 2 |
| 1877 | |
| 1878 | // Compilers are not aware of how to leverage the maximum value of |
| 1879 | // second_third_subsegments to find out a better magic number which allows us to |
| 1880 | // eliminate an additional shift. |
| 1881 | // 184467440737095517 = ceil(2^64/100) < floor(2^64*(10^8/(10^10 - 1))). |
| 1882 | const auto second_subsegment = static_cast<std::uint32_t>( |
| 1883 | umul128_upper64(x: second_third_subsegments, UINT64_C(184467440737095517))); |
| 1884 | |
| 1885 | // Since the final result is of 2 digits, we can do the computation in 32-bits. |
| 1886 | const auto third_subsegment = |
| 1887 | static_cast<std::uint32_t>(second_third_subsegments) - second_subsegment * 100; |
| 1888 | |
| 1889 | BOOST_CHARCONV_ASSERT(second_subsegment < 100000000); |
| 1890 | BOOST_CHARCONV_ASSERT(third_subsegment < 100); |
| 1891 | |
| 1892 | { |
| 1893 | std::uint32_t initial_digits; |
| 1894 | if (first_subsegment != 0) |
| 1895 | { |
| 1896 | prod = ((second_subsegment * UINT64_C(281474977)) >> 16) + 1; |
| 1897 | remaining_digits_in_the_current_subsegment = 6; |
| 1898 | |
| 1899 | initial_digits = static_cast<std::uint32_t>(prod >> 32); |
| 1900 | remaining_digits -= 2; |
| 1901 | } |
| 1902 | else |
| 1903 | { |
| 1904 | // 7 or 8 digits (9 or 10 digits in total). |
| 1905 | if (second_subsegment >= 1000000) |
| 1906 | { |
| 1907 | prod = (second_subsegment * UINT64_C(281474978)) >> 16; |
| 1908 | remaining_digits_in_the_current_subsegment = 6; |
| 1909 | } |
| 1910 | // 5 or 6 digits (7 or 8 digits in total). |
| 1911 | else if (second_subsegment >= 10000) |
| 1912 | { |
| 1913 | prod = second_subsegment * UINT64_C(429497); |
| 1914 | remaining_digits_in_the_current_subsegment = 4; |
| 1915 | } |
| 1916 | // 3 or 4 digits (5 or 6 digits in total). |
| 1917 | else if (second_subsegment >= 100) |
| 1918 | { |
| 1919 | prod = second_subsegment * UINT64_C(42949673); |
| 1920 | remaining_digits_in_the_current_subsegment = 2; |
| 1921 | } |
| 1922 | // 1 or 2 digits (3 or 4 digits in total). |
| 1923 | else |
| 1924 | { |
| 1925 | prod = std::uint64_t(second_subsegment) << 32; |
| 1926 | remaining_digits_in_the_current_subsegment = 0; |
| 1927 | } |
| 1928 | |
| 1929 | initial_digits = static_cast<std::uint32_t>(prod >> 32); |
| 1930 | buffer -= (initial_digits < 10 ? 1 : 0); |
| 1931 | remaining_digits -= (2 - (initial_digits < 10 ? 1 : 0)); |
| 1932 | } |
| 1933 | |
| 1934 | print_2_digits(n: initial_digits, buffer); |
| 1935 | buffer += 2; |
| 1936 | |
| 1937 | if (remaining_digits > remaining_digits_in_the_current_subsegment) |
| 1938 | { |
| 1939 | remaining_digits -= remaining_digits_in_the_current_subsegment; |
| 1940 | for (; remaining_digits_in_the_current_subsegment > 0; remaining_digits_in_the_current_subsegment -= 2) |
| 1941 | { |
| 1942 | // Write next two digits. |
| 1943 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 1944 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 1945 | buffer += 2; |
| 1946 | } |
| 1947 | } |
| 1948 | else |
| 1949 | { |
| 1950 | for (int i = 0; i < (remaining_digits - 1) / 2; ++i) |
| 1951 | { |
| 1952 | // Write next two digits. |
| 1953 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 1954 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 1955 | buffer += 2; |
| 1956 | } |
| 1957 | |
| 1958 | // Distinguish two cases of rounding. |
| 1959 | if (remaining_digits_in_the_current_subsegment > remaining_digits) |
| 1960 | { |
| 1961 | if ((remaining_digits & 1) != 0) |
| 1962 | { |
| 1963 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 1964 | } |
| 1965 | else |
| 1966 | { |
| 1967 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 1968 | } |
| 1969 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 1970 | |
| 1971 | if (check_rounding_condition_inside_subsegment( |
| 1972 | current_digits, fractional_part: static_cast<std::uint32_t>(prod), |
| 1973 | remaining_digits_in_the_current_subsegment: remaining_digits_in_the_current_subsegment - remaining_digits, |
| 1974 | has_further_digits: third_subsegment != 0 || has_more_segments)) |
| 1975 | { |
| 1976 | goto round_up; |
| 1977 | } |
| 1978 | |
| 1979 | goto print_last_digits; |
| 1980 | } |
| 1981 | else |
| 1982 | { |
| 1983 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 1984 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 1985 | |
| 1986 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 1987 | current_digits, |
| 1988 | next_subsegment: uint_with_known_number_of_digits<2>{.value: third_subsegment}, |
| 1989 | has_further_digits: has_more_segments)) |
| 1990 | { |
| 1991 | goto round_up_two_digits; |
| 1992 | } |
| 1993 | |
| 1994 | goto print_last_two_digits; |
| 1995 | } |
| 1996 | } |
| 1997 | } |
| 1998 | |
| 1999 | // Print the third subsegment. |
| 2000 | { |
| 2001 | if (remaining_digits > 2) |
| 2002 | { |
| 2003 | print_2_digits(n: third_subsegment, buffer); |
| 2004 | buffer += 2; |
| 2005 | remaining_digits -= 2; |
| 2006 | |
| 2007 | // If there is no more segment, then fill remaining digits with 0's and return. |
| 2008 | if (!has_more_segments) |
| 2009 | { |
| 2010 | goto fill_remaining_digits_with_0s; |
| 2011 | } |
| 2012 | } |
| 2013 | else if (remaining_digits == 1) |
| 2014 | { |
| 2015 | prod = third_subsegment * UINT64_C(429496730); |
| 2016 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2017 | |
| 2018 | if (check_rounding_condition_inside_subsegment( |
| 2019 | current_digits, fractional_part: static_cast<std::uint32_t>(prod), remaining_digits_in_the_current_subsegment: 1, has_further_digits: has_more_segments)) |
| 2020 | { |
| 2021 | goto round_up_one_digit; |
| 2022 | } |
| 2023 | |
| 2024 | goto print_last_one_digit; |
| 2025 | } |
| 2026 | else |
| 2027 | { |
| 2028 | // remaining_digits == 2. |
| 2029 | // If there is no more segment, then print the current two digits and return. |
| 2030 | if (!has_more_segments) |
| 2031 | { |
| 2032 | print_2_digits(n: third_subsegment, buffer); |
| 2033 | buffer += 2; |
| 2034 | goto insert_decimal_dot; |
| 2035 | } |
| 2036 | |
| 2037 | // Otherwise, for performing the rounding, we have to wait until the next |
| 2038 | // segment becomes available. This state can be detected afterward by |
| 2039 | // inspecting if remaining_digits == 0. |
| 2040 | remaining_digits = 0; |
| 2041 | current_digits = third_subsegment; |
| 2042 | } |
| 2043 | } |
| 2044 | } |
| 2045 | |
| 2046 | ///////////////////////////////////////////////////////////////////////////////////////////////// |
| 2047 | /// Phase 2 - Print further digit segments computed with the extended cache table. |
| 2048 | ///////////////////////////////////////////////////////////////////////////////////////////////// |
| 2049 | |
| 2050 | { |
| 2051 | auto multiplier_index = |
| 2052 | static_cast<std::uint32_t>(k + ExtendedCache::segment_length - ExtendedCache::k_min) / |
| 2053 | static_cast<std::uint32_t>(ExtendedCache::segment_length); |
| 2054 | |
| 2055 | int digits_in_the_second_segment; |
| 2056 | { |
| 2057 | const auto new_k = |
| 2058 | ExtendedCache::k_min + static_cast<int>(multiplier_index) * ExtendedCache::segment_length; |
| 2059 | digits_in_the_second_segment = new_k - k; |
| 2060 | k = new_k; |
| 2061 | } |
| 2062 | |
| 2063 | const auto exp2_base = e + boost::core::countr_zero(x: significand); |
| 2064 | |
| 2065 | using cache_block_type = typename std::decay<decltype(ExtendedCache::cache[0])>::type; |
| 2066 | |
| 2067 | cache_block_type blocks[ExtendedCache::max_cache_blocks]; |
| 2068 | cache_block_count_t<ExtendedCache::constant_block_count, ExtendedCache::max_cache_blocks> cache_block_count; |
| 2069 | |
| 2070 | // Deal with the second segment. The second segment is special because it can have |
| 2071 | // overlapping digits with the first segment. Note that we cannot just move the buffer |
| 2072 | // pointer backward and print the whole segment from there, because it may contain |
| 2073 | // leading zeros. |
| 2074 | { |
| 2075 | cache_block_count = |
| 2076 | load_extended_cache<ExtendedCache, ExtendedCache::constant_block_count>( |
| 2077 | blocks, e, k, multiplier_index); |
| 2078 | |
| 2079 | // Compute nm mod 2^Q. |
| 2080 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(significand, blocks, cache_block_count); |
| 2081 | |
| 2082 | BOOST_CHARCONV_IF_CONSTEXPR (ExtendedCache::segment_length == 22) |
| 2083 | { |
| 2084 | // No rounding, continue. |
| 2085 | if (remaining_digits > digits_in_the_second_segment) |
| 2086 | { |
| 2087 | remaining_digits -= digits_in_the_second_segment; |
| 2088 | |
| 2089 | if (digits_in_the_second_segment <= 2) |
| 2090 | { |
| 2091 | BOOST_CHARCONV_ASSERT(digits_in_the_second_segment != 0); |
| 2092 | |
| 2093 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( |
| 2094 | power_of_10[19], blocks, cache_block_count); |
| 2095 | |
| 2096 | auto subsegment = |
| 2097 | fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 2098 | generate_and_discard_lower(power_of_10[3], blocks, |
| 2099 | cache_block_count); |
| 2100 | |
| 2101 | if (digits_in_the_second_segment == 1) |
| 2102 | { |
| 2103 | auto prod = subsegment * UINT64_C(429496730); |
| 2104 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2105 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2106 | ++buffer; |
| 2107 | } |
| 2108 | else |
| 2109 | { |
| 2110 | auto prod = subsegment * UINT64_C(42949673); |
| 2111 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2112 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2113 | buffer += 2; |
| 2114 | } |
| 2115 | } // digits_in_the_second_segment <= 2 |
| 2116 | else if (digits_in_the_second_segment <= 16) |
| 2117 | { |
| 2118 | BOOST_CHARCONV_ASSERT(22 - digits_in_the_second_segment <= 19); |
| 2119 | |
| 2120 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( |
| 2121 | compute_power(UINT64_C(10), exp: 22 - digits_in_the_second_segment), |
| 2122 | blocks, cache_block_count); |
| 2123 | |
| 2124 | // When there are at most 9 digits, we can store them in 32-bits. |
| 2125 | if (digits_in_the_second_segment <= 9) |
| 2126 | { |
| 2127 | // The number of overlapping digits is in the range 13 ~ 19. |
| 2128 | const auto subsegment = |
| 2129 | fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 2130 | generate_and_discard_lower(power_of_10[9], blocks, |
| 2131 | cache_block_count); |
| 2132 | |
| 2133 | std::uint64_t prod; |
| 2134 | if ((digits_in_the_second_segment & 1) != 0) |
| 2135 | { |
| 2136 | prod = ((subsegment * UINT64_C(720575941)) >> 24) + 1; |
| 2137 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2138 | ++buffer; |
| 2139 | } |
| 2140 | else |
| 2141 | { |
| 2142 | prod = ((subsegment * UINT64_C(450359963)) >> 20) + 1; |
| 2143 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2144 | buffer += 2; |
| 2145 | } |
| 2146 | |
| 2147 | for (; digits_in_the_second_segment > 2; digits_in_the_second_segment -= 2) |
| 2148 | { |
| 2149 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2150 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2151 | buffer += 2; |
| 2152 | } |
| 2153 | } // digits_in_the_second_segment <= 9 |
| 2154 | else |
| 2155 | { |
| 2156 | // The number of digits in the segment is in the range 10 ~ 16. |
| 2157 | const auto first_second_subsegments = |
| 2158 | fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 2159 | generate_and_discard_lower(power_of_10[16], blocks, |
| 2160 | cache_block_count); |
| 2161 | |
| 2162 | // The first segment is of 8 digits, and the second segment is of |
| 2163 | // 2 ~ 8 digits. |
| 2164 | // ceil(2^(64+14)/10^8) = 3022314549036573 |
| 2165 | // = floor(2^(64+14)*(10^8/(10^16 - 1))) |
| 2166 | const auto first_subsegment = |
| 2167 | static_cast<std::uint32_t>(umul128_upper64(first_second_subsegments, |
| 2168 | UINT64_C(3022314549036573)) >> |
| 2169 | 14); |
| 2170 | const auto second_subsegment = |
| 2171 | static_cast<std::uint32_t>(first_second_subsegments) - |
| 2172 | UINT32_C(100000000) * first_subsegment; |
| 2173 | |
| 2174 | // Print the first subsegment. |
| 2175 | print_8_digits(n: first_subsegment, buffer); |
| 2176 | buffer += 8; |
| 2177 | |
| 2178 | // Print the second subsegment. |
| 2179 | // There are at least 2 digits in the second subsegment. |
| 2180 | auto prod = ((second_subsegment * UINT64_C(140737489)) >> 15) + 1; |
| 2181 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2182 | buffer += 2; |
| 2183 | digits_in_the_second_segment -= 10; |
| 2184 | |
| 2185 | for (; digits_in_the_second_segment > 1; digits_in_the_second_segment -= 2) |
| 2186 | { |
| 2187 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2188 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2189 | buffer += 2; |
| 2190 | } |
| 2191 | |
| 2192 | if (digits_in_the_second_segment != 0) |
| 2193 | { |
| 2194 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2195 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2196 | ++buffer; |
| 2197 | } |
| 2198 | } |
| 2199 | } // digits_in_the_second_segment <= 16 |
| 2200 | else |
| 2201 | { |
| 2202 | // The number of digits in the segment is in the range 17 ~ 22. |
| 2203 | const auto first_subsegment = |
| 2204 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate( |
| 2205 | power_of_10[6], blocks, cache_block_count); |
| 2206 | |
| 2207 | const auto second_third_subsegments = |
| 2208 | fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 2209 | generate_and_discard_lower(power_of_10[16], blocks, |
| 2210 | cache_block_count); |
| 2211 | |
| 2212 | // ceil(2^(64+14)/10^8) = 3022314549036573 |
| 2213 | // = floor(2^(64+14)*(10^8/(10^16 - 1))) |
| 2214 | const auto second_subsegment = |
| 2215 | static_cast<std::uint32_t>(umul128_upper64(second_third_subsegments, |
| 2216 | UINT64_C(3022314549036573)) >> |
| 2217 | 14); |
| 2218 | const auto third_subsegment = static_cast<std::uint32_t>(second_third_subsegments) - |
| 2219 | UINT32_C(100000000) * second_subsegment; |
| 2220 | |
| 2221 | // Print the first subsegment (1 ~ 6 digits). |
| 2222 | std::uint64_t prod {}; |
| 2223 | auto remaining_digits_in_the_current_subsegment = |
| 2224 | digits_in_the_second_segment - 16; |
| 2225 | |
| 2226 | switch (remaining_digits_in_the_current_subsegment) |
| 2227 | { |
| 2228 | case 1: |
| 2229 | prod = first_subsegment * UINT64_C(429496730); |
| 2230 | goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining; |
| 2231 | |
| 2232 | case 2: |
| 2233 | prod = first_subsegment * UINT64_C(42949673); |
| 2234 | goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining; |
| 2235 | |
| 2236 | case 3: |
| 2237 | prod = first_subsegment * UINT64_C(4294968); |
| 2238 | goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining; |
| 2239 | |
| 2240 | case 4: |
| 2241 | prod = first_subsegment * UINT64_C(429497); |
| 2242 | goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining; |
| 2243 | |
| 2244 | case 5: |
| 2245 | prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1; |
| 2246 | goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining; |
| 2247 | |
| 2248 | case 6: |
| 2249 | prod = first_subsegment * UINT64_C(429497); |
| 2250 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2251 | buffer += 2; |
| 2252 | remaining_digits_in_the_current_subsegment = 4; |
| 2253 | goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining; |
| 2254 | |
| 2255 | default: |
| 2256 | BOOST_UNREACHABLE_RETURN(prod); // NOLINT |
| 2257 | } |
| 2258 | |
| 2259 | second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining |
| 2260 | : |
| 2261 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2262 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2263 | ++buffer; |
| 2264 | |
| 2265 | second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining |
| 2266 | : |
| 2267 | for (; remaining_digits_in_the_current_subsegment > 1; |
| 2268 | remaining_digits_in_the_current_subsegment -= 2) |
| 2269 | { |
| 2270 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2271 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2272 | buffer += 2; |
| 2273 | } |
| 2274 | |
| 2275 | // Print the second and third subsegments (8 digits each). |
| 2276 | print_8_digits(n: second_subsegment, buffer); |
| 2277 | print_8_digits(n: third_subsegment, buffer: buffer + 8); |
| 2278 | buffer += 16; |
| 2279 | } |
| 2280 | } // remaining_digits > digits_in_the_second_segment |
| 2281 | |
| 2282 | // Perform rounding and return. |
| 2283 | else |
| 2284 | { |
| 2285 | if (digits_in_the_second_segment <= 2) |
| 2286 | { |
| 2287 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( |
| 2288 | power_of_10[19], blocks, cache_block_count); |
| 2289 | |
| 2290 | // Get one more bit for potential rounding on the segment boundary. |
| 2291 | auto subsegment = |
| 2292 | fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 2293 | generate_and_discard_lower(2000, blocks, cache_block_count); |
| 2294 | |
| 2295 | bool segment_boundary_rounding_bit = ((subsegment & 1) != 0); |
| 2296 | subsegment >>= 1; |
| 2297 | |
| 2298 | if (digits_in_the_second_segment == 2) |
| 2299 | { |
| 2300 | // Convert subsegment into fixed-point fractional form where the |
| 2301 | // integer part is of one digit. The integer part is ignored. |
| 2302 | // 42949673 = ceil(2^32/10^2) |
| 2303 | auto prod = static_cast<std::uint64_t>(subsegment) * UINT64_C(42949673); |
| 2304 | |
| 2305 | if (remaining_digits == 1) |
| 2306 | { |
| 2307 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2308 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2309 | const bool has_further_digits_v = has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0); |
| 2310 | if (check_rounding_condition_inside_subsegment(current_digits, fractional_part: static_cast<std::uint32_t>(prod), remaining_digits_in_the_current_subsegment: 1, has_further_digits: has_further_digits_v)) |
| 2311 | { |
| 2312 | goto round_up_one_digit; |
| 2313 | } |
| 2314 | goto print_last_one_digit; |
| 2315 | } |
| 2316 | |
| 2317 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2318 | const auto next_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2319 | |
| 2320 | if (remaining_digits == 0) |
| 2321 | { |
| 2322 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 2323 | current_digits, |
| 2324 | uint_with_known_number_of_digits<2>{.value: next_digits}, |
| 2325 | has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) |
| 2326 | { |
| 2327 | goto round_up_two_digits; |
| 2328 | } |
| 2329 | goto print_last_two_digits; |
| 2330 | } |
| 2331 | |
| 2332 | current_digits = next_digits; |
| 2333 | BOOST_CHARCONV_ASSERT(remaining_digits == 2); |
| 2334 | } |
| 2335 | else |
| 2336 | { |
| 2337 | BOOST_CHARCONV_ASSERT(digits_in_the_second_segment == 1); |
| 2338 | // Convert subsegment into fixed-point fractional form where the |
| 2339 | // integer part is of two digits. The integer part is ignored. |
| 2340 | // 429496730 = ceil(2^32/10^1) |
| 2341 | auto prod = static_cast<std::uint64_t>(subsegment) * UINT64_C(429496730); |
| 2342 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2343 | const auto next_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2344 | |
| 2345 | if (remaining_digits == 0) |
| 2346 | { |
| 2347 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 2348 | current_digits, |
| 2349 | uint_with_known_number_of_digits<1>{.value: next_digits}, |
| 2350 | has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) |
| 2351 | { |
| 2352 | goto round_up_two_digits; |
| 2353 | } |
| 2354 | goto print_last_two_digits; |
| 2355 | } |
| 2356 | |
| 2357 | current_digits = next_digits; |
| 2358 | BOOST_CHARCONV_ASSERT(remaining_digits == 1); |
| 2359 | } |
| 2360 | |
| 2361 | if (check_rounding_condition_with_next_bit( |
| 2362 | current_digits, segment_boundary_rounding_bit, |
| 2363 | has_further_digits<0, 0, ExtendedCache>(significand, exp2_base, k, uconst0, uconst0))) |
| 2364 | { |
| 2365 | goto round_up; |
| 2366 | } |
| 2367 | |
| 2368 | goto print_last_digits; |
| 2369 | } // digits_in_the_second_segment <= 2 |
| 2370 | |
| 2371 | // When there are at most 9 digits in the segment. |
| 2372 | if (digits_in_the_second_segment <= 9) |
| 2373 | { |
| 2374 | // Throw away all overlapping digits. |
| 2375 | BOOST_CHARCONV_ASSERT(22 - digits_in_the_second_segment <= 19); |
| 2376 | |
| 2377 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( |
| 2378 | compute_power(UINT64_C(10), exp: 22 - digits_in_the_second_segment), |
| 2379 | blocks, cache_block_count); |
| 2380 | |
| 2381 | // Get one more bit for potential rounding on the segment boundary. |
| 2382 | auto segment = fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 2383 | generate_and_discard_lower(power_of_10[9] << 1, blocks, |
| 2384 | cache_block_count); |
| 2385 | |
| 2386 | std::uint64_t prod; |
| 2387 | digits_in_the_second_segment -= remaining_digits; |
| 2388 | |
| 2389 | if ((remaining_digits & 1) != 0) |
| 2390 | { |
| 2391 | prod = ((segment * UINT64_C(1441151881)) >> 26) + 1; |
| 2392 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2393 | |
| 2394 | if (remaining_digits == 1) |
| 2395 | { |
| 2396 | goto second_segment22_at_most_9_digits_rounding; |
| 2397 | } |
| 2398 | |
| 2399 | print_1_digit(n: current_digits, buffer); |
| 2400 | ++buffer; |
| 2401 | } |
| 2402 | else |
| 2403 | { |
| 2404 | prod = ((segment * UINT64_C(1801439851)) >> 23) + 1; |
| 2405 | const auto next_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2406 | |
| 2407 | if (remaining_digits == 0) |
| 2408 | { |
| 2409 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 2410 | current_digits, |
| 2411 | uint_with_known_number_of_digits<2>{.value: next_digits}, [&] { |
| 2412 | return static_cast<std::uint32_t>(prod) >= |
| 2413 | (additional_static_data_holder:: |
| 2414 | fractional_part_rounding_thresholds32[digits_in_the_second_segment - 1] & 0x7fffffff) |
| 2415 | || has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0); |
| 2416 | })) |
| 2417 | { |
| 2418 | goto round_up_two_digits; |
| 2419 | } |
| 2420 | goto print_last_two_digits; |
| 2421 | } |
| 2422 | else if (remaining_digits == 2) |
| 2423 | { |
| 2424 | current_digits = next_digits; |
| 2425 | goto second_segment22_at_most_9_digits_rounding; |
| 2426 | } |
| 2427 | |
| 2428 | print_2_digits(n: next_digits, buffer); |
| 2429 | buffer += 2; |
| 2430 | } |
| 2431 | |
| 2432 | BOOST_CHARCONV_ASSERT(remaining_digits >= 3); |
| 2433 | |
| 2434 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 2435 | { |
| 2436 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2437 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2438 | buffer += 2; |
| 2439 | } |
| 2440 | |
| 2441 | if (digits_in_the_second_segment != 0) |
| 2442 | { |
| 2443 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2444 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2445 | remaining_digits = 0; |
| 2446 | |
| 2447 | second_segment22_at_most_9_digits_rounding: |
| 2448 | if (check_rounding_condition_inside_subsegment( |
| 2449 | current_digits, static_cast<std::uint32_t>(prod), |
| 2450 | digits_in_the_second_segment, has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, |
| 2451 | uconst0))) |
| 2452 | { |
| 2453 | goto round_up; |
| 2454 | } |
| 2455 | |
| 2456 | goto print_last_digits; |
| 2457 | } |
| 2458 | else |
| 2459 | { |
| 2460 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(200); |
| 2461 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2462 | const auto segment_boundary_rounding_bit = (current_digits & 1) != 0; |
| 2463 | current_digits >>= 1; |
| 2464 | |
| 2465 | if (check_rounding_condition_with_next_bit( |
| 2466 | current_digits, segment_boundary_rounding_bit, |
| 2467 | has_further_digits<0, 1, ExtendedCache>(significand, exp2_base, k, uconst0, uconst1))) |
| 2468 | { |
| 2469 | goto round_up_two_digits; |
| 2470 | } |
| 2471 | goto print_last_two_digits; |
| 2472 | } |
| 2473 | } // digits_in_the_second_segment <= 9 |
| 2474 | |
| 2475 | // first_second_subsegments is of 1 ~ 13 digits, and third_subsegment is |
| 2476 | // of 9 digits. |
| 2477 | // Get one more bit for potential rounding condition check. |
| 2478 | auto first_second_subsegments = |
| 2479 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate( |
| 2480 | power_of_10[13] << 1, blocks, cache_block_count); |
| 2481 | |
| 2482 | bool first_bit_of_third_subsegment = ((first_second_subsegments & 1) != 0); |
| 2483 | first_second_subsegments >>= 1; |
| 2484 | |
| 2485 | // Compilers are not aware of how to leverage the maximum value of |
| 2486 | // first_second_subsegments to find out a better magic number which |
| 2487 | // allows us to eliminate an additional shift. |
| 2488 | // 1844674407371 = ceil(2^64/10^7) = floor(2^64*(10^6/(10^13 - 1))). |
| 2489 | const auto first_subsegment = |
| 2490 | static_cast<std::uint32_t>(boost::charconv::detail::umul128_upper64( |
| 2491 | x: first_second_subsegments, y: 1844674407371)); |
| 2492 | |
| 2493 | const auto second_subsegment = |
| 2494 | static_cast<std::uint32_t>(first_second_subsegments) - 10000000 * first_subsegment; |
| 2495 | |
| 2496 | int digits_in_the_second_subsegment; |
| 2497 | |
| 2498 | // Print the first subsegment (0 ~ 6 digits) if exists. |
| 2499 | if (digits_in_the_second_segment > 16) |
| 2500 | { |
| 2501 | std::uint64_t prod; |
| 2502 | int remaining_digits_in_the_current_subsegment = digits_in_the_second_segment - 16; |
| 2503 | |
| 2504 | // No rounding, continue. |
| 2505 | if (remaining_digits > remaining_digits_in_the_current_subsegment) |
| 2506 | { |
| 2507 | remaining_digits -= remaining_digits_in_the_current_subsegment; |
| 2508 | |
| 2509 | // There is no overlap in the second subsegment. |
| 2510 | digits_in_the_second_subsegment = 7; |
| 2511 | |
| 2512 | // When there is no overlapping digit. |
| 2513 | if (remaining_digits_in_the_current_subsegment == 6) |
| 2514 | { |
| 2515 | prod = (first_subsegment * UINT64_C(429497)) + 1; |
| 2516 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2517 | buffer += 2; |
| 2518 | remaining_digits_in_the_current_subsegment -= 2; |
| 2519 | } |
| 2520 | // If there are overlapping digits, move all overlapping digits |
| 2521 | // into the integer part. |
| 2522 | else |
| 2523 | { |
| 2524 | prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1; |
| 2525 | prod *= compute_power(UINT64_C(10), exp: 5 - remaining_digits_in_the_current_subsegment); |
| 2526 | |
| 2527 | if ((remaining_digits_in_the_current_subsegment & 1) != 0) |
| 2528 | { |
| 2529 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2530 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2531 | ++buffer; |
| 2532 | } |
| 2533 | } |
| 2534 | |
| 2535 | for (; remaining_digits_in_the_current_subsegment > 1; remaining_digits_in_the_current_subsegment -= 2) |
| 2536 | { |
| 2537 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2538 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2539 | buffer += 2; |
| 2540 | } |
| 2541 | } |
| 2542 | // The first subsegment is the last subsegment to print. |
| 2543 | else |
| 2544 | { |
| 2545 | if ((remaining_digits & 1) != 0) |
| 2546 | { |
| 2547 | prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1; |
| 2548 | |
| 2549 | // If there are overlapping digits, move all overlapping digits |
| 2550 | // into the integer part and then get the next digit. |
| 2551 | if (remaining_digits_in_the_current_subsegment < 6) |
| 2552 | { |
| 2553 | prod *= compute_power(UINT64_C(10), exp: 5 - remaining_digits_in_the_current_subsegment); |
| 2554 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2555 | } |
| 2556 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2557 | remaining_digits_in_the_current_subsegment -= remaining_digits; |
| 2558 | |
| 2559 | if (remaining_digits == 1) |
| 2560 | { |
| 2561 | goto second_segment22_more_than_9_digits_first_subsegment_rounding; |
| 2562 | } |
| 2563 | |
| 2564 | print_1_digit(n: current_digits, buffer); |
| 2565 | ++buffer; |
| 2566 | } |
| 2567 | else |
| 2568 | { |
| 2569 | // When there is no overlapping digit. |
| 2570 | if (remaining_digits_in_the_current_subsegment == 6) |
| 2571 | { |
| 2572 | if (remaining_digits == 0) |
| 2573 | { |
| 2574 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 2575 | current_digits, |
| 2576 | uint_with_known_number_of_digits<6>{ |
| 2577 | .value: first_subsegment}, |
| 2578 | has_further_digits<1, 16, ExtendedCache>(significand, exp2_base, k, uconst1, uconst16))) |
| 2579 | { |
| 2580 | goto round_up_two_digits; |
| 2581 | } |
| 2582 | goto print_last_two_digits; |
| 2583 | } |
| 2584 | |
| 2585 | prod = (first_subsegment * UINT64_C(429497)) + 1; |
| 2586 | } |
| 2587 | // Otherwise, convert the subsegment into a fixed-point |
| 2588 | // fraction form, move all overlapping digits into the |
| 2589 | // integer part, and then extract the next two digits. |
| 2590 | else |
| 2591 | { |
| 2592 | prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1; |
| 2593 | prod *= compute_power(UINT64_C(10), exp: 5 - remaining_digits_in_the_current_subsegment); |
| 2594 | |
| 2595 | if (remaining_digits == 0) |
| 2596 | { |
| 2597 | goto second_segment22_more_than_9_digits_first_subsegment_rounding_inside_subsegment; |
| 2598 | } |
| 2599 | |
| 2600 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2601 | } |
| 2602 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2603 | remaining_digits_in_the_current_subsegment -= remaining_digits; |
| 2604 | |
| 2605 | if (remaining_digits == 2) |
| 2606 | { |
| 2607 | goto second_segment22_more_than_9_digits_first_subsegment_rounding; |
| 2608 | } |
| 2609 | |
| 2610 | print_2_digits(n: current_digits, buffer); |
| 2611 | buffer += 2; |
| 2612 | } |
| 2613 | |
| 2614 | BOOST_CHARCONV_ASSERT(remaining_digits >= 3); |
| 2615 | |
| 2616 | if (remaining_digits > 4) |
| 2617 | { |
| 2618 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2619 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2620 | buffer += 2; |
| 2621 | } |
| 2622 | |
| 2623 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2624 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2625 | remaining_digits = 0; |
| 2626 | |
| 2627 | second_segment22_more_than_9_digits_first_subsegment_rounding: |
| 2628 | if (remaining_digits_in_the_current_subsegment == 0) |
| 2629 | { |
| 2630 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 2631 | current_digits, |
| 2632 | uint_with_known_number_of_digits<7>{.value: second_subsegment}, |
| 2633 | has_further_digits<1, 9, ExtendedCache>(significand, exp2_base, k, uconst1, uconst9))) |
| 2634 | { |
| 2635 | goto round_up; |
| 2636 | } |
| 2637 | } |
| 2638 | else |
| 2639 | { |
| 2640 | second_segment22_more_than_9_digits_first_subsegment_rounding_inside_subsegment |
| 2641 | : |
| 2642 | if (check_rounding_condition_inside_subsegment( |
| 2643 | current_digits, static_cast<std::uint32_t>(prod), |
| 2644 | remaining_digits_in_the_current_subsegment, |
| 2645 | has_further_digits<1, 16, ExtendedCache>(significand, exp2_base, k, uconst1, uconst16))) |
| 2646 | { |
| 2647 | goto round_up; |
| 2648 | } |
| 2649 | } |
| 2650 | goto print_last_digits; |
| 2651 | } |
| 2652 | } |
| 2653 | else |
| 2654 | { |
| 2655 | digits_in_the_second_subsegment = digits_in_the_second_segment - 9; |
| 2656 | } |
| 2657 | |
| 2658 | // Print the second subsegment (1 ~ 7 digits). |
| 2659 | { |
| 2660 | // No rounding, continue. |
| 2661 | if (remaining_digits > digits_in_the_second_subsegment) |
| 2662 | { |
| 2663 | auto prod = ((second_subsegment * UINT64_C(17592187)) >> 12) + 1; |
| 2664 | remaining_digits -= digits_in_the_second_subsegment; |
| 2665 | |
| 2666 | // When there is no overlapping digit. |
| 2667 | if (digits_in_the_second_subsegment == 7) |
| 2668 | { |
| 2669 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2670 | ++buffer; |
| 2671 | } |
| 2672 | // If there are overlapping digits, move all overlapping digits |
| 2673 | // into the integer part. |
| 2674 | else |
| 2675 | { |
| 2676 | prod *= compute_power(UINT64_C(10), |
| 2677 | exp: 6 - digits_in_the_second_subsegment); |
| 2678 | |
| 2679 | if ((digits_in_the_second_subsegment & 1) != 0) |
| 2680 | { |
| 2681 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2682 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2683 | ++buffer; |
| 2684 | } |
| 2685 | } |
| 2686 | |
| 2687 | for (; digits_in_the_second_subsegment > 1; digits_in_the_second_subsegment -= 2) |
| 2688 | { |
| 2689 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2690 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2691 | buffer += 2; |
| 2692 | } |
| 2693 | } |
| 2694 | // The second subsegment is the last subsegment to print. |
| 2695 | else |
| 2696 | { |
| 2697 | std::uint64_t prod; |
| 2698 | |
| 2699 | if ((remaining_digits & 1) != 0) |
| 2700 | { |
| 2701 | prod = ((second_subsegment * UINT64_C(17592187)) >> 12) + 1; |
| 2702 | |
| 2703 | // If there are overlapping digits, move all overlapping digits |
| 2704 | // into the integer part and then get the next digit. |
| 2705 | if (digits_in_the_second_subsegment < 7) |
| 2706 | { |
| 2707 | prod *= compute_power(UINT64_C(10), exp: 6 - digits_in_the_second_subsegment); |
| 2708 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2709 | } |
| 2710 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2711 | digits_in_the_second_subsegment -= remaining_digits; |
| 2712 | |
| 2713 | if (remaining_digits == 1) |
| 2714 | { |
| 2715 | goto second_segment22_more_than_9_digits_second_subsegment_rounding; |
| 2716 | } |
| 2717 | |
| 2718 | print_1_digit(n: current_digits, buffer); |
| 2719 | ++buffer; |
| 2720 | } |
| 2721 | else |
| 2722 | { |
| 2723 | // When there is no overlapping digit. |
| 2724 | if (digits_in_the_second_subsegment == 7) |
| 2725 | { |
| 2726 | if (remaining_digits == 0) |
| 2727 | { |
| 2728 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 2729 | current_digits, |
| 2730 | uint_with_known_number_of_digits<7>{ |
| 2731 | .value: second_subsegment}, |
| 2732 | has_further_digits<1, 9, ExtendedCache>(significand, exp2_base, k, uconst1, uconst9))) |
| 2733 | { |
| 2734 | goto round_up_two_digits; |
| 2735 | } |
| 2736 | goto print_last_two_digits; |
| 2737 | } |
| 2738 | |
| 2739 | prod = ((second_subsegment * UINT64_C(10995117)) >> 8) + 1; |
| 2740 | } |
| 2741 | // Otherwise, convert the subsegment into a fixed-point |
| 2742 | // fraction form, move all overlapping digits into the |
| 2743 | // integer part, and then extract the next two digits. |
| 2744 | else |
| 2745 | { |
| 2746 | prod = ((second_subsegment * UINT64_C(17592187)) >> 12) + 1; |
| 2747 | prod *= compute_power(UINT64_C(10), exp: 6 - digits_in_the_second_subsegment); |
| 2748 | |
| 2749 | if (remaining_digits == 0) |
| 2750 | { |
| 2751 | goto second_segment22_more_than_9_digits_second_subsegment_rounding_inside_subsegment; |
| 2752 | } |
| 2753 | |
| 2754 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2755 | } |
| 2756 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2757 | digits_in_the_second_subsegment -= remaining_digits; |
| 2758 | |
| 2759 | if (remaining_digits == 2) |
| 2760 | { |
| 2761 | goto second_segment22_more_than_9_digits_second_subsegment_rounding; |
| 2762 | } |
| 2763 | |
| 2764 | print_2_digits(n: current_digits, buffer); |
| 2765 | buffer += 2; |
| 2766 | } |
| 2767 | |
| 2768 | BOOST_CHARCONV_ASSERT(remaining_digits >= 3); |
| 2769 | |
| 2770 | if (remaining_digits > 4) |
| 2771 | { |
| 2772 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2773 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2774 | buffer += 2; |
| 2775 | } |
| 2776 | |
| 2777 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2778 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2779 | remaining_digits = 0; |
| 2780 | |
| 2781 | second_segment22_more_than_9_digits_second_subsegment_rounding: |
| 2782 | if (digits_in_the_second_subsegment == 0) |
| 2783 | { |
| 2784 | if (check_rounding_condition_with_next_bit( |
| 2785 | current_digits, first_bit_of_third_subsegment, |
| 2786 | has_further_digits<0, 9, ExtendedCache>(significand, exp2_base, k, uconst0, uconst9))) |
| 2787 | { |
| 2788 | goto round_up; |
| 2789 | } |
| 2790 | } |
| 2791 | else |
| 2792 | { |
| 2793 | second_segment22_more_than_9_digits_second_subsegment_rounding_inside_subsegment |
| 2794 | : |
| 2795 | if (check_rounding_condition_inside_subsegment( |
| 2796 | current_digits, static_cast<std::uint32_t>(prod), |
| 2797 | digits_in_the_second_subsegment, has_further_digits<1, 9, ExtendedCache>(significand, exp2_base, k, |
| 2798 | uconst1, uconst9))) |
| 2799 | { |
| 2800 | goto round_up; |
| 2801 | } |
| 2802 | } |
| 2803 | goto print_last_digits; |
| 2804 | } |
| 2805 | } |
| 2806 | |
| 2807 | // Print the third subsegment (9 digits). |
| 2808 | { |
| 2809 | // Get one more bit if we need to check rounding conditions on |
| 2810 | // the segment boundary. We already have shifted by 1-bit in the |
| 2811 | // computation of first & second subsegments, so here we don't |
| 2812 | // shift the multiplier. |
| 2813 | auto third_subsegment = |
| 2814 | fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 2815 | generate_and_discard_lower(power_of_10[9], blocks, |
| 2816 | cache_block_count); |
| 2817 | |
| 2818 | bool segment_boundary_rounding_bit = ((third_subsegment & 1) != 0); |
| 2819 | third_subsegment >>= 1; |
| 2820 | third_subsegment += (first_bit_of_third_subsegment ? 500000000 : 0); |
| 2821 | |
| 2822 | std::uint64_t prod; |
| 2823 | if ((remaining_digits & 1) != 0) |
| 2824 | { |
| 2825 | prod = ((third_subsegment * UINT64_C(720575941)) >> 24) + 1; |
| 2826 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2827 | |
| 2828 | if (remaining_digits == 1) |
| 2829 | { |
| 2830 | if (check_rounding_condition_inside_subsegment( |
| 2831 | current_digits, static_cast<std::uint32_t>(prod), 8, |
| 2832 | has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) |
| 2833 | { |
| 2834 | goto round_up_one_digit; |
| 2835 | } |
| 2836 | goto print_last_one_digit; |
| 2837 | } |
| 2838 | |
| 2839 | print_1_digit(n: current_digits, buffer); |
| 2840 | ++buffer; |
| 2841 | } |
| 2842 | else |
| 2843 | { |
| 2844 | prod = ((third_subsegment * UINT64_C(450359963)) >> 20) + 1; |
| 2845 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2846 | |
| 2847 | if (remaining_digits == 2) |
| 2848 | { |
| 2849 | goto second_segment22_more_than_9_digits_third_subsegment_rounding; |
| 2850 | } |
| 2851 | |
| 2852 | print_2_digits(n: current_digits, buffer); |
| 2853 | buffer += 2; |
| 2854 | } |
| 2855 | |
| 2856 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 2857 | { |
| 2858 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2859 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2860 | buffer += 2; |
| 2861 | } |
| 2862 | |
| 2863 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2864 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 2865 | |
| 2866 | if (remaining_digits < 9) |
| 2867 | { |
| 2868 | second_segment22_more_than_9_digits_third_subsegment_rounding: |
| 2869 | if (check_rounding_condition_inside_subsegment( |
| 2870 | current_digits, static_cast<std::uint32_t>(prod), 9 - remaining_digits, |
| 2871 | has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) |
| 2872 | { |
| 2873 | goto round_up_two_digits; |
| 2874 | } |
| 2875 | } |
| 2876 | else |
| 2877 | { |
| 2878 | if (check_rounding_condition_with_next_bit( |
| 2879 | current_digits, segment_boundary_rounding_bit, |
| 2880 | has_further_digits<0, 0, ExtendedCache>(significand, exp2_base, k, uconst0, uconst0))) |
| 2881 | { |
| 2882 | goto round_up_two_digits; |
| 2883 | } |
| 2884 | } |
| 2885 | goto print_last_two_digits; |
| 2886 | } |
| 2887 | } |
| 2888 | } // ExtendedCache::segment_length == 22 |
| 2889 | |
| 2890 | else BOOST_CHARCONV_IF_CONSTEXPR (ExtendedCache::segment_length == 252) |
| 2891 | { |
| 2892 | int overlapping_digits = 252 - digits_in_the_second_segment; |
| 2893 | int remaining_subsegment_pairs = 14; |
| 2894 | |
| 2895 | while (overlapping_digits >= 18) |
| 2896 | { |
| 2897 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( |
| 2898 | power_of_10[18], blocks, cache_block_count); |
| 2899 | --remaining_subsegment_pairs; |
| 2900 | overlapping_digits -= 18; |
| 2901 | } |
| 2902 | |
| 2903 | auto subsegment_pair = fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[18] << 1, blocks, cache_block_count); |
| 2904 | auto subsegment_boundary_rounding_bit = (subsegment_pair & 1) != 0; |
| 2905 | subsegment_pair >>= 1; |
| 2906 | |
| 2907 | // Deal with the first subsegment pair. |
| 2908 | { |
| 2909 | // Divide it into two 9-digits subsegments. |
| 2910 | const auto first_part = static_cast<std::uint32_t>(subsegment_pair / power_of_10[9]); |
| 2911 | const auto second_part = static_cast<std::uint32_t>(subsegment_pair - power_of_10[9] * first_part); |
| 2912 | |
| 2913 | auto print_subsegment = [&](std::uint32_t subsegment, int digits_in_the_subsegment) |
| 2914 | { |
| 2915 | remaining_digits -= digits_in_the_subsegment; |
| 2916 | |
| 2917 | // Move all overlapping digits into the integer part. |
| 2918 | auto prod = ((subsegment * UINT64_C(720575941)) >> 24) + 1; |
| 2919 | if (digits_in_the_subsegment < 9) |
| 2920 | { |
| 2921 | prod *= compute_power(UINT32_C(10), exp: 8 - digits_in_the_subsegment); |
| 2922 | |
| 2923 | if ((digits_in_the_subsegment & 1) != 0) |
| 2924 | { |
| 2925 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2926 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2927 | ++buffer; |
| 2928 | } |
| 2929 | } |
| 2930 | else |
| 2931 | { |
| 2932 | print_1_digit(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2933 | ++buffer; |
| 2934 | } |
| 2935 | |
| 2936 | for (; digits_in_the_subsegment > 1; digits_in_the_subsegment -= 2) |
| 2937 | { |
| 2938 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 2939 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 2940 | buffer += 2; |
| 2941 | } |
| 2942 | }; |
| 2943 | |
| 2944 | // When the first part is not completely overlapping with the first segment. |
| 2945 | int digits_in_the_second_part; |
| 2946 | if (overlapping_digits < 9) |
| 2947 | { |
| 2948 | int digits_in_the_first_part = 9 - overlapping_digits; |
| 2949 | |
| 2950 | // No rounding, continue. |
| 2951 | if (remaining_digits > digits_in_the_first_part) |
| 2952 | { |
| 2953 | digits_in_the_second_part = 9; |
| 2954 | print_subsegment(first_part, digits_in_the_first_part); |
| 2955 | } |
| 2956 | // Perform rounding and return. |
| 2957 | else |
| 2958 | { |
| 2959 | // When there is no overlapping digit. |
| 2960 | std::uint64_t prod; |
| 2961 | if (digits_in_the_first_part == 9) |
| 2962 | { |
| 2963 | if ((remaining_digits & 1) != 0) |
| 2964 | { |
| 2965 | prod = ((first_part * UINT64_C(720575941)) >> 24) + 1; |
| 2966 | } |
| 2967 | else |
| 2968 | { |
| 2969 | if (remaining_digits == 0) |
| 2970 | { |
| 2971 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 2972 | current_digits, |
| 2973 | uint_with_known_number_of_digits<9>{.value: first_part}, |
| 2974 | compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 2975 | { |
| 2976 | goto round_up_two_digits; |
| 2977 | } |
| 2978 | goto print_last_two_digits; |
| 2979 | } |
| 2980 | |
| 2981 | prod = ((first_part * UINT64_C(450359963)) >> 20) + 1; |
| 2982 | } |
| 2983 | } |
| 2984 | else |
| 2985 | { |
| 2986 | prod = ((first_part * UINT64_C(720575941)) >> 24) + 1; |
| 2987 | prod *= compute_power(UINT32_C(10), exp: 8 - digits_in_the_first_part); |
| 2988 | |
| 2989 | if ((remaining_digits & 1) != 0) |
| 2990 | { |
| 2991 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 2992 | } |
| 2993 | else |
| 2994 | { |
| 2995 | if (remaining_digits == 0) |
| 2996 | { |
| 2997 | goto second_segment252_first_subsegment_rounding_inside_subsegment; |
| 2998 | } |
| 2999 | |
| 3000 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3001 | } |
| 3002 | } |
| 3003 | digits_in_the_first_part -= remaining_digits; |
| 3004 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3005 | |
| 3006 | if (remaining_digits > 2) |
| 3007 | { |
| 3008 | if ((remaining_digits & 1) != 0) |
| 3009 | { |
| 3010 | print_1_digit(n: current_digits, buffer); |
| 3011 | ++buffer; |
| 3012 | } |
| 3013 | else |
| 3014 | { |
| 3015 | print_2_digits(n: current_digits, buffer); |
| 3016 | buffer += 2; |
| 3017 | } |
| 3018 | |
| 3019 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 3020 | { |
| 3021 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3022 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3023 | buffer += 2; |
| 3024 | } |
| 3025 | |
| 3026 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3027 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3028 | remaining_digits = 0; |
| 3029 | } |
| 3030 | |
| 3031 | if (digits_in_the_first_part != 0) |
| 3032 | { |
| 3033 | second_segment252_first_subsegment_rounding_inside_subsegment: |
| 3034 | if (check_rounding_condition_inside_subsegment( |
| 3035 | current_digits, static_cast<std::uint32_t>(prod), |
| 3036 | digits_in_the_first_part, compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3037 | { |
| 3038 | goto round_up; |
| 3039 | } |
| 3040 | } |
| 3041 | else |
| 3042 | { |
| 3043 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 3044 | current_digits, |
| 3045 | uint_with_known_number_of_digits<9>{.value: static_cast<std::uint32_t>(second_part)}, |
| 3046 | compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3047 | { |
| 3048 | goto round_up; |
| 3049 | } |
| 3050 | } |
| 3051 | goto print_last_digits; |
| 3052 | } |
| 3053 | } |
| 3054 | else |
| 3055 | { |
| 3056 | digits_in_the_second_part = 18 - overlapping_digits; |
| 3057 | } |
| 3058 | |
| 3059 | // Print the second part. |
| 3060 | // No rounding, continue. |
| 3061 | if (remaining_digits > digits_in_the_second_part) |
| 3062 | { |
| 3063 | print_subsegment(second_part, digits_in_the_second_part); |
| 3064 | } |
| 3065 | // Perform rounding and return. |
| 3066 | else |
| 3067 | { |
| 3068 | // When there is no overlapping digit. |
| 3069 | std::uint64_t prod; |
| 3070 | if (digits_in_the_second_part == 9) |
| 3071 | { |
| 3072 | if ((remaining_digits & 1) != 0) |
| 3073 | { |
| 3074 | prod = ((second_part * UINT64_C(720575941)) >> 24) + 1; |
| 3075 | } |
| 3076 | else |
| 3077 | { |
| 3078 | if (remaining_digits == 0) |
| 3079 | { |
| 3080 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 3081 | current_digits, |
| 3082 | uint_with_known_number_of_digits<9>{.value: static_cast<std::uint32_t>(second_part)}, |
| 3083 | compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3084 | { |
| 3085 | goto round_up_two_digits; |
| 3086 | } |
| 3087 | goto print_last_two_digits; |
| 3088 | } |
| 3089 | |
| 3090 | prod = ((second_part * UINT64_C(450359963)) >> 20) + 1; |
| 3091 | } |
| 3092 | } |
| 3093 | else |
| 3094 | { |
| 3095 | prod = ((second_part * UINT64_C(720575941)) >> 24) + 1; |
| 3096 | prod *= compute_power(UINT32_C(10), exp: 8 - digits_in_the_second_part); |
| 3097 | |
| 3098 | if ((remaining_digits & 1) != 0) |
| 3099 | { |
| 3100 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); |
| 3101 | } |
| 3102 | else |
| 3103 | { |
| 3104 | if (remaining_digits == 0) |
| 3105 | { |
| 3106 | goto second_segment252_second_subsegment_rounding_inside_subsegment; |
| 3107 | } |
| 3108 | |
| 3109 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3110 | } |
| 3111 | } |
| 3112 | digits_in_the_second_part -= remaining_digits; |
| 3113 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3114 | |
| 3115 | if (remaining_digits > 2) |
| 3116 | { |
| 3117 | if ((remaining_digits & 1) != 0) |
| 3118 | { |
| 3119 | print_1_digit(n: current_digits, buffer); |
| 3120 | ++buffer; |
| 3121 | } |
| 3122 | else |
| 3123 | { |
| 3124 | print_2_digits(n: current_digits, buffer); |
| 3125 | buffer += 2; |
| 3126 | } |
| 3127 | |
| 3128 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 3129 | { |
| 3130 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3131 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3132 | buffer += 2; |
| 3133 | } |
| 3134 | |
| 3135 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3136 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3137 | remaining_digits = 0; |
| 3138 | } |
| 3139 | |
| 3140 | if (digits_in_the_second_part != 0) |
| 3141 | { |
| 3142 | second_segment252_second_subsegment_rounding_inside_subsegment: |
| 3143 | if (check_rounding_condition_inside_subsegment( |
| 3144 | current_digits, static_cast<std::uint32_t>(prod), |
| 3145 | digits_in_the_second_part, compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3146 | { |
| 3147 | goto round_up; |
| 3148 | } |
| 3149 | } |
| 3150 | else |
| 3151 | { |
| 3152 | if (check_rounding_condition_with_next_bit( |
| 3153 | current_digits, subsegment_boundary_rounding_bit, |
| 3154 | compute_has_further_digits<0, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3155 | { |
| 3156 | goto round_up; |
| 3157 | } |
| 3158 | } |
| 3159 | goto print_last_digits; |
| 3160 | } |
| 3161 | } |
| 3162 | |
| 3163 | // Remaining subsegment pairs do not have overlapping digits. |
| 3164 | --remaining_subsegment_pairs; |
| 3165 | for (; remaining_subsegment_pairs > 0; --remaining_subsegment_pairs) |
| 3166 | { |
| 3167 | subsegment_pair = fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[18], blocks, cache_block_count); |
| 3168 | |
| 3169 | subsegment_pair += (subsegment_boundary_rounding_bit ? power_of_10[18] : 0); |
| 3170 | subsegment_boundary_rounding_bit = (subsegment_pair & 1) != 0; |
| 3171 | subsegment_pair >>= 1; |
| 3172 | |
| 3173 | const auto first_part = static_cast<std::uint32_t>(subsegment_pair / power_of_10[9]); |
| 3174 | const auto second_part = static_cast<std::uint32_t>(subsegment_pair - power_of_10[9] * first_part); |
| 3175 | |
| 3176 | // The first part can be printed without rounding. |
| 3177 | if (remaining_digits > 9) |
| 3178 | { |
| 3179 | print_9_digits(n: first_part, buffer); |
| 3180 | |
| 3181 | // The second part also can be printed without rounding. |
| 3182 | if (remaining_digits > 18) |
| 3183 | { |
| 3184 | print_9_digits(n: second_part, buffer: buffer + 9); |
| 3185 | } |
| 3186 | // Otherwise, perform rounding and return. |
| 3187 | else |
| 3188 | { |
| 3189 | buffer += 9; |
| 3190 | remaining_digits -= 9; |
| 3191 | |
| 3192 | std::uint64_t prod; |
| 3193 | int remaining_digits_in_the_current_subsegment = 9 - remaining_digits; |
| 3194 | |
| 3195 | if ((remaining_digits & 1) != 0) |
| 3196 | { |
| 3197 | prod = ((second_part * UINT64_C(720575941)) >> 24) + 1; |
| 3198 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3199 | |
| 3200 | if (remaining_digits == 1) |
| 3201 | { |
| 3202 | goto second_segment252_loop_second_subsegment_rounding; |
| 3203 | } |
| 3204 | |
| 3205 | print_1_digit(n: current_digits, buffer); |
| 3206 | ++buffer; |
| 3207 | } |
| 3208 | else |
| 3209 | { |
| 3210 | prod = ((second_part * UINT64_C(450359963)) >> 20) + 1; |
| 3211 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3212 | |
| 3213 | if (remaining_digits == 2) |
| 3214 | { |
| 3215 | goto second_segment252_loop_second_subsegment_rounding; |
| 3216 | } |
| 3217 | |
| 3218 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3219 | buffer += 2; |
| 3220 | } |
| 3221 | |
| 3222 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 3223 | { |
| 3224 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3225 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3226 | buffer += 2; |
| 3227 | } |
| 3228 | |
| 3229 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3230 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3231 | remaining_digits = 0; |
| 3232 | |
| 3233 | if (remaining_digits_in_the_current_subsegment != 0) |
| 3234 | { |
| 3235 | second_segment252_loop_second_subsegment_rounding: |
| 3236 | if (check_rounding_condition_inside_subsegment( |
| 3237 | current_digits, static_cast<std::uint32_t>(prod), |
| 3238 | remaining_digits_in_the_current_subsegment, |
| 3239 | compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3240 | { |
| 3241 | goto round_up; |
| 3242 | } |
| 3243 | goto print_last_digits; |
| 3244 | } |
| 3245 | else |
| 3246 | { |
| 3247 | if (check_rounding_condition_with_next_bit( |
| 3248 | current_digits, subsegment_boundary_rounding_bit, |
| 3249 | compute_has_further_digits<0, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3250 | { |
| 3251 | goto round_up_two_digits; |
| 3252 | } |
| 3253 | goto print_last_two_digits; |
| 3254 | } |
| 3255 | } |
| 3256 | } |
| 3257 | // Otherwise, perform rounding and return. |
| 3258 | else |
| 3259 | { |
| 3260 | std::uint64_t prod; |
| 3261 | int remaining_digits_in_the_current_subsegment = 9 - remaining_digits; |
| 3262 | if ((remaining_digits & 1) != 0) |
| 3263 | { |
| 3264 | prod = ((first_part * UINT64_C(720575941)) >> 24) + 1; |
| 3265 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3266 | |
| 3267 | if (remaining_digits == 1) |
| 3268 | { |
| 3269 | goto second_segment252_loop_first_subsegment_rounding; |
| 3270 | } |
| 3271 | |
| 3272 | print_1_digit(n: current_digits, buffer); |
| 3273 | ++buffer; |
| 3274 | } |
| 3275 | else |
| 3276 | { |
| 3277 | prod = ((first_part * UINT64_C(450359963)) >> 20) + 1; |
| 3278 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3279 | |
| 3280 | if (remaining_digits == 2) |
| 3281 | { |
| 3282 | goto second_segment252_loop_first_subsegment_rounding; |
| 3283 | } |
| 3284 | |
| 3285 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3286 | buffer += 2; |
| 3287 | } |
| 3288 | |
| 3289 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 3290 | { |
| 3291 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3292 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3293 | buffer += 2; |
| 3294 | } |
| 3295 | |
| 3296 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3297 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3298 | remaining_digits = 0; |
| 3299 | |
| 3300 | if (remaining_digits_in_the_current_subsegment != 0) |
| 3301 | { |
| 3302 | second_segment252_loop_first_subsegment_rounding: |
| 3303 | if (check_rounding_condition_inside_subsegment( |
| 3304 | current_digits, static_cast<std::uint32_t>(prod), |
| 3305 | remaining_digits_in_the_current_subsegment, |
| 3306 | compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3307 | { |
| 3308 | goto round_up; |
| 3309 | } |
| 3310 | goto print_last_digits; |
| 3311 | } |
| 3312 | else |
| 3313 | { |
| 3314 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 3315 | current_digits, |
| 3316 | uint_with_known_number_of_digits<9>{.value: static_cast<std::uint32_t>(second_part)}, |
| 3317 | compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3318 | { |
| 3319 | goto round_up_two_digits; |
| 3320 | } |
| 3321 | goto print_last_two_digits; |
| 3322 | } |
| 3323 | } |
| 3324 | |
| 3325 | buffer += 18; |
| 3326 | remaining_digits -= 18; |
| 3327 | } |
| 3328 | } // ExtendedCache::segment_length == 252 |
| 3329 | } |
| 3330 | |
| 3331 | // Print all remaining segments. |
| 3332 | while (has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0)) |
| 3333 | { |
| 3334 | // Get new segment. |
| 3335 | ++multiplier_index; |
| 3336 | k += ExtendedCache::segment_length; |
| 3337 | |
| 3338 | cache_block_count = load_extended_cache<ExtendedCache, ExtendedCache::constant_block_count>(blocks, e, k, multiplier_index); |
| 3339 | |
| 3340 | // Compute nm mod 2^Q. |
| 3341 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(significand, blocks, cache_block_count); |
| 3342 | |
| 3343 | BOOST_CHARCONV_IF_CONSTEXPR (ExtendedCache::segment_length == 22) |
| 3344 | { |
| 3345 | // When at least two subsegments left. |
| 3346 | if (remaining_digits > 16) |
| 3347 | { |
| 3348 | std::uint64_t first_second_subsegments = fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[16], blocks, cache_block_count); |
| 3349 | |
| 3350 | const auto first_subsegment = |
| 3351 | static_cast<std::uint32_t>(boost::charconv::detail::umul128_upper64(x: first_second_subsegments, UINT64_C(3022314549036573)) >> 14); |
| 3352 | |
| 3353 | const std::uint32_t second_subsegment = static_cast<std::uint32_t>(first_second_subsegments) - UINT32_C(100000000) * first_subsegment; |
| 3354 | |
| 3355 | print_8_digits(n: first_subsegment, buffer); |
| 3356 | print_8_digits(n: second_subsegment, buffer: buffer + 8); |
| 3357 | |
| 3358 | // When more segments left. |
| 3359 | if (remaining_digits > 22) |
| 3360 | { |
| 3361 | const auto third_subsegment = static_cast<std::uint32_t>( |
| 3362 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate_and_discard_lower(power_of_10[6], blocks,cache_block_count)); |
| 3363 | |
| 3364 | print_6_digits(n: third_subsegment, buffer: buffer + 16); |
| 3365 | buffer += 22; |
| 3366 | remaining_digits -= 22; |
| 3367 | } |
| 3368 | // When this is the last segment. |
| 3369 | else |
| 3370 | { |
| 3371 | buffer += 16; |
| 3372 | remaining_digits -= 16; |
| 3373 | |
| 3374 | auto third_subsegment = fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 3375 | generate_and_discard_lower(power_of_10[6] << 1, blocks, cache_block_count); |
| 3376 | |
| 3377 | bool segment_boundary_rounding_bit = ((third_subsegment & 1) != 0); |
| 3378 | third_subsegment >>= 1; |
| 3379 | |
| 3380 | std::uint64_t prod; |
| 3381 | if ((remaining_digits & 1) != 0) |
| 3382 | { |
| 3383 | prod = ((third_subsegment * UINT64_C(687195)) >> 4) + 1; |
| 3384 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3385 | |
| 3386 | if (remaining_digits == 1) |
| 3387 | { |
| 3388 | if (check_rounding_condition_inside_subsegment( |
| 3389 | current_digits, static_cast<std::uint32_t>(prod), 5, |
| 3390 | has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) |
| 3391 | { |
| 3392 | goto round_up_one_digit; |
| 3393 | } |
| 3394 | goto print_last_one_digit; |
| 3395 | } |
| 3396 | |
| 3397 | print_1_digit(n: current_digits, buffer); |
| 3398 | ++buffer; |
| 3399 | } |
| 3400 | else |
| 3401 | { |
| 3402 | prod = (third_subsegment * UINT64_C(429497)) + 1; |
| 3403 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3404 | |
| 3405 | if (remaining_digits == 2) |
| 3406 | { |
| 3407 | goto segment_loop22_more_than_16_digits_rounding; |
| 3408 | } |
| 3409 | |
| 3410 | print_2_digits(n: current_digits, buffer); |
| 3411 | buffer += 2; |
| 3412 | } |
| 3413 | |
| 3414 | if (remaining_digits > 4) |
| 3415 | { |
| 3416 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3417 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3418 | buffer += 2; |
| 3419 | |
| 3420 | if (remaining_digits == 6) |
| 3421 | { |
| 3422 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3423 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3424 | |
| 3425 | if (check_rounding_condition_with_next_bit( |
| 3426 | current_digits, segment_boundary_rounding_bit, |
| 3427 | has_further_digits<0, 0, ExtendedCache>(significand, exp2_base, k, uconst0, uconst0))) |
| 3428 | { |
| 3429 | goto round_up_two_digits; |
| 3430 | } |
| 3431 | goto print_last_two_digits; |
| 3432 | } |
| 3433 | } |
| 3434 | |
| 3435 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3436 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3437 | |
| 3438 | segment_loop22_more_than_16_digits_rounding: |
| 3439 | if (check_rounding_condition_inside_subsegment( |
| 3440 | current_digits, static_cast<std::uint32_t>(prod), 6 - remaining_digits, |
| 3441 | has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) |
| 3442 | { |
| 3443 | goto round_up_two_digits; |
| 3444 | } |
| 3445 | goto print_last_two_digits; |
| 3446 | } |
| 3447 | } |
| 3448 | // When two subsegments left. |
| 3449 | else if (remaining_digits > 8) |
| 3450 | { |
| 3451 | // Get one more bit for potential rounding conditions check. |
| 3452 | auto first_second_subsegments = |
| 3453 | fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 3454 | generate_and_discard_lower(power_of_10[16] << 1, blocks, cache_block_count); |
| 3455 | |
| 3456 | bool first_bit_of_third_subsegment = ((first_second_subsegments & 1) != 0); |
| 3457 | first_second_subsegments >>= 1; |
| 3458 | |
| 3459 | // 3022314549036573 = ceil(2^78/10^8) = floor(2^78*(10^8/(10^16 - |
| 3460 | // 1))). |
| 3461 | const auto first_subsegment = |
| 3462 | static_cast<std::uint32_t>(boost::charconv::detail::umul128_upper64(x: first_second_subsegments, UINT64_C(3022314549036573)) >> 14); |
| 3463 | |
| 3464 | const auto second_subsegment = static_cast<std::uint32_t>(first_second_subsegments) - UINT32_C(100000000) * first_subsegment; |
| 3465 | |
| 3466 | print_8_digits(n: first_subsegment, buffer); |
| 3467 | buffer += 8; |
| 3468 | remaining_digits -= 8; |
| 3469 | |
| 3470 | // Second subsegment (8 digits). |
| 3471 | std::uint64_t prod; |
| 3472 | if ((remaining_digits & 1) != 0) |
| 3473 | { |
| 3474 | prod = ((second_subsegment * UINT64_C(112589991)) >> 18) + 1; |
| 3475 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3476 | |
| 3477 | if (remaining_digits == 1) |
| 3478 | { |
| 3479 | if (check_rounding_condition_inside_subsegment( |
| 3480 | current_digits, static_cast<std::uint32_t>(prod), 7, has_further_digits<1, 6, ExtendedCache>(significand, exp2_base, k, |
| 3481 | uconst1, uconst6))) |
| 3482 | { |
| 3483 | goto round_up_one_digit; |
| 3484 | } |
| 3485 | goto print_last_one_digit; |
| 3486 | } |
| 3487 | |
| 3488 | print_1_digit(n: current_digits, buffer); |
| 3489 | ++buffer; |
| 3490 | } |
| 3491 | else |
| 3492 | { |
| 3493 | prod = ((second_subsegment * UINT64_C(140737489)) >> 15) + 1; |
| 3494 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3495 | |
| 3496 | if (remaining_digits == 2) |
| 3497 | { |
| 3498 | goto segment_loop22_more_than_8_digits_rounding; |
| 3499 | } |
| 3500 | |
| 3501 | print_2_digits(n: current_digits, buffer); |
| 3502 | buffer += 2; |
| 3503 | } |
| 3504 | |
| 3505 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 3506 | { |
| 3507 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3508 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3509 | buffer += 2; |
| 3510 | } |
| 3511 | |
| 3512 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3513 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3514 | |
| 3515 | if (remaining_digits < 8) |
| 3516 | { |
| 3517 | segment_loop22_more_than_8_digits_rounding: |
| 3518 | if (check_rounding_condition_inside_subsegment( |
| 3519 | current_digits, static_cast<std::uint32_t>(prod), 8 - remaining_digits, |
| 3520 | has_further_digits<1, 6, ExtendedCache>(significand, exp2_base, k, uconst1, uconst6))) |
| 3521 | { |
| 3522 | goto round_up_two_digits; |
| 3523 | } |
| 3524 | } |
| 3525 | else { |
| 3526 | if (check_rounding_condition_with_next_bit( |
| 3527 | current_digits, first_bit_of_third_subsegment, |
| 3528 | has_further_digits<0, 6, ExtendedCache>(significand, exp2_base, k, uconst0, uconst6))) |
| 3529 | { |
| 3530 | goto round_up_two_digits; |
| 3531 | } |
| 3532 | } |
| 3533 | goto print_last_two_digits; |
| 3534 | } |
| 3535 | // remaining_digits is at most 8. |
| 3536 | else |
| 3537 | { |
| 3538 | // Get one more bit for potential rounding conditions check. |
| 3539 | auto first_subsegment = |
| 3540 | fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 3541 | generate_and_discard_lower(power_of_10[8] << 1, blocks, cache_block_count); |
| 3542 | |
| 3543 | bool first_bit_of_second_subsegment = ((first_subsegment & 1) != 0); |
| 3544 | first_subsegment >>= 1; |
| 3545 | |
| 3546 | std::uint64_t prod; |
| 3547 | if ((remaining_digits & 1) != 0) |
| 3548 | { |
| 3549 | prod = ((first_subsegment * UINT64_C(112589991)) >> 18) + 1; |
| 3550 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3551 | |
| 3552 | if (remaining_digits == 1) |
| 3553 | { |
| 3554 | if (check_rounding_condition_inside_subsegment( |
| 3555 | current_digits, static_cast<std::uint32_t>(prod), 7, has_further_digits<1, 14, ExtendedCache>(significand, exp2_base, k, |
| 3556 | uconst1, uconst14))) |
| 3557 | { |
| 3558 | goto round_up_one_digit; |
| 3559 | } |
| 3560 | goto print_last_one_digit; |
| 3561 | } |
| 3562 | |
| 3563 | print_1_digit(n: current_digits, buffer); |
| 3564 | ++buffer; |
| 3565 | } |
| 3566 | else |
| 3567 | { |
| 3568 | prod = ((first_subsegment * UINT64_C(140737489)) >> 15) + 1; |
| 3569 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3570 | |
| 3571 | if (remaining_digits == 2) |
| 3572 | { |
| 3573 | goto segment_loop22_at_most_8_digits_rounding; |
| 3574 | } |
| 3575 | |
| 3576 | print_2_digits(n: current_digits, buffer); |
| 3577 | buffer += 2; |
| 3578 | } |
| 3579 | |
| 3580 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 3581 | { |
| 3582 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3583 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3584 | buffer += 2; |
| 3585 | } |
| 3586 | |
| 3587 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3588 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3589 | |
| 3590 | if (remaining_digits < 8) |
| 3591 | { |
| 3592 | segment_loop22_at_most_8_digits_rounding: |
| 3593 | if (check_rounding_condition_inside_subsegment( |
| 3594 | current_digits, static_cast<std::uint32_t>(prod), 8 - remaining_digits, |
| 3595 | has_further_digits<1, 14, ExtendedCache>(significand, exp2_base, k, uconst1, uconst14))) |
| 3596 | { |
| 3597 | goto round_up_two_digits; |
| 3598 | } |
| 3599 | } |
| 3600 | else |
| 3601 | { |
| 3602 | if (check_rounding_condition_with_next_bit( |
| 3603 | current_digits, first_bit_of_second_subsegment, |
| 3604 | has_further_digits<0, 14, ExtendedCache>(significand, exp2_base, k, uconst0, uconst14))) |
| 3605 | { |
| 3606 | goto round_up_two_digits; |
| 3607 | } |
| 3608 | } |
| 3609 | goto print_last_two_digits; |
| 3610 | } |
| 3611 | } // ExtendedCache::segment_length == 22 |
| 3612 | else if (ExtendedCache::segment_length == 252) |
| 3613 | { |
| 3614 | // Print as many 18-digits subsegment pairs as possible. |
| 3615 | for (int remaining_subsegment_pairs = 14; remaining_subsegment_pairs > 0; |
| 3616 | --remaining_subsegment_pairs) |
| 3617 | { |
| 3618 | // No rounding, continue. |
| 3619 | if (remaining_digits > 18) |
| 3620 | { |
| 3621 | const auto subsegment_pair = |
| 3622 | fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[18], blocks, cache_block_count); |
| 3623 | |
| 3624 | const auto first_part = static_cast<std::uint32_t>(subsegment_pair / power_of_10[9]); |
| 3625 | const auto second_part = static_cast<std::uint32_t>(subsegment_pair - power_of_10[9] * first_part); |
| 3626 | |
| 3627 | print_9_digits(n: first_part, buffer); |
| 3628 | print_9_digits(n: second_part, buffer: buffer + 9); |
| 3629 | buffer += 18; |
| 3630 | remaining_digits -= 18; |
| 3631 | } |
| 3632 | // Final subsegment pair. |
| 3633 | else |
| 3634 | { |
| 3635 | auto last_subsegment_pair = |
| 3636 | fixed_point_calculator<ExtendedCache::max_cache_blocks>:: |
| 3637 | generate_and_discard_lower(power_of_10[18] << 1, blocks, cache_block_count); |
| 3638 | |
| 3639 | const bool subsegment_boundary_rounding_bit = ((last_subsegment_pair & 1) != 0); |
| 3640 | last_subsegment_pair >>= 1; |
| 3641 | |
| 3642 | const auto first_part = static_cast<std::uint32_t>(last_subsegment_pair / power_of_10[9]); |
| 3643 | const auto second_part = static_cast<std::uint32_t>(last_subsegment_pair) - power_of_10[9] * first_part; |
| 3644 | |
| 3645 | if (remaining_digits <= 9) |
| 3646 | { |
| 3647 | std::uint64_t prod; |
| 3648 | |
| 3649 | if ((remaining_digits & 1) != 0) |
| 3650 | { |
| 3651 | prod = ((first_part * UINT64_C(1441151881)) >> 25) + 1; |
| 3652 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3653 | |
| 3654 | if (remaining_digits == 1) |
| 3655 | { |
| 3656 | if (check_rounding_condition_inside_subsegment( |
| 3657 | current_digits, static_cast<std::uint32_t>(prod), 8, |
| 3658 | compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3659 | { |
| 3660 | goto round_up_one_digit; |
| 3661 | } |
| 3662 | goto print_last_one_digit; |
| 3663 | } |
| 3664 | |
| 3665 | print_1_digit(n: current_digits, buffer); |
| 3666 | ++buffer; |
| 3667 | } |
| 3668 | else |
| 3669 | { |
| 3670 | prod = ((first_part * UINT64_C(450359963)) >> 20) + 1; |
| 3671 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3672 | |
| 3673 | if (remaining_digits == 2) |
| 3674 | { |
| 3675 | goto segment_loop252_final18_first_part_rounding; |
| 3676 | } |
| 3677 | |
| 3678 | print_2_digits(n: current_digits, buffer); |
| 3679 | buffer += 2; |
| 3680 | } |
| 3681 | |
| 3682 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 3683 | { |
| 3684 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3685 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3686 | buffer += 2; |
| 3687 | } |
| 3688 | |
| 3689 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3690 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3691 | |
| 3692 | if (remaining_digits < 9) |
| 3693 | { |
| 3694 | segment_loop252_final18_first_part_rounding: |
| 3695 | if (check_rounding_condition_inside_subsegment( |
| 3696 | current_digits, static_cast<std::uint32_t>(prod), |
| 3697 | 9 - remaining_digits, compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3698 | { |
| 3699 | goto round_up_two_digits; |
| 3700 | } |
| 3701 | } |
| 3702 | else |
| 3703 | { |
| 3704 | if (check_rounding_condition_subsegment_boundary_with_next_subsegment( |
| 3705 | current_digits, |
| 3706 | uint_with_known_number_of_digits<9>{.value: static_cast<std::uint32_t>(second_part)}, |
| 3707 | compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3708 | { |
| 3709 | goto round_up_two_digits; |
| 3710 | } |
| 3711 | } |
| 3712 | goto print_last_two_digits; |
| 3713 | } // remaining_digits <= 9 |
| 3714 | |
| 3715 | print_9_digits(n: first_part, buffer); |
| 3716 | buffer += 9; |
| 3717 | remaining_digits -= 9; |
| 3718 | |
| 3719 | std::uint64_t prod; |
| 3720 | |
| 3721 | if ((remaining_digits & 1) != 0) |
| 3722 | { |
| 3723 | prod = ((second_part * UINT64_C(1441151881)) >> 25) + 1; |
| 3724 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3725 | |
| 3726 | if (remaining_digits == 1) |
| 3727 | { |
| 3728 | if (check_rounding_condition_inside_subsegment( |
| 3729 | current_digits, static_cast<std::uint32_t>(prod), 8, |
| 3730 | compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3731 | { |
| 3732 | goto round_up_one_digit; |
| 3733 | } |
| 3734 | goto print_last_one_digit; |
| 3735 | } |
| 3736 | |
| 3737 | print_1_digit(n: current_digits, buffer); |
| 3738 | ++buffer; |
| 3739 | } |
| 3740 | else |
| 3741 | { |
| 3742 | prod = ((second_part * UINT64_C(450359963)) >> 20) + 1; |
| 3743 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3744 | |
| 3745 | if (remaining_digits == 2) |
| 3746 | { |
| 3747 | goto segment_loop252_final18_second_part_rounding; |
| 3748 | } |
| 3749 | |
| 3750 | print_2_digits(n: current_digits, buffer); |
| 3751 | buffer += 2; |
| 3752 | } |
| 3753 | |
| 3754 | for (int i = 0; i < (remaining_digits - 3) / 2; ++i) |
| 3755 | { |
| 3756 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3757 | print_2_digits(n: static_cast<std::uint32_t>(prod >> 32), buffer); |
| 3758 | buffer += 2; |
| 3759 | } |
| 3760 | |
| 3761 | prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); |
| 3762 | current_digits = static_cast<std::uint32_t>(prod >> 32); |
| 3763 | |
| 3764 | if (remaining_digits < 9) |
| 3765 | { |
| 3766 | segment_loop252_final18_second_part_rounding: |
| 3767 | if (check_rounding_condition_inside_subsegment( |
| 3768 | current_digits, static_cast<std::uint32_t>(prod), 9 - remaining_digits, |
| 3769 | compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3770 | { |
| 3771 | goto round_up_two_digits; |
| 3772 | } |
| 3773 | } |
| 3774 | else |
| 3775 | { |
| 3776 | if (check_rounding_condition_with_next_bit( |
| 3777 | current_digits, subsegment_boundary_rounding_bit, |
| 3778 | compute_has_further_digits<0, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) |
| 3779 | { |
| 3780 | goto round_up_two_digits; |
| 3781 | } |
| 3782 | } |
| 3783 | goto print_last_two_digits; |
| 3784 | } |
| 3785 | } |
| 3786 | } // if (ExtendedCache::segment_length == 252) |
| 3787 | } |
| 3788 | } |
| 3789 | |
| 3790 | |
| 3791 | ///////////////////////////////////////////////////////////////////////////////////////////////// |
| 3792 | /// Phase 3 - Fill remaining digits with 0's, insert decimal dot, print exponent, and |
| 3793 | /// return. |
| 3794 | ///////////////////////////////////////////////////////////////////////////////////////////////// |
| 3795 | |
| 3796 | fill_remaining_digits_with_0s: |
| 3797 | // This is probably not needed for the general format, but currently I am not 100% sure. |
| 3798 | // (When fixed format is eventually choosed, we do not remove trailing zeros in the integer part. |
| 3799 | // I am not sure if those trailing zeros are guaranteed to be already printed or not.) |
| 3800 | std::memset(s: buffer, c: '0', n: static_cast<std::size_t>(remaining_digits)); |
| 3801 | buffer += remaining_digits; |
| 3802 | |
| 3803 | insert_decimal_dot: |
| 3804 | if (fmt == chars_format::general) |
| 3805 | { |
| 3806 | // Decide between fixed vs scientific. |
| 3807 | if (-4 <= decimal_exponent_normalized && decimal_exponent_normalized < precision) |
| 3808 | { |
| 3809 | // Fixed. |
| 3810 | if (decimal_exponent_normalized >= 0) |
| 3811 | { |
| 3812 | // Insert decimal dot. |
| 3813 | decimal_dot_pos = buffer_starting_pos + decimal_exponent_normalized + 1; |
| 3814 | std::memmove(dest: buffer_starting_pos, src: buffer_starting_pos + 1, |
| 3815 | n: static_cast<std::size_t>(decimal_dot_pos - buffer_starting_pos)); |
| 3816 | *decimal_dot_pos = '.'; |
| 3817 | } |
| 3818 | else |
| 3819 | { |
| 3820 | // Print leading zeros and insert decimal dot. |
| 3821 | int number_of_leading_zeros = -decimal_exponent_normalized - 1; |
| 3822 | std::memmove(dest: buffer_starting_pos + number_of_leading_zeros + 2, src: buffer_starting_pos + 1, |
| 3823 | n: static_cast<std::size_t>(buffer - buffer_starting_pos - 1)); |
| 3824 | std::memcpy(dest: buffer_starting_pos, src: "0." , n: 2); |
| 3825 | std::memset(s: buffer_starting_pos + 2, c: '0', n: static_cast<std::size_t>(number_of_leading_zeros)); |
| 3826 | buffer += number_of_leading_zeros + 1; |
| 3827 | } |
| 3828 | // Don't print exponent. |
| 3829 | fmt = chars_format::fixed; |
| 3830 | } |
| 3831 | else |
| 3832 | { |
| 3833 | // Scientific. |
| 3834 | // Insert decimal dot. |
| 3835 | *buffer_starting_pos = *(buffer_starting_pos + 1); |
| 3836 | *(buffer_starting_pos + 1) = '.'; |
| 3837 | } |
| 3838 | |
| 3839 | // Remove trailing zeros. |
| 3840 | while (true) |
| 3841 | { |
| 3842 | auto prev = buffer - 1; |
| 3843 | |
| 3844 | // Remove decimal dot as well if there is no fractional digits. |
| 3845 | if (*prev == '.') |
| 3846 | { |
| 3847 | buffer = prev; |
| 3848 | break; |
| 3849 | } |
| 3850 | else if (*prev != '0') |
| 3851 | { |
| 3852 | break; |
| 3853 | } |
| 3854 | buffer = prev; |
| 3855 | } |
| 3856 | } |
| 3857 | else if (decimal_dot_pos != buffer_starting_pos) |
| 3858 | { |
| 3859 | std::memmove(dest: buffer_starting_pos, src: buffer_starting_pos + 1, |
| 3860 | n: static_cast<std::size_t>(decimal_dot_pos - buffer_starting_pos)); |
| 3861 | *decimal_dot_pos = '.'; |
| 3862 | } |
| 3863 | |
| 3864 | if (fmt != chars_format::fixed) |
| 3865 | { |
| 3866 | if (decimal_exponent_normalized >= 0) |
| 3867 | { |
| 3868 | std::memcpy(dest: buffer, src: "e+" , n: 2); // NOLINT : Specifically not null-terminating |
| 3869 | } |
| 3870 | else |
| 3871 | { |
| 3872 | std::memcpy(dest: buffer, src: "e-" , n: 2); // NOLINT : Specifically not null-terminating |
| 3873 | decimal_exponent_normalized = -decimal_exponent_normalized; |
| 3874 | } |
| 3875 | |
| 3876 | buffer += 2; |
| 3877 | if (decimal_exponent_normalized >= 100) |
| 3878 | { |
| 3879 | // d1 = decimal_exponent / 10; d2 = decimal_exponent % 10; |
| 3880 | // 6554 = ceil(2^16 / 10) |
| 3881 | auto prod = static_cast<std::uint32_t>(decimal_exponent_normalized) * UINT32_C(6554); |
| 3882 | auto d1 = prod >> 16; |
| 3883 | prod = static_cast<std::uint16_t>(prod) * UINT16_C(5); // * 10 |
| 3884 | auto d2 = prod >> 15; // >> 16 |
| 3885 | print_2_digits(n: d1, buffer); |
| 3886 | print_1_digit(n: d2, buffer: buffer + 2); |
| 3887 | buffer += 3; |
| 3888 | } |
| 3889 | else |
| 3890 | { |
| 3891 | print_2_digits(n: static_cast<std::uint32_t>(decimal_exponent_normalized), buffer); |
| 3892 | buffer += 2; |
| 3893 | } |
| 3894 | } |
| 3895 | |
| 3896 | return {.ptr: buffer, .ec: std::errc()}; |
| 3897 | |
| 3898 | round_up: |
| 3899 | if ((remaining_digits & 1) != 0) |
| 3900 | { |
| 3901 | round_up_one_digit: |
| 3902 | if (++current_digits == 10) |
| 3903 | { |
| 3904 | goto round_up_all_9s; |
| 3905 | } |
| 3906 | |
| 3907 | goto print_last_one_digit; |
| 3908 | } |
| 3909 | else |
| 3910 | { |
| 3911 | round_up_two_digits: |
| 3912 | if (++current_digits == 100) |
| 3913 | { |
| 3914 | goto round_up_all_9s; |
| 3915 | } |
| 3916 | |
| 3917 | goto print_last_two_digits; |
| 3918 | } |
| 3919 | |
| 3920 | print_last_digits: |
| 3921 | if ((remaining_digits & 1) != 0) |
| 3922 | { |
| 3923 | print_last_one_digit: |
| 3924 | print_1_digit(n: current_digits, buffer); |
| 3925 | ++buffer; |
| 3926 | } |
| 3927 | else |
| 3928 | { |
| 3929 | print_last_two_digits: |
| 3930 | print_2_digits(n: current_digits, buffer); |
| 3931 | buffer += 2; |
| 3932 | } |
| 3933 | |
| 3934 | goto insert_decimal_dot; |
| 3935 | |
| 3936 | round_up_all_9s: |
| 3937 | char* first_9_pos = buffer; |
| 3938 | buffer += (2 - (remaining_digits & 1)); |
| 3939 | |
| 3940 | // Find the starting position of printed digits. |
| 3941 | char* digit_starting_pos = [&] { |
| 3942 | // For negative exponent & fixed format, we already printed leading zeros. |
| 3943 | if (fmt == chars_format::fixed && decimal_exponent_normalized < 0) |
| 3944 | { |
| 3945 | return buffer_starting_pos - decimal_exponent_normalized + 1; |
| 3946 | } |
| 3947 | // We reserved one slot for decimal dot, so the starting position of printed digits |
| 3948 | // is buffer_starting_pos + 1 if we need to print decimal dot. |
| 3949 | return buffer_starting_pos == decimal_dot_pos ? buffer_starting_pos |
| 3950 | : buffer_starting_pos + 1; |
| 3951 | }(); |
| 3952 | // Find all preceding 9's. |
| 3953 | if ((first_9_pos - digit_starting_pos) % 2 != 0) |
| 3954 | { |
| 3955 | if (*(first_9_pos - 1) != '9') |
| 3956 | { |
| 3957 | ++*(first_9_pos - 1); |
| 3958 | if ((remaining_digits & 1) != 0) |
| 3959 | { |
| 3960 | *first_9_pos = '0'; |
| 3961 | } |
| 3962 | else |
| 3963 | { |
| 3964 | std::memcpy(dest: first_9_pos, src: "00" , n: 2); |
| 3965 | } |
| 3966 | goto insert_decimal_dot; |
| 3967 | } |
| 3968 | --first_9_pos; |
| 3969 | } |
| 3970 | while (first_9_pos != digit_starting_pos) |
| 3971 | { |
| 3972 | if (std::memcmp(s1: first_9_pos - 2, s2: "99" , n: 2) != 0) |
| 3973 | { |
| 3974 | if (*(first_9_pos - 1) != '9') |
| 3975 | { |
| 3976 | ++*(first_9_pos - 1); |
| 3977 | } |
| 3978 | else |
| 3979 | { |
| 3980 | ++*(first_9_pos - 2); |
| 3981 | *(first_9_pos - 1) = '0'; |
| 3982 | } |
| 3983 | std::memset(s: first_9_pos, c: '0', n: static_cast<std::size_t>(buffer - first_9_pos)); |
| 3984 | goto insert_decimal_dot; |
| 3985 | } |
| 3986 | first_9_pos -= 2; |
| 3987 | } |
| 3988 | |
| 3989 | // Every digit we wrote so far are all 9's. In this case, we have to shift the whole thing by 1. |
| 3990 | ++decimal_exponent_normalized; |
| 3991 | |
| 3992 | if (fmt == chars_format::fixed) |
| 3993 | { |
| 3994 | if (decimal_exponent_normalized > 0) |
| 3995 | { |
| 3996 | // We need to print one more character. |
| 3997 | if (buffer == last) |
| 3998 | { |
| 3999 | return {.ptr: last, .ec: std::errc::value_too_large}; |
| 4000 | } |
| 4001 | ++buffer; |
| 4002 | // If we were to print the decimal dot, we have to shift it to right |
| 4003 | // since we now have one more digit in the integer part. |
| 4004 | if (buffer_starting_pos != decimal_dot_pos) |
| 4005 | { |
| 4006 | ++decimal_dot_pos; |
| 4007 | } |
| 4008 | } |
| 4009 | else if (decimal_exponent_normalized == 0) |
| 4010 | { |
| 4011 | // For the case 0.99...9 -> 1.00...0, the rounded digit is one before the first digit written. |
| 4012 | // Note: decimal_exponent_normalized was negative before the increment (++decimal_exponent_normalized), |
| 4013 | // so we already have printed "00" onto the buffer. |
| 4014 | // Hence, --digit_starting_pos doesn't go more than the starting position of the buffer. |
| 4015 | --digit_starting_pos; |
| 4016 | } |
| 4017 | } |
| 4018 | |
| 4019 | // Nolint is applied to the following two calls since we know they are not supposed to be null terminated |
| 4020 | *digit_starting_pos = '1'; |
| 4021 | std::memset(s: digit_starting_pos + 1, c: '0', n: static_cast<std::size_t>(buffer - digit_starting_pos - 1)); // NOLINT |
| 4022 | |
| 4023 | goto insert_decimal_dot; |
| 4024 | } |
| 4025 | |
| 4026 | }}} // Namespaces |
| 4027 | |
| 4028 | #ifdef BOOST_MSVC |
| 4029 | # pragma warning(pop) |
| 4030 | #endif |
| 4031 | |
| 4032 | #endif // BOOST_CHARCONV_DETAIL_FLOFF |
| 4033 | |