File indexing completed on 2025-04-19 08:19:39
0001
0002
0003
0004
0005
0006 #ifndef BOOST_CHARCONV_DETAIL_RYU_RYU_GENERIC_128_HPP
0007 #define BOOST_CHARCONV_DETAIL_RYU_RYU_GENERIC_128_HPP
0008
0009 #include <boost/charconv/detail/ryu/generic_128.hpp>
0010 #include <boost/charconv/detail/integer_search_trees.hpp>
0011 #include <boost/charconv/detail/config.hpp>
0012 #include <boost/charconv/detail/bit_layouts.hpp>
0013 #include <boost/charconv/to_chars.hpp>
0014 #include <cinttypes>
0015 #include <cstdio>
0016 #include <cstdint>
0017
0018 #ifdef BOOST_CHARCONV_DEBUG
0019 # include <iostream>
0020 #endif
0021
0022 namespace boost { namespace charconv { namespace detail { namespace ryu {
0023
0024 static constexpr int32_t fd128_exceptional_exponent = 0x7FFFFFFF;
0025 static constexpr unsigned_128_type one = 1;
0026
0027 struct floating_decimal_128
0028 {
0029 unsigned_128_type mantissa;
0030 int32_t exponent;
0031 bool sign;
0032 };
0033
0034 #ifdef BOOST_CHARCONV_DEBUG
0035 static char* s(unsigned_128_type v) {
0036 int len = num_digits(v);
0037 char* b = static_cast<char*>(malloc((len + 1) * sizeof(char)));
0038 for (int i = 0; i < len; i++) {
0039 const uint32_t c = static_cast<uint32_t>(v % 10);
0040 v /= 10;
0041 b[len - 1 - i] = static_cast<char>('0' + c);
0042 }
0043 b[len] = 0;
0044 return b;
0045 }
0046 #endif
0047
0048 static inline struct floating_decimal_128 generic_binary_to_decimal(
0049 const unsigned_128_type bits,
0050 const uint32_t mantissaBits, const uint32_t exponentBits, const bool explicitLeadingBit) noexcept
0051 {
0052 #ifdef BOOST_CHARCONV_DEBUG
0053 printf("IN=");
0054 for (int32_t bit = 127; bit >= 0; --bit)
0055 {
0056 printf("%u", static_cast<uint32_t>((bits >> bit) & 1));
0057 }
0058 printf("\n");
0059 #endif
0060
0061 const uint32_t bias = (1u << (exponentBits - 1)) - 1;
0062 const bool ieeeSign = ((bits >> (mantissaBits + exponentBits)) & 1) != 0;
0063 const unsigned_128_type ieeeMantissa = bits & ((one << mantissaBits) - 1);
0064 const uint32_t ieeeExponent = static_cast<uint32_t>((bits >> mantissaBits) & ((one << exponentBits) - 1u));
0065
0066 if (ieeeExponent == 0 && ieeeMantissa == 0)
0067 {
0068 struct floating_decimal_128 fd {0, 0, ieeeSign};
0069 return fd;
0070 }
0071 if (ieeeExponent == ((1u << exponentBits) - 1u))
0072 {
0073 struct floating_decimal_128 fd;
0074 fd.mantissa = explicitLeadingBit ? ieeeMantissa & ((one << (mantissaBits - 1)) - 1) : ieeeMantissa;
0075 fd.exponent = fd128_exceptional_exponent;
0076 fd.sign = ieeeSign;
0077 return fd;
0078 }
0079
0080 int32_t e2;
0081 unsigned_128_type m2;
0082
0083 if (explicitLeadingBit)
0084 {
0085
0086 if (ieeeExponent == 0)
0087 {
0088 e2 = static_cast<int32_t>(1 - bias - mantissaBits + 1 - 2);
0089 }
0090 else
0091 {
0092 e2 = static_cast<int32_t>(ieeeExponent - bias - mantissaBits + 1 - 2);
0093 }
0094 m2 = ieeeMantissa;
0095 }
0096 else
0097 {
0098 if (ieeeExponent == 0)
0099 {
0100 e2 = static_cast<int32_t>(1 - bias - mantissaBits - 2);
0101 m2 = ieeeMantissa;
0102 } else
0103 {
0104 e2 = static_cast<int32_t>(ieeeExponent - bias - mantissaBits - 2U);
0105 m2 = (one << mantissaBits) | ieeeMantissa;
0106 }
0107 }
0108 const bool even = (m2 & 1) == 0;
0109 const bool acceptBounds = even;
0110
0111 #ifdef BOOST_CHARCONV_DEBUG
0112 printf("-> %s %s * 2^%d\n", ieeeSign ? "-" : "+", s(m2), e2 + 2);
0113 #endif
0114
0115
0116 const unsigned_128_type mv = 4 * m2;
0117
0118 const uint32_t mmShift =
0119 (ieeeMantissa != (explicitLeadingBit ? one << (mantissaBits - 1) : 0))
0120 || (ieeeExponent == 0);
0121
0122
0123 unsigned_128_type vr;
0124 unsigned_128_type vp;
0125 unsigned_128_type vm;
0126 int32_t e10;
0127 bool vmIsTrailingZeros = false;
0128 bool vrIsTrailingZeros = false;
0129 if (e2 >= 0)
0130 {
0131
0132
0133 const uint32_t q = log10Pow2(e2) - (e2 > 3);
0134 e10 = static_cast<int32_t>(q);
0135 const int32_t k = BOOST_CHARCONV_POW5_INV_BITCOUNT + static_cast<int32_t>(pow5bits(q)) - 1;
0136 const int32_t i = -e2 + static_cast<int32_t>(q) + k;
0137 uint64_t pow5[4];
0138 generic_computeInvPow5(q, pow5);
0139 vr = mulShift(4 * m2, pow5, i);
0140 vp = mulShift(4 * m2 + 2, pow5, i);
0141 vm = mulShift(4 * m2 - 1 - mmShift, pow5, i);
0142
0143 #ifdef BOOST_CHARCONV_DEBUG
0144 printf("%s * 2^%d / 10^%d\n", s(mv), e2, q);
0145 printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
0146 #endif
0147
0148
0149 if (q <= 55)
0150 {
0151
0152 if (mv % 5 == 0)
0153 {
0154 vrIsTrailingZeros = multipleOfPowerOf5(mv, q - 1);
0155 }
0156 else if (acceptBounds)
0157 {
0158
0159
0160
0161 vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q);
0162 }
0163 else
0164 {
0165
0166 vp -= multipleOfPowerOf5(mv + 2, q);
0167 }
0168 }
0169 }
0170 else
0171 {
0172
0173 const uint32_t q = log10Pow5(-e2) - static_cast<uint32_t>(-e2 > 1);
0174 e10 = static_cast<int32_t>(q) + e2;
0175 const int32_t i = -e2 - static_cast<int32_t>(q);
0176 const int32_t k = static_cast<int32_t>(pow5bits(static_cast<uint32_t>(i))) - BOOST_CHARCONV_POW5_BITCOUNT;
0177 const int32_t j = static_cast<int32_t>(q) - k;
0178 uint64_t pow5[4];
0179 generic_computePow5(static_cast<uint32_t>(i), pow5);
0180 vr = mulShift(4 * m2, pow5, j);
0181 vp = mulShift(4 * m2 + 2, pow5, j);
0182 vm = mulShift(4 * m2 - 1 - mmShift, pow5, j);
0183
0184 #ifdef BOOST_CHARCONV_DEBUG
0185 printf("%s * 5^%d / 10^%d\n", s(mv), -e2, q);
0186 printf("%d %d %d %d\n", q, i, k, j);
0187 printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
0188 #endif
0189
0190 if (q <= 1)
0191 {
0192
0193
0194 vrIsTrailingZeros = true;
0195 if (acceptBounds)
0196 {
0197
0198 vmIsTrailingZeros = mmShift == 1;
0199 }
0200 else
0201 {
0202
0203 --vp;
0204 }
0205 }
0206 else if (q < 127)
0207 {
0208
0209
0210
0211
0212
0213 vrIsTrailingZeros = multipleOfPowerOf2(mv, q - 1);
0214
0215 #ifdef BOOST_CHARCONV_DEBUG
0216 printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
0217 #endif
0218 }
0219 }
0220
0221 #ifdef BOOST_CHARCONV_DEBUG
0222 printf("e10=%d\n", e10);
0223 printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
0224 printf("vm is trailing zeros=%s\n", vmIsTrailingZeros ? "true" : "false");
0225 printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
0226 #endif
0227
0228
0229 uint32_t removed = 0;
0230 uint8_t lastRemovedDigit = 0;
0231 unsigned_128_type output;
0232
0233 while (vp / 10 > vm / 10)
0234 {
0235 vmIsTrailingZeros &= vm % 10 == 0;
0236 vrIsTrailingZeros &= lastRemovedDigit == 0;
0237 lastRemovedDigit = static_cast<uint8_t>(vr % 10);
0238 vr /= 10;
0239 vp /= 10;
0240 vm /= 10;
0241 ++removed;
0242 }
0243
0244 #ifdef BOOST_CHARCONV_DEBUG
0245 printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
0246 printf("d-10=%s\n", vmIsTrailingZeros ? "true" : "false");
0247 #endif
0248
0249 if (vmIsTrailingZeros)
0250 {
0251 while (vm % 10 == 0)
0252 {
0253 vrIsTrailingZeros &= lastRemovedDigit == 0;
0254 lastRemovedDigit = static_cast<uint8_t>(vr % 10);
0255 vr /= 10;
0256 vp /= 10;
0257 vm /= 10;
0258 ++removed;
0259 }
0260 }
0261
0262 #ifdef BOOST_CHARCONV_DEBUG
0263 printf("%s %d\n", s(vr), lastRemovedDigit);
0264 printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
0265 #endif
0266
0267 if (vrIsTrailingZeros && (lastRemovedDigit == 5) && (vr % 2 == 0))
0268 {
0269
0270 lastRemovedDigit = 4;
0271 }
0272
0273 output = vr + static_cast<unsigned_128_type>((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || (lastRemovedDigit >= 5));
0274 const int32_t exp = e10 + static_cast<int32_t>(removed);
0275
0276 #ifdef BOOST_CHARCONV_DEBUG
0277 printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
0278 printf("O=%s\n", s(output));
0279 printf("EXP=%d\n", exp);
0280 #endif
0281
0282 return {output, exp, ieeeSign};
0283 }
0284
0285 static inline int copy_special_str(char* result, const std::ptrdiff_t result_size, const struct floating_decimal_128 fd) noexcept
0286 {
0287 if (fd.sign)
0288 {
0289 *result = '-';
0290 ++result;
0291 }
0292
0293 if (fd.mantissa)
0294 {
0295 if (fd.sign)
0296 {
0297 if (fd.mantissa == static_cast<unsigned_128_type>(2305843009213693952) ||
0298 fd.mantissa == static_cast<unsigned_128_type>(6917529027641081856) ||
0299 fd.mantissa == static_cast<unsigned_128_type>(1) << 110)
0300 {
0301 if (result_size >= 10)
0302 {
0303 std::memcpy(result, "nan(snan)", 9);
0304 return 10;
0305 }
0306 else
0307 {
0308 return -1;
0309 }
0310 }
0311 else
0312 {
0313 if (result_size >= 9)
0314 {
0315 std::memcpy(result, "nan(ind)", 8);
0316 return 9;
0317 }
0318 else
0319 {
0320 return -1;
0321 }
0322 }
0323 }
0324 else
0325 {
0326 if (fd.mantissa == static_cast<unsigned_128_type>(2305843009213693952) ||
0327 fd.mantissa == static_cast<unsigned_128_type>(6917529027641081856) ||
0328 fd.mantissa == static_cast<unsigned_128_type>(1) << 110)
0329 {
0330 if (result_size >= 9)
0331 {
0332 std::memcpy(result, "nan(snan)", 9);
0333 return 9;
0334 }
0335 else
0336 {
0337 return -1;
0338 }
0339 }
0340 else
0341 {
0342 if (result_size >= 3)
0343 {
0344 std::memcpy(result, "nan", 3);
0345 return 3;
0346 }
0347 else
0348 {
0349 return -1;
0350 }
0351 }
0352 }
0353 }
0354
0355 if (result_size >= 3 + static_cast<std::ptrdiff_t>(fd.sign))
0356 {
0357 memcpy(result, "inf", 3);
0358 return static_cast<int>(fd.sign) + 3;
0359 }
0360
0361 return -1;
0362 }
0363
0364 static inline int generic_to_chars_fixed(const struct floating_decimal_128 v, char* result, const ptrdiff_t result_size, int precision) noexcept
0365 {
0366 if (v.exponent == fd128_exceptional_exponent)
0367 {
0368 return copy_special_str(result, result_size, v);
0369 }
0370
0371
0372 if (v.sign)
0373 {
0374 *result++ = '-';
0375 }
0376
0377 unsigned_128_type output = v.mantissa;
0378 const auto r = to_chars_128integer_impl(result, result + result_size, output);
0379 if (r.ec != std::errc())
0380 {
0381 return -static_cast<int>(r.ec);
0382 }
0383
0384 auto current_len = static_cast<int>(r.ptr - result);
0385
0386 #ifdef BOOST_CHARCONV_DEBUG
0387 char* man_print = s(v.mantissa);
0388 std::cerr << "Exp: " << v.exponent
0389 << "\nMantissa: " << man_print
0390 << "\nMan len: " << current_len << std::endl;
0391 free(man_print);
0392 #endif
0393
0394 if (v.exponent == 0)
0395 {
0396
0397 return current_len + static_cast<int>(v.sign);
0398 }
0399 else if (v.exponent > 0)
0400 {
0401
0402
0403 if (current_len + v.exponent > result_size)
0404 {
0405 return -static_cast<int>(std::errc::value_too_large);
0406 }
0407
0408 result = r.ptr;
0409 memset(result, '0', static_cast<std::size_t>(v.exponent));
0410 result += static_cast<std::size_t>(v.exponent);
0411 current_len += v.exponent;
0412 *result++ = '.';
0413 ++precision;
0414 }
0415 else if ((-v.exponent) < current_len)
0416 {
0417
0418 if (current_len + v.exponent + 1 > result_size)
0419 {
0420 return -static_cast<int>(std::errc::result_out_of_range);
0421 }
0422
0423 memmove(result + current_len + v.exponent + 1, result + current_len + v.exponent, static_cast<std::size_t>(-v.exponent));
0424 memcpy(result + current_len + v.exponent, ".", 1U);
0425 ++current_len;
0426 precision -= current_len + v.exponent;
0427 result += current_len + v.exponent + 1;
0428 }
0429 else
0430 {
0431
0432 if (-v.exponent + 2 > result_size)
0433 {
0434 return -static_cast<int>(std::errc::value_too_large);
0435 }
0436
0437 memmove(result - v.exponent - current_len + 2, result, static_cast<std::size_t>(current_len));
0438 memcpy(result, "0.", 2U);
0439 memset(result + 2, '0', static_cast<std::size_t>(0 - v.exponent - current_len));
0440 current_len = -v.exponent + 2;
0441 precision -= current_len - 2;
0442 result += current_len;
0443 }
0444
0445 if (precision > 0)
0446 {
0447 if (current_len + precision > result_size)
0448 {
0449 return -static_cast<int>(std::errc::result_out_of_range);
0450 }
0451
0452 memset(result, '0', static_cast<std::size_t>(precision));
0453 current_len += precision;
0454 }
0455
0456 return current_len + static_cast<int>(v.sign);
0457 }
0458
0459
0460
0461
0462
0463
0464
0465
0466 static inline int generic_to_chars(const struct floating_decimal_128 v, char* result, const ptrdiff_t result_size,
0467 chars_format fmt = chars_format::general, int precision = -1) noexcept
0468 {
0469 if (v.exponent == fd128_exceptional_exponent)
0470 {
0471 return copy_special_str(result, result_size, v);
0472 }
0473
0474 unsigned_128_type output = v.mantissa;
0475 const uint32_t olength = static_cast<uint32_t>(num_digits(output));
0476
0477 #ifdef BOOST_CHARCONV_DEBUG
0478 printf("DIGITS=%s\n", s(v.mantissa));
0479 printf("OLEN=%u\n", olength);
0480 printf("EXP=%u\n", v.exponent + olength);
0481 #endif
0482
0483
0484 if (fmt == chars_format::general)
0485 {
0486 const int64_t exp = v.exponent + static_cast<int64_t>(olength);
0487 if (std::abs(exp) <= olength)
0488 {
0489 return generic_to_chars_fixed(v, result, result_size, precision);
0490 }
0491 }
0492
0493
0494 size_t index = 0;
0495 if (v.sign)
0496 {
0497 result[index++] = '-';
0498 }
0499
0500 if (index + olength > static_cast<size_t>(result_size))
0501 {
0502 return -static_cast<int>(std::errc::value_too_large);
0503 }
0504 else if (olength == 0)
0505 {
0506 return -2;
0507 }
0508
0509 for (uint32_t i = 0; i < olength - 1; ++i)
0510 {
0511 const auto c = static_cast<uint32_t>(output % 10);
0512 output /= 10;
0513 result[index + olength - i] = static_cast<char>('0' + c);
0514 }
0515 BOOST_CHARCONV_ASSERT(output < 10);
0516 result[index] = static_cast<char>('0' + static_cast<uint32_t>(output % 10));
0517
0518
0519 if (olength > 1)
0520 {
0521 result[index + 1] = '.';
0522 index += olength + 1;
0523 }
0524 else
0525 {
0526 ++index;
0527 }
0528
0529
0530 if (precision != -1)
0531 {
0532 if (static_cast<size_t>(precision) < index)
0533 {
0534 if (fmt != chars_format::scientific)
0535 {
0536 index = static_cast<size_t>(precision) + 1 + static_cast<size_t>(v.sign);
0537 }
0538 else
0539 {
0540 index = static_cast<size_t>(precision) + 2 + static_cast<size_t>(v.sign);
0541 }
0542
0543
0544 if (result[index] >= '5' && index < olength + 1 + static_cast<size_t>(v.sign))
0545 {
0546 bool continue_rounding = false;
0547 auto current_index = index;
0548 do
0549 {
0550 --current_index;
0551 if (result[current_index] == '9')
0552 {
0553 continue_rounding = true;
0554 result[current_index] = '0';
0555 }
0556 else
0557 {
0558 continue_rounding = false;
0559 result[current_index] = static_cast<char>(result[current_index] + static_cast<char>(1));
0560 }
0561 } while (continue_rounding && current_index > 2);
0562 }
0563
0564
0565 if (fmt != chars_format::scientific)
0566 {
0567 while (result[index - 1] == '0')
0568 {
0569 --index;
0570 }
0571 }
0572 else
0573 {
0574
0575 if (precision + 1 > static_cast<int>(olength))
0576 {
0577 result[index - 1] = '0';
0578 }
0579 }
0580 }
0581 else if (static_cast<size_t>(precision) > index)
0582 {
0583
0584 return -1;
0585 }
0586 }
0587
0588
0589 result[index++] = 'e';
0590 int32_t exp = v.exponent + static_cast<int32_t>(olength) - 1;
0591 if (exp < 0)
0592 {
0593 result[index++] = '-';
0594 exp = -exp;
0595 }
0596 else
0597 {
0598 result[index++] = '+';
0599 }
0600
0601 uint32_t elength = static_cast<uint32_t>(num_digits(exp));
0602 for (uint32_t i = 0; i < elength; ++i)
0603 {
0604
0605 if (elength == 1)
0606 {
0607 result[index + elength - 1 - i] = '0';
0608 ++index;
0609 }
0610
0611 const uint32_t c = static_cast<uint32_t>(exp % 10);
0612 exp /= 10;
0613 result[index + elength - 1 - i] = static_cast<char>('0' + c);
0614 }
0615 if (elength == 0)
0616 {
0617 result[index++] = '0';
0618 result[index++] = '0';
0619 }
0620
0621 index += elength;
0622 return static_cast<int>(index);
0623 }
0624
0625 static inline struct floating_decimal_128 float_to_fd128(float f) noexcept
0626 {
0627 static_assert(sizeof(float) == sizeof(uint32_t), "Float is not 32 bits");
0628 uint32_t bits = 0;
0629 std::memcpy(&bits, &f, sizeof(float));
0630 return generic_binary_to_decimal(bits, 23, 8, false);
0631 }
0632
0633 static inline struct floating_decimal_128 double_to_fd128(double d) noexcept
0634 {
0635 static_assert(sizeof(double) == sizeof(uint64_t), "Double is not 64 bits");
0636 uint64_t bits = 0;
0637 std::memcpy(&bits, &d, sizeof(double));
0638 return generic_binary_to_decimal(bits, 52, 11, false);
0639 }
0640
0641
0642
0643 #ifdef BOOST_CHARCONV_HAS_FLOAT16
0644
0645 static inline struct floating_decimal_128 float16_t_to_fd128(std::float16_t f) noexcept
0646 {
0647 uint16_t bits = 0;
0648 std::memcpy(&bits, &f, sizeof(std::float16_t));
0649 return generic_binary_to_decimal(bits, 10, 5, false);
0650 }
0651
0652 #endif
0653
0654 #ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
0655
0656 static inline struct floating_decimal_128 float16_t_to_fd128(std::bfloat16_t f) noexcept
0657 {
0658 uint16_t bits = 0;
0659 std::memcpy(&bits, &f, sizeof(std::bfloat16_t));
0660 return generic_binary_to_decimal(bits, 7, 8, false);
0661 }
0662
0663 #endif
0664
0665 #if BOOST_CHARCONV_LDBL_BITS == 80
0666
0667 static inline struct floating_decimal_128 long_double_to_fd128(long double d) noexcept
0668 {
0669 #ifdef BOOST_CHARCONV_HAS_INT128
0670 unsigned_128_type bits = 0;
0671 std::memcpy(&bits, &d, sizeof(long double));
0672 #else
0673 trivial_uint128 trivial_bits;
0674 std::memcpy(&trivial_bits, &d, sizeof(long double));
0675 unsigned_128_type bits {trivial_bits};
0676 #endif
0677
0678 #ifdef BOOST_CHARCONV_DEBUG
0679
0680
0681
0682
0683 bits &= (one << 80) - 1;
0684 #endif
0685
0686 return generic_binary_to_decimal(bits, 64, 15, true);
0687 }
0688
0689 #elif BOOST_CHARCONV_LDBL_BITS == 128
0690
0691 static inline struct floating_decimal_128 long_double_to_fd128(long double d) noexcept
0692 {
0693 unsigned_128_type bits = 0;
0694 std::memcpy(&bits, &d, sizeof(long double));
0695
0696 #if LDBL_MANT_DIG == 113
0697 # ifdef __PPC64__
0698 return generic_binary_to_decimal(bits, 112, 15, false);
0699 # else
0700 return generic_binary_to_decimal(bits, 112, 15, true);
0701 # endif
0702 #elif LDBL_MANT_DIG == 106
0703 return generic_binary_to_decimal(bits, 105, 11, true);
0704 #endif
0705 }
0706
0707 #endif
0708
0709 }}}}
0710
0711 #endif