dtoa.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // Tencent is pleased to support the open source community by making RapidJSON
  2. // available.
  3. //
  4. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
  5. // rights reserved.
  6. //
  7. // Licensed under the MIT License (the "License"); you may not use this file
  8. // except in compliance with the License. You may obtain a copy of the License
  9. // at
  10. //
  11. // http://opensource.org/licenses/MIT
  12. //
  13. // Unless required by applicable law or agreed to in writing, software
  14. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. // License for the specific language governing permissions and limitations under
  17. // the License.
  18. // This is a C++ header-only implementation of Grisu2 algorithm from the
  19. // publication: Loitsch, Florian. "Printing floating-point numbers quickly and
  20. // accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243.
  21. #ifndef RAPIDJSON_DTOA_
  22. #define RAPIDJSON_DTOA_
  23. #include "diyfp.h"
  24. #include "ieee754.h"
  25. #include "itoa.h" // GetDigitsLut()
  26. RAPIDJSON_NAMESPACE_BEGIN
  27. namespace internal {
  28. #ifdef __GNUC__
  29. RAPIDJSON_DIAG_PUSH
  30. RAPIDJSON_DIAG_OFF(effc++)
  31. RAPIDJSON_DIAG_OFF(array - bounds) // some gcc versions generate wrong warnings
  32. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
  33. #endif
  34. inline void GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest,
  35. uint64_t ten_kappa, uint64_t wp_w) {
  36. while (rest < wp_w && delta - rest >= ten_kappa &&
  37. (rest + ten_kappa < wp_w || /// closer
  38. wp_w - rest > rest + ten_kappa - wp_w)) {
  39. buffer[len - 1]--;
  40. rest += ten_kappa;
  41. }
  42. }
  43. inline int CountDecimalDigit32(uint32_t n) {
  44. // Simple pure C++ implementation was faster than __builtin_clz version in
  45. // this situation.
  46. if (n < 10) return 1;
  47. if (n < 100) return 2;
  48. if (n < 1000) return 3;
  49. if (n < 10000) return 4;
  50. if (n < 100000) return 5;
  51. if (n < 1000000) return 6;
  52. if (n < 10000000) return 7;
  53. if (n < 100000000) return 8;
  54. // Will not reach 10 digits in DigitGen()
  55. // if (n < 1000000000) return 9;
  56. // return 10;
  57. return 9;
  58. }
  59. inline void DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta,
  60. char *buffer, int *len, int *K) {
  61. static const uint32_t kPow10[] = {1, 10, 100, 1000,
  62. 10000, 100000, 1000000, 10000000,
  63. 100000000, 1000000000};
  64. const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
  65. const DiyFp wp_w = Mp - W;
  66. uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
  67. uint64_t p2 = Mp.f & (one.f - 1);
  68. int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
  69. *len = 0;
  70. while (kappa > 0) {
  71. uint32_t d = 0;
  72. switch (kappa) {
  73. case 9:
  74. d = p1 / 100000000;
  75. p1 %= 100000000;
  76. break;
  77. case 8:
  78. d = p1 / 10000000;
  79. p1 %= 10000000;
  80. break;
  81. case 7:
  82. d = p1 / 1000000;
  83. p1 %= 1000000;
  84. break;
  85. case 6:
  86. d = p1 / 100000;
  87. p1 %= 100000;
  88. break;
  89. case 5:
  90. d = p1 / 10000;
  91. p1 %= 10000;
  92. break;
  93. case 4:
  94. d = p1 / 1000;
  95. p1 %= 1000;
  96. break;
  97. case 3:
  98. d = p1 / 100;
  99. p1 %= 100;
  100. break;
  101. case 2:
  102. d = p1 / 10;
  103. p1 %= 10;
  104. break;
  105. case 1:
  106. d = p1;
  107. p1 = 0;
  108. break;
  109. default:;
  110. }
  111. if (d || *len)
  112. buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
  113. kappa--;
  114. uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
  115. if (tmp <= delta) {
  116. *K += kappa;
  117. GrisuRound(buffer, *len, delta, tmp,
  118. static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
  119. return;
  120. }
  121. }
  122. // kappa = 0
  123. for (;;) {
  124. p2 *= 10;
  125. delta *= 10;
  126. char d = static_cast<char>(p2 >> -one.e);
  127. if (d || *len) buffer[(*len)++] = static_cast<char>('0' + d);
  128. p2 &= one.f - 1;
  129. kappa--;
  130. if (p2 < delta) {
  131. *K += kappa;
  132. int index = -kappa;
  133. GrisuRound(buffer, *len, delta, p2, one.f,
  134. wp_w.f * (index < 9 ? kPow10[index] : 0));
  135. return;
  136. }
  137. }
  138. }
  139. inline void Grisu2(double value, char *buffer, int *length, int *K) {
  140. const DiyFp v(value);
  141. DiyFp w_m, w_p;
  142. v.NormalizedBoundaries(&w_m, &w_p);
  143. const DiyFp c_mk = GetCachedPower(w_p.e, K);
  144. const DiyFp W = v.Normalize() * c_mk;
  145. DiyFp Wp = w_p * c_mk;
  146. DiyFp Wm = w_m * c_mk;
  147. Wm.f++;
  148. Wp.f--;
  149. DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
  150. }
  151. inline char *WriteExponent(int K, char *buffer) {
  152. if (K < 0) {
  153. *buffer++ = '-';
  154. K = -K;
  155. }
  156. if (K >= 100) {
  157. *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
  158. K %= 100;
  159. const char *d = GetDigitsLut() + K * 2;
  160. *buffer++ = d[0];
  161. *buffer++ = d[1];
  162. } else if (K >= 10) {
  163. const char *d = GetDigitsLut() + K * 2;
  164. *buffer++ = d[0];
  165. *buffer++ = d[1];
  166. } else
  167. *buffer++ = static_cast<char>('0' + static_cast<char>(K));
  168. return buffer;
  169. }
  170. inline char *Prettify(char *buffer, int length, int k, int maxDecimalPlaces) {
  171. const int kk = length + k; // 10^(kk-1) <= v < 10^kk
  172. if (0 <= k && kk <= 21) {
  173. // 1234e7 -> 12340000000
  174. for (int i = length; i < kk; i++) buffer[i] = '0';
  175. buffer[kk] = '.';
  176. buffer[kk + 1] = '0';
  177. return &buffer[kk + 2];
  178. } else if (0 < kk && kk <= 21) {
  179. // 1234e-2 -> 12.34
  180. std::memmove(&buffer[kk + 1], &buffer[kk],
  181. static_cast<size_t>(length - kk));
  182. buffer[kk] = '.';
  183. if (0 > k + maxDecimalPlaces) {
  184. // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
  185. // Remove extra trailing zeros (at least one) after truncation.
  186. for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
  187. if (buffer[i] != '0') return &buffer[i + 1];
  188. return &buffer[kk + 2]; // Reserve one zero
  189. } else
  190. return &buffer[length + 1];
  191. } else if (-6 < kk && kk <= 0) {
  192. // 1234e-6 -> 0.001234
  193. const int offset = 2 - kk;
  194. std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
  195. buffer[0] = '0';
  196. buffer[1] = '.';
  197. for (int i = 2; i < offset; i++) buffer[i] = '0';
  198. if (length - kk > maxDecimalPlaces) {
  199. // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
  200. // Remove extra trailing zeros (at least one) after truncation.
  201. for (int i = maxDecimalPlaces + 1; i > 2; i--)
  202. if (buffer[i] != '0') return &buffer[i + 1];
  203. return &buffer[3]; // Reserve one zero
  204. } else
  205. return &buffer[length + offset];
  206. } else if (kk < -maxDecimalPlaces) {
  207. // Truncate to zero
  208. buffer[0] = '0';
  209. buffer[1] = '.';
  210. buffer[2] = '0';
  211. return &buffer[3];
  212. } else if (length == 1) {
  213. // 1e30
  214. buffer[1] = 'e';
  215. return WriteExponent(kk - 1, &buffer[2]);
  216. } else {
  217. // 1234e30 -> 1.234e33
  218. std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
  219. buffer[1] = '.';
  220. buffer[length + 1] = 'e';
  221. return WriteExponent(kk - 1, &buffer[0 + length + 2]);
  222. }
  223. }
  224. inline char *dtoa(double value, char *buffer, int maxDecimalPlaces = 324) {
  225. RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
  226. Double d(value);
  227. if (d.IsZero()) {
  228. if (d.Sign()) *buffer++ = '-'; // -0.0, Issue #289
  229. buffer[0] = '0';
  230. buffer[1] = '.';
  231. buffer[2] = '0';
  232. return &buffer[3];
  233. } else {
  234. if (value < 0) {
  235. *buffer++ = '-';
  236. value = -value;
  237. }
  238. int length, K;
  239. Grisu2(value, buffer, &length, &K);
  240. return Prettify(buffer, length, K, maxDecimalPlaces);
  241. }
  242. }
  243. #ifdef __GNUC__
  244. RAPIDJSON_DIAG_POP
  245. #endif
  246. } // namespace internal
  247. RAPIDJSON_NAMESPACE_END
  248. #endif // RAPIDJSON_DTOA_