ryu_generic_128.hpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. // Copyright 2018 - 2023 Ulf Adams
  2. // Copyright 2023 Matt Borland
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. #ifndef BOOST_CHARCONV_DETAIL_RYU_RYU_GENERIC_128_HPP
  6. #define BOOST_CHARCONV_DETAIL_RYU_RYU_GENERIC_128_HPP
  7. #include <boost/charconv/detail/ryu/generic_128.hpp>
  8. #include <boost/charconv/detail/integer_search_trees.hpp>
  9. #include <boost/charconv/detail/config.hpp>
  10. #include <boost/charconv/detail/bit_layouts.hpp>
  11. #include <boost/charconv/to_chars.hpp>
  12. #include <cinttypes>
  13. #include <cstdio>
  14. #include <cstdint>
  15. #ifdef BOOST_CHARCONV_DEBUG
  16. # include <iostream>
  17. #endif
  18. namespace boost { namespace charconv { namespace detail { namespace ryu {
  19. static constexpr int32_t fd128_exceptional_exponent = 0x7FFFFFFF;
  20. static constexpr unsigned_128_type one = 1;
  21. struct floating_decimal_128
  22. {
  23. unsigned_128_type mantissa;
  24. int32_t exponent;
  25. bool sign;
  26. };
  27. #ifdef BOOST_CHARCONV_DEBUG
  28. static char* s(unsigned_128_type v) {
  29. int len = num_digits(v);
  30. char* b = static_cast<char*>(malloc((len + 1) * sizeof(char)));
  31. for (int i = 0; i < len; i++) {
  32. const uint32_t c = static_cast<uint32_t>(v % 10);
  33. v /= 10;
  34. b[len - 1 - i] = static_cast<char>('0' + c);
  35. }
  36. b[len] = 0;
  37. return b;
  38. }
  39. #endif
  40. static inline struct floating_decimal_128 generic_binary_to_decimal(
  41. const unsigned_128_type bits,
  42. const uint32_t mantissaBits, const uint32_t exponentBits, const bool explicitLeadingBit) noexcept
  43. {
  44. #ifdef BOOST_CHARCONV_DEBUG
  45. printf("IN=");
  46. for (int32_t bit = 127; bit >= 0; --bit)
  47. {
  48. printf("%u", static_cast<uint32_t>((bits >> bit) & 1));
  49. }
  50. printf("\n");
  51. #endif
  52. const uint32_t bias = (1u << (exponentBits - 1)) - 1;
  53. const bool ieeeSign = ((bits >> (mantissaBits + exponentBits)) & 1) != 0;
  54. const unsigned_128_type ieeeMantissa = bits & ((one << mantissaBits) - 1);
  55. const uint32_t ieeeExponent = static_cast<uint32_t>((bits >> mantissaBits) & ((one << exponentBits) - 1u));
  56. if (ieeeExponent == 0 && ieeeMantissa == 0)
  57. {
  58. struct floating_decimal_128 fd {0, 0, ieeeSign};
  59. return fd;
  60. }
  61. if (ieeeExponent == ((1u << exponentBits) - 1u))
  62. {
  63. struct floating_decimal_128 fd;
  64. fd.mantissa = explicitLeadingBit ? ieeeMantissa & ((one << (mantissaBits - 1)) - 1) : ieeeMantissa;
  65. fd.exponent = fd128_exceptional_exponent;
  66. fd.sign = ieeeSign;
  67. return fd;
  68. }
  69. int32_t e2;
  70. unsigned_128_type m2;
  71. // We subtract 2 in all cases so that the bounds computation has 2 additional bits.
  72. if (explicitLeadingBit)
  73. {
  74. // mantissaBits includes the explicit leading bit, so we need to correct for that here.
  75. if (ieeeExponent == 0)
  76. {
  77. e2 = static_cast<int32_t>(1 - bias - mantissaBits + 1 - 2);
  78. }
  79. else
  80. {
  81. e2 = static_cast<int32_t>(ieeeExponent - bias - mantissaBits + 1 - 2);
  82. }
  83. m2 = ieeeMantissa;
  84. }
  85. else
  86. {
  87. if (ieeeExponent == 0)
  88. {
  89. e2 = static_cast<int32_t>(1 - bias - mantissaBits - 2);
  90. m2 = ieeeMantissa;
  91. } else
  92. {
  93. e2 = static_cast<int32_t>(ieeeExponent - bias - mantissaBits - 2U);
  94. m2 = (one << mantissaBits) | ieeeMantissa;
  95. }
  96. }
  97. const bool even = (m2 & 1) == 0;
  98. const bool acceptBounds = even;
  99. #ifdef BOOST_CHARCONV_DEBUG
  100. printf("-> %s %s * 2^%d\n", ieeeSign ? "-" : "+", s(m2), e2 + 2);
  101. #endif
  102. // Step 2: Determine the interval of legal decimal representations.
  103. const unsigned_128_type mv = 4 * m2;
  104. // Implicit bool -> int conversion. True is 1, false is 0.
  105. const uint32_t mmShift =
  106. (ieeeMantissa != (explicitLeadingBit ? one << (mantissaBits - 1) : 0))
  107. || (ieeeExponent == 0);
  108. // Step 3: Convert to a decimal power base using 128-bit arithmetic.
  109. unsigned_128_type vr;
  110. unsigned_128_type vp;
  111. unsigned_128_type vm;
  112. int32_t e10;
  113. bool vmIsTrailingZeros = false;
  114. bool vrIsTrailingZeros = false;
  115. if (e2 >= 0)
  116. {
  117. // I tried special-casing q == 0, but there was no effect on performance.
  118. // This expression is slightly faster than max(0, log10Pow2(e2) - 1).
  119. const uint32_t q = log10Pow2(e2) - (e2 > 3);
  120. e10 = static_cast<int32_t>(q);
  121. const int32_t k = BOOST_CHARCONV_POW5_INV_BITCOUNT + static_cast<int32_t>(pow5bits(q)) - 1;
  122. const int32_t i = -e2 + static_cast<int32_t>(q) + k;
  123. uint64_t pow5[4];
  124. generic_computeInvPow5(q, pow5);
  125. vr = mulShift(4 * m2, pow5, i);
  126. vp = mulShift(4 * m2 + 2, pow5, i);
  127. vm = mulShift(4 * m2 - 1 - mmShift, pow5, i);
  128. #ifdef BOOST_CHARCONV_DEBUG
  129. printf("%s * 2^%d / 10^%d\n", s(mv), e2, q);
  130. printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
  131. #endif
  132. // floor(log_5(2^128)) = 55, this is very conservative
  133. if (q <= 55)
  134. {
  135. // Only one of mp, mv, and mm can be a multiple of 5, if any.
  136. if (mv % 5 == 0)
  137. {
  138. vrIsTrailingZeros = multipleOfPowerOf5(mv, q - 1);
  139. }
  140. else if (acceptBounds)
  141. {
  142. // Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q
  143. // <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q
  144. // <=> true && pow5Factor(mm) >= q, since e2 >= q.
  145. vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q);
  146. }
  147. else
  148. {
  149. // Same as min(e2 + 1, pow5Factor(mp)) >= q.
  150. vp -= multipleOfPowerOf5(mv + 2, q);
  151. }
  152. }
  153. }
  154. else
  155. {
  156. // This expression is slightly faster than max(0, log10Pow5(-e2) - 1).
  157. const uint32_t q = log10Pow5(-e2) - static_cast<uint32_t>(-e2 > 1);
  158. e10 = static_cast<int32_t>(q) + e2;
  159. const int32_t i = -e2 - static_cast<int32_t>(q);
  160. const int32_t k = static_cast<int32_t>(pow5bits(static_cast<uint32_t>(i))) - BOOST_CHARCONV_POW5_BITCOUNT;
  161. const int32_t j = static_cast<int32_t>(q) - k;
  162. uint64_t pow5[4];
  163. generic_computePow5(static_cast<uint32_t>(i), pow5);
  164. vr = mulShift(4 * m2, pow5, j);
  165. vp = mulShift(4 * m2 + 2, pow5, j);
  166. vm = mulShift(4 * m2 - 1 - mmShift, pow5, j);
  167. #ifdef BOOST_CHARCONV_DEBUG
  168. printf("%s * 5^%d / 10^%d\n", s(mv), -e2, q);
  169. printf("%d %d %d %d\n", q, i, k, j);
  170. printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
  171. #endif
  172. if (q <= 1)
  173. {
  174. // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
  175. // mv = 4 m2, so it always has at least two trailing 0 bits.
  176. vrIsTrailingZeros = true;
  177. if (acceptBounds)
  178. {
  179. // mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff mmShift == 1.
  180. vmIsTrailingZeros = mmShift == 1;
  181. }
  182. else
  183. {
  184. // mp = mv + 2, so it always has at least one trailing 0 bit.
  185. --vp;
  186. }
  187. }
  188. else if (q < 127)
  189. {
  190. // We need to compute min(ntz(mv), pow5Factor(mv) - e2) >= q-1
  191. // <=> ntz(mv) >= q-1 && pow5Factor(mv) - e2 >= q-1
  192. // <=> ntz(mv) >= q-1 (e2 is negative and -e2 >= q)
  193. // <=> (mv & ((1 << (q-1)) - 1)) == 0
  194. // We also need to make sure that the left shift does not overflow.
  195. vrIsTrailingZeros = multipleOfPowerOf2(mv, q - 1);
  196. #ifdef BOOST_CHARCONV_DEBUG
  197. printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
  198. #endif
  199. }
  200. }
  201. #ifdef BOOST_CHARCONV_DEBUG
  202. printf("e10=%d\n", e10);
  203. printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
  204. printf("vm is trailing zeros=%s\n", vmIsTrailingZeros ? "true" : "false");
  205. printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
  206. #endif
  207. // Step 4: Find the shortest decimal representation in the interval of legal representations.
  208. uint32_t removed = 0;
  209. uint8_t lastRemovedDigit = 0;
  210. unsigned_128_type output;
  211. while (vp / 10 > vm / 10)
  212. {
  213. vmIsTrailingZeros &= vm % 10 == 0;
  214. vrIsTrailingZeros &= lastRemovedDigit == 0;
  215. lastRemovedDigit = static_cast<uint8_t>(vr % 10);
  216. vr /= 10;
  217. vp /= 10;
  218. vm /= 10;
  219. ++removed;
  220. }
  221. #ifdef BOOST_CHARCONV_DEBUG
  222. printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
  223. printf("d-10=%s\n", vmIsTrailingZeros ? "true" : "false");
  224. #endif
  225. if (vmIsTrailingZeros)
  226. {
  227. while (vm % 10 == 0)
  228. {
  229. vrIsTrailingZeros &= lastRemovedDigit == 0;
  230. lastRemovedDigit = static_cast<uint8_t>(vr % 10);
  231. vr /= 10;
  232. vp /= 10;
  233. vm /= 10;
  234. ++removed;
  235. }
  236. }
  237. #ifdef BOOST_CHARCONV_DEBUG
  238. printf("%s %d\n", s(vr), lastRemovedDigit);
  239. printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
  240. #endif
  241. if (vrIsTrailingZeros && (lastRemovedDigit == 5) && (vr % 2 == 0))
  242. {
  243. // Round even if the exact numbers is .....50..0.
  244. lastRemovedDigit = 4;
  245. }
  246. // We need to take vr+1 if vr is outside bounds, or we need to round up.
  247. output = vr + static_cast<unsigned_128_type>((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || (lastRemovedDigit >= 5));
  248. const int32_t exp = e10 + static_cast<int32_t>(removed);
  249. #ifdef BOOST_CHARCONV_DEBUG
  250. printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm));
  251. printf("O=%s\n", s(output));
  252. printf("EXP=%d\n", exp);
  253. #endif
  254. return {output, exp, ieeeSign};
  255. }
  256. static inline int copy_special_str(char* result, const std::ptrdiff_t result_size, const struct floating_decimal_128 fd) noexcept
  257. {
  258. if (fd.sign)
  259. {
  260. *result = '-';
  261. ++result;
  262. }
  263. if (fd.mantissa)
  264. {
  265. if (fd.sign)
  266. {
  267. if (fd.mantissa == static_cast<unsigned_128_type>(2305843009213693952) ||
  268. fd.mantissa == static_cast<unsigned_128_type>(6917529027641081856) ||
  269. fd.mantissa == static_cast<unsigned_128_type>(1) << 110) // 2^110
  270. {
  271. if (result_size >= 10)
  272. {
  273. std::memcpy(result, "nan(snan)", 9);
  274. return 10;
  275. }
  276. else
  277. {
  278. return -1;
  279. }
  280. }
  281. else
  282. {
  283. if (result_size >= 9)
  284. {
  285. std::memcpy(result, "nan(ind)", 8);
  286. return 9;
  287. }
  288. else
  289. {
  290. return -1;
  291. }
  292. }
  293. }
  294. else
  295. {
  296. if (fd.mantissa == static_cast<unsigned_128_type>(2305843009213693952) ||
  297. fd.mantissa == static_cast<unsigned_128_type>(6917529027641081856) ||
  298. fd.mantissa == static_cast<unsigned_128_type>(1) << 110) // 2^110
  299. {
  300. if (result_size >= 9)
  301. {
  302. std::memcpy(result, "nan(snan)", 9);
  303. return 9;
  304. }
  305. else
  306. {
  307. return -1;
  308. }
  309. }
  310. else
  311. {
  312. if (result_size >= 3)
  313. {
  314. std::memcpy(result, "nan", 3);
  315. return 3;
  316. }
  317. else
  318. {
  319. return -1;
  320. }
  321. }
  322. }
  323. }
  324. if (result_size >= 3 + static_cast<std::ptrdiff_t>(fd.sign))
  325. {
  326. memcpy(result, "inf", 3);
  327. return static_cast<int>(fd.sign) + 3;
  328. }
  329. return -1;
  330. }
  331. static inline int generic_to_chars_fixed(const struct floating_decimal_128 v, char* result, const ptrdiff_t result_size, int precision) noexcept
  332. {
  333. if (v.exponent == fd128_exceptional_exponent)
  334. {
  335. return copy_special_str(result, result_size, v);
  336. }
  337. // Step 5: Print the decimal representation.
  338. if (v.sign)
  339. {
  340. *result++ = '-';
  341. }
  342. unsigned_128_type output = v.mantissa;
  343. const auto r = to_chars_128integer_impl(result, result + result_size, output);
  344. if (r.ec != std::errc())
  345. {
  346. return -static_cast<int>(r.ec);
  347. }
  348. auto current_len = static_cast<int>(r.ptr - result);
  349. #ifdef BOOST_CHARCONV_DEBUG
  350. char* man_print = s(v.mantissa);
  351. std::cerr << "Exp: " << v.exponent
  352. << "\nMantissa: " << man_print
  353. << "\nMan len: " << current_len << std::endl;
  354. free(man_print);
  355. #endif
  356. if (v.exponent == 0)
  357. {
  358. // Option 1: We need to do nothing but insert 0s
  359. if (precision > 0)
  360. {
  361. result[current_len++] = '.';
  362. memset(result+current_len, '0', static_cast<size_t>(precision));
  363. current_len += precision;
  364. precision = 0;
  365. }
  366. }
  367. else if (v.exponent > 0)
  368. {
  369. // Option 2: Append 0s to the end of the number until we get the proper significand value
  370. // Then we need precison worth of zeros after the decimal point as applicable
  371. if (current_len + v.exponent > result_size)
  372. {
  373. return -static_cast<int>(std::errc::value_too_large);
  374. }
  375. result = r.ptr;
  376. memset(result, '0', static_cast<std::size_t>(v.exponent));
  377. result += static_cast<std::size_t>(v.exponent);
  378. *result++ = '.';
  379. current_len += v.exponent + 1;
  380. }
  381. else if ((-v.exponent) < current_len)
  382. {
  383. // Option 3: Insert a decimal point into the middle of the existing number
  384. if (current_len + v.exponent + 1 > result_size)
  385. {
  386. return -static_cast<int>(std::errc::result_out_of_range);
  387. }
  388. memmove(result + current_len + v.exponent + 1, result + current_len + v.exponent, static_cast<std::size_t>(-v.exponent));
  389. const auto shift = result + current_len + v.exponent;
  390. const auto shift_width = (shift - result) + 1;
  391. memcpy(shift, ".", 1U);
  392. ++current_len;
  393. if (current_len - shift_width > precision)
  394. {
  395. if (precision > 0)
  396. {
  397. current_len = static_cast<int>(shift_width) + precision;
  398. }
  399. precision = 0;
  400. // Since we wrote additional characters into the buffer we need to add a null terminator,
  401. // so they are not read
  402. const auto round_val = result[current_len];
  403. result[current_len] = '\0';
  404. // More complicated rounding situations like 9999.999999 are already handled
  405. // so we don't need to worry about rounding past the decimal point
  406. if (round_val >= '5')
  407. {
  408. auto current_spot = current_len - 1;
  409. bool continue_rounding = true;
  410. while (result[current_spot] != '.' && continue_rounding)
  411. {
  412. if (result[current_spot] < '9')
  413. {
  414. result[current_spot] = static_cast<char>(static_cast<int>(result[current_spot]) + 1);
  415. continue_rounding = false;
  416. }
  417. else
  418. {
  419. result[current_spot] = '0';
  420. continue_rounding = true;
  421. }
  422. --current_spot;
  423. }
  424. BOOST_CHARCONV_ASSERT(!continue_rounding);
  425. }
  426. }
  427. else
  428. {
  429. precision -= current_len - static_cast<int>(shift_width);
  430. result += current_len + v.exponent + 1;
  431. }
  432. }
  433. else
  434. {
  435. // Option 4: Leading 0s
  436. if (-v.exponent + 2 > result_size)
  437. {
  438. return -static_cast<int>(std::errc::value_too_large);
  439. }
  440. memmove(result - v.exponent - current_len + 2, result, static_cast<std::size_t>(current_len));
  441. memcpy(result, "0.", 2U);
  442. memset(result + 2, '0', static_cast<std::size_t>(0 - v.exponent - current_len));
  443. current_len = -v.exponent + 2;
  444. precision -= current_len - 2;
  445. result += current_len;
  446. }
  447. if (precision > 0)
  448. {
  449. if (current_len + precision > result_size)
  450. {
  451. return -static_cast<int>(std::errc::result_out_of_range);
  452. }
  453. memset(result, '0', static_cast<std::size_t>(precision));
  454. current_len += precision;
  455. }
  456. return current_len + static_cast<int>(v.sign);
  457. }
  458. // Converts the given decimal floating point number to a string, writing to result, and returning
  459. // the number characters written. Does not terminate the buffer with a 0. In the worst case, this
  460. // function can write up to 53 characters.
  461. //
  462. // Maximal char buffer requirement:
  463. // sign + mantissa digits + decimal dot + 'E' + exponent sign + exponent digits
  464. // = 1 + 39 + 1 + 1 + 1 + 10 = 53
  465. static inline int generic_to_chars(const struct floating_decimal_128 v, char* result, const ptrdiff_t result_size,
  466. chars_format fmt = chars_format::general, int precision = -1) noexcept
  467. {
  468. if (v.exponent == fd128_exceptional_exponent)
  469. {
  470. return copy_special_str(result, result_size, v);
  471. }
  472. unsigned_128_type output = v.mantissa;
  473. const uint32_t olength = static_cast<uint32_t>(num_digits(output));
  474. #ifdef BOOST_CHARCONV_DEBUG
  475. printf("DIGITS=%s\n", s(v.mantissa));
  476. printf("OLEN=%u\n", olength);
  477. printf("EXP=%u\n", v.exponent + olength);
  478. #endif
  479. // See: https://github.com/cppalliance/charconv/issues/64
  480. if (fmt == chars_format::general)
  481. {
  482. const int64_t exp = v.exponent + static_cast<int64_t>(olength);
  483. if (std::abs(exp) <= olength)
  484. {
  485. auto ptr = generic_to_chars_fixed(v, result, result_size, precision);
  486. if (ptr >= 1 && result[ptr - 1] == '0')
  487. {
  488. --ptr;
  489. while (ptr > 0 && result[ptr] == '0')
  490. {
  491. --ptr;
  492. }
  493. ++ptr;
  494. }
  495. return ptr;
  496. }
  497. }
  498. // Step 5: Print the decimal representation.
  499. size_t index = 0;
  500. if (v.sign)
  501. {
  502. result[index++] = '-';
  503. }
  504. if (index + olength > static_cast<size_t>(result_size))
  505. {
  506. return -static_cast<int>(std::errc::value_too_large);
  507. }
  508. else if (olength == 0)
  509. {
  510. return -2; // Something has gone horribly wrong
  511. }
  512. for (uint32_t i = 0; i < olength - 1; ++i)
  513. {
  514. const auto c = static_cast<uint32_t>(output % 10);
  515. output /= 10;
  516. result[index + olength - i] = static_cast<char>('0' + c);
  517. }
  518. BOOST_CHARCONV_ASSERT(output < 10);
  519. result[index] = static_cast<char>('0' + static_cast<uint32_t>(output % 10)); // output should be < 10 by now.
  520. // Print decimal point if needed.
  521. if (olength > 1)
  522. {
  523. result[index + 1] = '.';
  524. index += olength + 1;
  525. }
  526. else
  527. {
  528. ++index;
  529. }
  530. // Reset the index to where the required precision should be
  531. if (precision != -1)
  532. {
  533. if (static_cast<size_t>(precision) < index)
  534. {
  535. if (fmt != chars_format::scientific)
  536. {
  537. index = static_cast<size_t>(precision) + 1 + static_cast<size_t>(v.sign); // Precision is number of characters not just the decimal portion
  538. }
  539. else
  540. {
  541. index = static_cast<size_t>(precision) + 2 + static_cast<size_t>(v.sign); // In scientific format the precision is just the decimal places
  542. }
  543. // Now we need to see if we need to round
  544. if (result[index] >= '5' && index < olength + 1 + static_cast<size_t>(v.sign))
  545. {
  546. bool continue_rounding = false;
  547. auto current_index = index;
  548. do
  549. {
  550. --current_index;
  551. if (result[current_index] == '9')
  552. {
  553. continue_rounding = true;
  554. result[current_index] = '0';
  555. }
  556. else
  557. {
  558. continue_rounding = false;
  559. result[current_index] = static_cast<char>(result[current_index] + static_cast<char>(1));
  560. }
  561. } while (continue_rounding && current_index > 2);
  562. }
  563. // If the last digit is a zero than overwrite that as well, but not in scientific formatting
  564. if (fmt != chars_format::scientific)
  565. {
  566. while (result[index - 1] == '0')
  567. {
  568. --index;
  569. }
  570. }
  571. else
  572. {
  573. // In scientific formatting we may need a final 0 to achieve the correct precision
  574. if (precision + 1 > static_cast<int>(olength))
  575. {
  576. result[index - 1] = '0';
  577. }
  578. }
  579. }
  580. else if (static_cast<size_t>(precision) > index)
  581. {
  582. // Use our fallback routine that will capture more of the precision
  583. return -1;
  584. }
  585. }
  586. // Print the exponent.
  587. result[index++] = 'e';
  588. int32_t exp = v.exponent + static_cast<int32_t>(olength) - 1;
  589. if (exp < 0)
  590. {
  591. result[index++] = '-';
  592. exp = -exp;
  593. }
  594. else
  595. {
  596. result[index++] = '+';
  597. }
  598. uint32_t elength = static_cast<uint32_t>(num_digits(exp));
  599. for (uint32_t i = 0; i < elength; ++i)
  600. {
  601. // Always print a minimum of 2 characters in the exponent field
  602. if (elength == 1)
  603. {
  604. result[index + elength - 1 - i] = '0';
  605. ++index;
  606. }
  607. const uint32_t c = static_cast<uint32_t>(exp % 10);
  608. exp /= 10;
  609. result[index + elength - 1 - i] = static_cast<char>('0' + c);
  610. }
  611. if (elength == 0)
  612. {
  613. result[index++] = '0';
  614. result[index++] = '0';
  615. }
  616. index += elength;
  617. return static_cast<int>(index);
  618. }
  619. static inline struct floating_decimal_128 float_to_fd128(float f) noexcept
  620. {
  621. static_assert(sizeof(float) == sizeof(uint32_t), "Float is not 32 bits");
  622. uint32_t bits = 0;
  623. std::memcpy(&bits, &f, sizeof(float));
  624. return generic_binary_to_decimal(bits, 23, 8, false);
  625. }
  626. static inline struct floating_decimal_128 double_to_fd128(double d) noexcept
  627. {
  628. static_assert(sizeof(double) == sizeof(uint64_t), "Double is not 64 bits");
  629. uint64_t bits = 0;
  630. std::memcpy(&bits, &d, sizeof(double));
  631. return generic_binary_to_decimal(bits, 52, 11, false);
  632. }
  633. // https://en.cppreference.com/w/cpp/types/floating-point#Fixed_width_floating-point_types
  634. #ifdef BOOST_CHARCONV_HAS_FLOAT16
  635. static inline struct floating_decimal_128 float16_t_to_fd128(std::float16_t f) noexcept
  636. {
  637. uint16_t bits = 0;
  638. std::memcpy(&bits, &f, sizeof(std::float16_t));
  639. return generic_binary_to_decimal(bits, 10, 5, false);
  640. }
  641. #endif
  642. #ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
  643. static inline struct floating_decimal_128 float16_t_to_fd128(std::bfloat16_t f) noexcept
  644. {
  645. uint16_t bits = 0;
  646. std::memcpy(&bits, &f, sizeof(std::bfloat16_t));
  647. return generic_binary_to_decimal(bits, 7, 8, false);
  648. }
  649. #endif
  650. #if BOOST_CHARCONV_LDBL_BITS == 80
  651. static inline struct floating_decimal_128 long_double_to_fd128(long double d) noexcept
  652. {
  653. #ifdef BOOST_CHARCONV_HAS_INT128
  654. unsigned_128_type bits = 0;
  655. std::memcpy(&bits, &d, sizeof(long double));
  656. #else
  657. trivial_uint128 trivial_bits;
  658. std::memcpy(&trivial_bits, &d, sizeof(long double));
  659. unsigned_128_type bits {trivial_bits};
  660. #endif
  661. #ifdef BOOST_CHARCONV_DEBUG
  662. // For some odd reason, this ends up with noise in the top 48 bits. We can
  663. // clear out those bits with the following line; this is not required, the
  664. // conversion routine should ignore those bits, but the debug output can be
  665. // confusing if they aren't 0s.
  666. bits &= (one << 80) - 1;
  667. #endif
  668. return generic_binary_to_decimal(bits, 64, 15, true);
  669. }
  670. #elif BOOST_CHARCONV_LDBL_BITS == 128
  671. static inline struct floating_decimal_128 long_double_to_fd128(long double d) noexcept
  672. {
  673. unsigned_128_type bits = 0;
  674. std::memcpy(&bits, &d, sizeof(long double));
  675. #if LDBL_MANT_DIG == 113 // binary128 (e.g. ARM, S390X, PPC64LE)
  676. # ifdef __PPC64__
  677. return generic_binary_to_decimal(bits, 112, 15, false);
  678. # else
  679. return generic_binary_to_decimal(bits, 112, 15, true);
  680. # endif
  681. #elif LDBL_MANT_DIG == 106 // ibm128 (e.g. PowerPC)
  682. return generic_binary_to_decimal(bits, 105, 11, true);
  683. #endif
  684. }
  685. #endif
  686. }}}} // Namespaces
  687. #endif //BOOST_RYU_GENERIC_128_HPP