File indexing completed on 2025-01-18 09:38:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #ifndef BOOST_JSON_DETAIL_RYU_IMPL_D2S_IPP
0035 #define BOOST_JSON_DETAIL_RYU_IMPL_D2S_IPP
0036
0037 #include <boost/json/detail/ryu/ryu.hpp>
0038 #include <cstdlib>
0039 #include <cstring>
0040
0041 #ifdef RYU_DEBUG
0042 #include <stdio.h>
0043 #endif
0044
0045
0046
0047 #if defined(__SIZEOF_INT128__) && !defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS)
0048 #define BOOST_JSON_RYU_HAS_UINT128
0049 #elif defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS) && defined(_M_X64)
0050 #define BOOST_JSON_RYU_HAS_64_BIT_INTRINSICS
0051 #endif
0052
0053 #include <boost/json/detail/ryu/detail/common.hpp>
0054 #include <boost/json/detail/ryu/detail/digit_table.hpp>
0055 #include <boost/json/detail/ryu/detail/d2s.hpp>
0056 #include <boost/json/detail/ryu/detail/d2s_intrinsics.hpp>
0057
0058 namespace boost {
0059 namespace json {
0060 namespace detail {
0061
0062 namespace ryu {
0063 namespace detail {
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102 #if defined(BOOST_JSON_RYU_HAS_UINT128)
0103
0104
0105 inline
0106 std::uint64_t
0107 mulShift(
0108 const std::uint64_t m,
0109 const std::uint64_t* const mul,
0110 const std::int32_t j) noexcept
0111 {
0112 const uint128_t b0 = ((uint128_t) m) * mul[0];
0113 const uint128_t b2 = ((uint128_t) m) * mul[1];
0114 return (std::uint64_t) (((b0 >> 64) + b2) >> (j - 64));
0115 }
0116
0117 inline
0118 uint64_t
0119 mulShiftAll(
0120 const std::uint64_t m,
0121 const std::uint64_t* const mul,
0122 std::int32_t const j,
0123 std::uint64_t* const vp,
0124 std::uint64_t* const vm,
0125 const std::uint32_t mmShift) noexcept
0126 {
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139 *vp = mulShift(4 * m + 2, mul, j);
0140 *vm = mulShift(4 * m - 1 - mmShift, mul, j);
0141 return mulShift(4 * m, mul, j);
0142 }
0143
0144 #elif defined(BOOST_JSON_RYU_HAS_64_BIT_INTRINSICS)
0145
0146 inline
0147 std::uint64_t
0148 mulShift(
0149 const std::uint64_t m,
0150 const std::uint64_t* const mul,
0151 const std::int32_t j) noexcept
0152 {
0153
0154 std::uint64_t high1;
0155 std::uint64_t const low1 = umul128(m, mul[1], &high1);
0156 std::uint64_t high0;
0157 umul128(m, mul[0], &high0);
0158 std::uint64_t const sum = high0 + low1;
0159 if (sum < high0)
0160 ++high1;
0161 return shiftright128(sum, high1, j - 64);
0162 }
0163
0164 inline
0165 std::uint64_t
0166 mulShiftAll(
0167 const std::uint64_t m,
0168 const std::uint64_t* const mul,
0169 const std::int32_t j,
0170 std::uint64_t* const vp,
0171 std::uint64_t* const vm,
0172 const std::uint32_t mmShift) noexcept
0173 {
0174 *vp = mulShift(4 * m + 2, mul, j);
0175 *vm = mulShift(4 * m - 1 - mmShift, mul, j);
0176 return mulShift(4 * m, mul, j);
0177 }
0178
0179 #else
0180
0181 inline
0182 std::uint64_t
0183 mulShiftAll(
0184 std::uint64_t m,
0185 const std::uint64_t* const mul,
0186 const std::int32_t j,
0187 std::uint64_t* const vp,
0188 std::uint64_t* const vm,
0189 const std::uint32_t mmShift)
0190 {
0191 m <<= 1;
0192
0193 std::uint64_t tmp;
0194 std::uint64_t const lo = umul128(m, mul[0], &tmp);
0195 std::uint64_t hi;
0196 std::uint64_t const mid = tmp + umul128(m, mul[1], &hi);
0197 hi += mid < tmp;
0198
0199 const std::uint64_t lo2 = lo + mul[0];
0200 const std::uint64_t mid2 = mid + mul[1] + (lo2 < lo);
0201 const std::uint64_t hi2 = hi + (mid2 < mid);
0202 *vp = shiftright128(mid2, hi2, (std::uint32_t)(j - 64 - 1));
0203
0204 if (mmShift == 1)
0205 {
0206 const std::uint64_t lo3 = lo - mul[0];
0207 const std::uint64_t mid3 = mid - mul[1] - (lo3 > lo);
0208 const std::uint64_t hi3 = hi - (mid3 > mid);
0209 *vm = shiftright128(mid3, hi3, (std::uint32_t)(j - 64 - 1));
0210 }
0211 else
0212 {
0213 const std::uint64_t lo3 = lo + lo;
0214 const std::uint64_t mid3 = mid + mid + (lo3 < lo);
0215 const std::uint64_t hi3 = hi + hi + (mid3 < mid);
0216 const std::uint64_t lo4 = lo3 - mul[0];
0217 const std::uint64_t mid4 = mid3 - mul[1] - (lo4 > lo3);
0218 const std::uint64_t hi4 = hi3 - (mid4 > mid3);
0219 *vm = shiftright128(mid4, hi4, (std::uint32_t)(j - 64));
0220 }
0221
0222 return shiftright128(mid, hi, (std::uint32_t)(j - 64 - 1));
0223 }
0224
0225 #endif
0226
0227 inline
0228 std::uint32_t
0229 decimalLength17(
0230 const std::uint64_t v)
0231 {
0232
0233
0234
0235
0236 BOOST_ASSERT(v < 100000000000000000L);
0237 if (v >= 10000000000000000L) { return 17; }
0238 if (v >= 1000000000000000L) { return 16; }
0239 if (v >= 100000000000000L) { return 15; }
0240 if (v >= 10000000000000L) { return 14; }
0241 if (v >= 1000000000000L) { return 13; }
0242 if (v >= 100000000000L) { return 12; }
0243 if (v >= 10000000000L) { return 11; }
0244 if (v >= 1000000000L) { return 10; }
0245 if (v >= 100000000L) { return 9; }
0246 if (v >= 10000000L) { return 8; }
0247 if (v >= 1000000L) { return 7; }
0248 if (v >= 100000L) { return 6; }
0249 if (v >= 10000L) { return 5; }
0250 if (v >= 1000L) { return 4; }
0251 if (v >= 100L) { return 3; }
0252 if (v >= 10L) { return 2; }
0253 return 1;
0254 }
0255
0256
0257 struct floating_decimal_64
0258 {
0259 std::uint64_t mantissa;
0260
0261
0262 std::int32_t exponent;
0263 };
0264
0265 inline
0266 floating_decimal_64
0267 d2d(
0268 const std::uint64_t ieeeMantissa,
0269 const std::uint32_t ieeeExponent)
0270 {
0271 std::int32_t e2;
0272 std::uint64_t m2;
0273 if (ieeeExponent == 0)
0274 {
0275
0276 e2 = 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
0277 m2 = ieeeMantissa;
0278 }
0279 else
0280 {
0281 e2 = (std::int32_t)ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
0282 m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
0283 }
0284 const bool even = (m2 & 1) == 0;
0285 const bool acceptBounds = even;
0286
0287 #ifdef RYU_DEBUG
0288 printf("-> %" PRIu64 " * 2^%d\n", m2, e2 + 2);
0289 #endif
0290
0291
0292 const std::uint64_t mv = 4 * m2;
0293
0294 const std::uint32_t mmShift = ieeeMantissa != 0 || ieeeExponent <= 1;
0295
0296
0297
0298
0299
0300 std::uint64_t vr, vp, vm;
0301 std::int32_t e10;
0302 bool vmIsTrailingZeros = false;
0303 bool vrIsTrailingZeros = false;
0304 if (e2 >= 0) {
0305
0306
0307 const std::uint32_t q = log10Pow2(e2) - (e2 > 3);
0308 e10 = (std::int32_t)q;
0309 const std::int32_t k = DOUBLE_POW5_INV_BITCOUNT + pow5bits((int32_t)q) - 1;
0310 const std::int32_t i = -e2 + (std::int32_t)q + k;
0311 #if defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
0312 uint64_t pow5[2];
0313 double_computeInvPow5(q, pow5);
0314 vr = mulShiftAll(m2, pow5, i, &vp, &vm, mmShift);
0315 #else
0316 vr = mulShiftAll(m2, DOUBLE_POW5_INV_SPLIT()[q], i, &vp, &vm, mmShift);
0317 #endif
0318 #ifdef RYU_DEBUG
0319 printf("%" PRIu64 " * 2^%d / 10^%u\n", mv, e2, q);
0320 printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
0321 #endif
0322 if (q <= 21)
0323 {
0324
0325
0326
0327 const std::uint32_t mvMod5 = ((std::uint32_t)mv) - 5 * ((std::uint32_t)div5(mv));
0328 if (mvMod5 == 0)
0329 {
0330 vrIsTrailingZeros = multipleOfPowerOf5(mv, q);
0331 }
0332 else if (acceptBounds)
0333 {
0334
0335
0336
0337 vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q);
0338 }
0339 else
0340 {
0341
0342 vp -= multipleOfPowerOf5(mv + 2, q);
0343 }
0344 }
0345 }
0346 else
0347 {
0348
0349 const std::uint32_t q = log10Pow5(-e2) - (-e2 > 1);
0350 e10 = (std::int32_t)q + e2;
0351 const std::int32_t i = -e2 - (std::int32_t)q;
0352 const std::int32_t k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
0353 const std::int32_t j = (std::int32_t)q - k;
0354 #if defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
0355 std::uint64_t pow5[2];
0356 double_computePow5(i, pow5);
0357 vr = mulShiftAll(m2, pow5, j, &vp, &vm, mmShift);
0358 #else
0359 vr = mulShiftAll(m2, DOUBLE_POW5_SPLIT()[i], j, &vp, &vm, mmShift);
0360 #endif
0361 #ifdef RYU_DEBUG
0362 printf("%" PRIu64 " * 5^%d / 10^%u\n", mv, -e2, q);
0363 printf("%u %d %d %d\n", q, i, k, j);
0364 printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
0365 #endif
0366 if (q <= 1)
0367 {
0368
0369
0370 vrIsTrailingZeros = true;
0371 if (acceptBounds)
0372 {
0373
0374 vmIsTrailingZeros = mmShift == 1;
0375 }
0376 else
0377 {
0378
0379 --vp;
0380 }
0381 }
0382 else if (q < 63)
0383 {
0384
0385
0386
0387
0388
0389 vrIsTrailingZeros = multipleOfPowerOf2(mv, q);
0390 #ifdef RYU_DEBUG
0391 printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
0392 #endif
0393 }
0394 }
0395 #ifdef RYU_DEBUG
0396 printf("e10=%d\n", e10);
0397 printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
0398 printf("vm is trailing zeros=%s\n", vmIsTrailingZeros ? "true" : "false");
0399 printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
0400 #endif
0401
0402
0403 std::int32_t removed = 0;
0404 std::uint8_t lastRemovedDigit = 0;
0405 std::uint64_t output;
0406
0407 if (vmIsTrailingZeros || vrIsTrailingZeros)
0408 {
0409
0410 for (;;)
0411 {
0412 const std::uint64_t vpDiv10 = div10(vp);
0413 const std::uint64_t vmDiv10 = div10(vm);
0414 if (vpDiv10 <= vmDiv10)
0415 break;
0416 const std::uint32_t vmMod10 = ((std::uint32_t)vm) - 10 * ((std::uint32_t)vmDiv10);
0417 const std::uint64_t vrDiv10 = div10(vr);
0418 const std::uint32_t vrMod10 = ((std::uint32_t)vr) - 10 * ((std::uint32_t)vrDiv10);
0419 vmIsTrailingZeros &= vmMod10 == 0;
0420 vrIsTrailingZeros &= lastRemovedDigit == 0;
0421 lastRemovedDigit = (uint8_t)vrMod10;
0422 vr = vrDiv10;
0423 vp = vpDiv10;
0424 vm = vmDiv10;
0425 ++removed;
0426 }
0427 #ifdef RYU_DEBUG
0428 printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
0429 printf("d-10=%s\n", vmIsTrailingZeros ? "true" : "false");
0430 #endif
0431 if (vmIsTrailingZeros)
0432 {
0433 for (;;)
0434 {
0435 const std::uint64_t vmDiv10 = div10(vm);
0436 const std::uint32_t vmMod10 = ((std::uint32_t)vm) - 10 * ((std::uint32_t)vmDiv10);
0437 if (vmMod10 != 0)
0438 break;
0439 const std::uint64_t vpDiv10 = div10(vp);
0440 const std::uint64_t vrDiv10 = div10(vr);
0441 const std::uint32_t vrMod10 = ((std::uint32_t)vr) - 10 * ((std::uint32_t)vrDiv10);
0442 vrIsTrailingZeros &= lastRemovedDigit == 0;
0443 lastRemovedDigit = (uint8_t)vrMod10;
0444 vr = vrDiv10;
0445 vp = vpDiv10;
0446 vm = vmDiv10;
0447 ++removed;
0448 }
0449 }
0450 #ifdef RYU_DEBUG
0451 printf("%" PRIu64 " %d\n", vr, lastRemovedDigit);
0452 printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
0453 #endif
0454 if (vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0)
0455 {
0456
0457 lastRemovedDigit = 4;
0458 }
0459
0460 output = vr + ((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5);
0461 }
0462 else
0463 {
0464
0465 bool roundUp = false;
0466 const std::uint64_t vpDiv100 = div100(vp);
0467 const std::uint64_t vmDiv100 = div100(vm);
0468 if (vpDiv100 > vmDiv100)
0469 {
0470
0471 const std::uint64_t vrDiv100 = div100(vr);
0472 const std::uint32_t vrMod100 = ((std::uint32_t)vr) - 100 * ((std::uint32_t)vrDiv100);
0473 roundUp = vrMod100 >= 50;
0474 vr = vrDiv100;
0475 vp = vpDiv100;
0476 vm = vmDiv100;
0477 removed += 2;
0478 }
0479
0480
0481
0482
0483 for (;;)
0484 {
0485 const std::uint64_t vpDiv10 = div10(vp);
0486 const std::uint64_t vmDiv10 = div10(vm);
0487 if (vpDiv10 <= vmDiv10)
0488 break;
0489 const std::uint64_t vrDiv10 = div10(vr);
0490 const std::uint32_t vrMod10 = ((std::uint32_t)vr) - 10 * ((std::uint32_t)vrDiv10);
0491 roundUp = vrMod10 >= 5;
0492 vr = vrDiv10;
0493 vp = vpDiv10;
0494 vm = vmDiv10;
0495 ++removed;
0496 }
0497 #ifdef RYU_DEBUG
0498 printf("%" PRIu64 " roundUp=%s\n", vr, roundUp ? "true" : "false");
0499 printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
0500 #endif
0501
0502 output = vr + (vr == vm || roundUp);
0503 }
0504 const std::int32_t exp = e10 + removed;
0505
0506 #ifdef RYU_DEBUG
0507 printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
0508 printf("O=%" PRIu64 "\n", output);
0509 printf("EXP=%d\n", exp);
0510 #endif
0511
0512 floating_decimal_64 fd;
0513 fd.exponent = exp;
0514 fd.mantissa = output;
0515 return fd;
0516 }
0517
0518 inline
0519 int
0520 to_chars(
0521 const floating_decimal_64 v,
0522 const bool sign,
0523 char* const result)
0524 {
0525
0526 int index = 0;
0527 if (sign)
0528 result[index++] = '-';
0529
0530 std::uint64_t output = v.mantissa;
0531 std::uint32_t const olength = decimalLength17(output);
0532
0533 #ifdef RYU_DEBUG
0534 printf("DIGITS=%" PRIu64 "\n", v.mantissa);
0535 printf("OLEN=%u\n", olength);
0536 printf("EXP=%u\n", v.exponent + olength);
0537 #endif
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547 std::uint32_t i = 0;
0548
0549
0550
0551
0552 if ((output >> 32) != 0)
0553 {
0554
0555 std::uint64_t const q = div1e8(output);
0556 std::uint32_t output2 = ((std::uint32_t)output) - 100000000 * ((std::uint32_t)q);
0557 output = q;
0558
0559 const std::uint32_t c = output2 % 10000;
0560 output2 /= 10000;
0561 const std::uint32_t d = output2 % 10000;
0562 const std::uint32_t c0 = (c % 100) << 1;
0563 const std::uint32_t c1 = (c / 100) << 1;
0564 const std::uint32_t d0 = (d % 100) << 1;
0565 const std::uint32_t d1 = (d / 100) << 1;
0566 std::memcpy(result + index + olength - i - 1, DIGIT_TABLE() + c0, 2);
0567 std::memcpy(result + index + olength - i - 3, DIGIT_TABLE() + c1, 2);
0568 std::memcpy(result + index + olength - i - 5, DIGIT_TABLE() + d0, 2);
0569 std::memcpy(result + index + olength - i - 7, DIGIT_TABLE() + d1, 2);
0570 i += 8;
0571 }
0572 uint32_t output2 = (std::uint32_t)output;
0573 while (output2 >= 10000)
0574 {
0575 #ifdef __clang__
0576 const uint32_t c = output2 - 10000 * (output2 / 10000);
0577 #else
0578 const uint32_t c = output2 % 10000;
0579 #endif
0580 output2 /= 10000;
0581 const uint32_t c0 = (c % 100) << 1;
0582 const uint32_t c1 = (c / 100) << 1;
0583 memcpy(result + index + olength - i - 1, DIGIT_TABLE() + c0, 2);
0584 memcpy(result + index + olength - i - 3, DIGIT_TABLE() + c1, 2);
0585 i += 4;
0586 }
0587 if (output2 >= 100) {
0588 const uint32_t c = (output2 % 100) << 1;
0589 output2 /= 100;
0590 memcpy(result + index + olength - i - 1, DIGIT_TABLE() + c, 2);
0591 i += 2;
0592 }
0593 if (output2 >= 10) {
0594 const uint32_t c = output2 << 1;
0595
0596 result[index + olength - i] = DIGIT_TABLE()[c + 1];
0597 result[index] = DIGIT_TABLE()[c];
0598 }
0599 else {
0600 result[index] = (char)('0' + output2);
0601 }
0602
0603
0604 if (olength > 1) {
0605 result[index + 1] = '.';
0606 index += olength + 1;
0607 }
0608 else {
0609 ++index;
0610 }
0611
0612
0613 result[index++] = 'E';
0614 int32_t exp = v.exponent + (int32_t)olength - 1;
0615 if (exp < 0) {
0616 result[index++] = '-';
0617 exp = -exp;
0618 }
0619
0620 if (exp >= 100) {
0621 const int32_t c = exp % 10;
0622 memcpy(result + index, DIGIT_TABLE() + 2 * (exp / 10), 2);
0623 result[index + 2] = (char)('0' + c);
0624 index += 3;
0625 }
0626 else if (exp >= 10) {
0627 memcpy(result + index, DIGIT_TABLE() + 2 * exp, 2);
0628 index += 2;
0629 }
0630 else {
0631 result[index++] = (char)('0' + exp);
0632 }
0633
0634 return index;
0635 }
0636
0637 static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent,
0638 floating_decimal_64* const v) {
0639 const uint64_t m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
0640 const int32_t e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS;
0641
0642 if (e2 > 0) {
0643
0644
0645 return false;
0646 }
0647
0648 if (e2 < -52) {
0649
0650 return false;
0651 }
0652
0653
0654
0655 const uint64_t mask = (1ull << -e2) - 1;
0656 const uint64_t fraction = m2 & mask;
0657 if (fraction != 0) {
0658 return false;
0659 }
0660
0661
0662
0663
0664 v->mantissa = m2 >> -e2;
0665 v->exponent = 0;
0666 return true;
0667 }
0668
0669 }
0670
0671 int
0672 d2s_buffered_n(
0673 double f,
0674 char* result,
0675 bool allow_infinity_and_nan) noexcept
0676 {
0677 using namespace detail;
0678
0679 std::uint64_t const bits = double_to_bits(f);
0680
0681 #ifdef RYU_DEBUG
0682 printf("IN=");
0683 for (std::int32_t bit = 63; bit >= 0; --bit) {
0684 printf("%d", (int)((bits >> bit) & 1));
0685 }
0686 printf("\n");
0687 #endif
0688
0689
0690 const bool ieeeSign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
0691 const std::uint64_t ieeeMantissa = bits & ((1ull << DOUBLE_MANTISSA_BITS) - 1);
0692 const std::uint32_t ieeeExponent = (std::uint32_t)((bits >> DOUBLE_MANTISSA_BITS) & ((1u << DOUBLE_EXPONENT_BITS) - 1));
0693
0694 if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) {
0695
0696 if (allow_infinity_and_nan)
0697 return copy_special_str(result, ieeeSign, ieeeExponent != 0, ieeeMantissa != 0);
0698 else
0699 return copy_special_str_conforming(result, ieeeSign, ieeeExponent != 0, ieeeMantissa != 0);
0700
0701 }
0702
0703 floating_decimal_64 v;
0704 const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, &v);
0705 if (isSmallInt) {
0706
0707
0708
0709
0710 for (;;) {
0711 std::uint64_t const q = div10(v.mantissa);
0712 std::uint32_t const r = ((std::uint32_t) v.mantissa) - 10 * ((std::uint32_t) q);
0713 if (r != 0)
0714 break;
0715 v.mantissa = q;
0716 ++v.exponent;
0717 }
0718 }
0719 else {
0720 v = d2d(ieeeMantissa, ieeeExponent);
0721 }
0722
0723 return to_chars(v, ieeeSign, result);
0724 }
0725
0726 }
0727
0728 }
0729 }
0730 }
0731
0732 #endif