double-conversion-double-to-string.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. // © 2018 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. //
  4. // From the double-conversion library. Original license:
  5. //
  6. // Copyright 2010 the V8 project authors. All rights reserved.
  7. // Redistribution and use in source and binary forms, with or without
  8. // modification, are permitted provided that the following conditions are
  9. // met:
  10. //
  11. // * Redistributions of source code must retain the above copyright
  12. // notice, this list of conditions and the following disclaimer.
  13. // * Redistributions in binary form must reproduce the above
  14. // copyright notice, this list of conditions and the following
  15. // disclaimer in the documentation and/or other materials provided
  16. // with the distribution.
  17. // * Neither the name of Google Inc. nor the names of its
  18. // contributors may be used to endorse or promote products derived
  19. // from this software without specific prior written permission.
  20. //
  21. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  27. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. // ICU PATCH: ifdef around UCONFIG_NO_FORMATTING
  33. #include "unicode/utypes.h"
  34. #if !UCONFIG_NO_FORMATTING
  35. #include <algorithm>
  36. #include <climits>
  37. #include <cmath>
  38. // ICU PATCH: Customize header file paths for ICU.
  39. // The file fixed-dtoa.h is not needed.
  40. #include "double-conversion-double-to-string.h"
  41. #include "double-conversion-bignum-dtoa.h"
  42. #include "double-conversion-fast-dtoa.h"
  43. #include "double-conversion-ieee.h"
  44. #include "double-conversion-utils.h"
  45. // ICU PATCH: Wrap in ICU namespace
  46. U_NAMESPACE_BEGIN
  47. namespace double_conversion {
  48. #if 0 // not needed for ICU
  49. const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() {
  50. int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
  51. static DoubleToStringConverter converter(flags,
  52. "Infinity",
  53. "NaN",
  54. 'e',
  55. -6, 21,
  56. 6, 0);
  57. return converter;
  58. }
  59. bool DoubleToStringConverter::HandleSpecialValues(
  60. double value,
  61. StringBuilder* result_builder) const {
  62. Double double_inspect(value);
  63. if (double_inspect.IsInfinite()) {
  64. if (infinity_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
  65. if (value < 0) {
  66. result_builder->AddCharacter('-');
  67. }
  68. result_builder->AddString(infinity_symbol_);
  69. return true;
  70. }
  71. if (double_inspect.IsNan()) {
  72. if (nan_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
  73. result_builder->AddString(nan_symbol_);
  74. return true;
  75. }
  76. return false;
  77. }
  78. void DoubleToStringConverter::CreateExponentialRepresentation(
  79. const char* decimal_digits,
  80. int length,
  81. int exponent,
  82. StringBuilder* result_builder) const {
  83. DOUBLE_CONVERSION_ASSERT(length != 0);
  84. result_builder->AddCharacter(decimal_digits[0]);
  85. if (length != 1) {
  86. result_builder->AddCharacter('.');
  87. result_builder->AddSubstring(&decimal_digits[1], length-1);
  88. }
  89. result_builder->AddCharacter(exponent_character_);
  90. if (exponent < 0) {
  91. result_builder->AddCharacter('-');
  92. exponent = -exponent;
  93. } else {
  94. if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
  95. result_builder->AddCharacter('+');
  96. }
  97. }
  98. DOUBLE_CONVERSION_ASSERT(exponent < 1e4);
  99. // Changing this constant requires updating the comment of DoubleToStringConverter constructor
  100. const int kMaxExponentLength = 5;
  101. char buffer[kMaxExponentLength + 1];
  102. buffer[kMaxExponentLength] = '\0';
  103. int first_char_pos = kMaxExponentLength;
  104. if (exponent == 0) {
  105. buffer[--first_char_pos] = '0';
  106. } else {
  107. while (exponent > 0) {
  108. buffer[--first_char_pos] = '0' + (exponent % 10);
  109. exponent /= 10;
  110. }
  111. }
  112. // Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength)
  113. // For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2
  114. while(kMaxExponentLength - first_char_pos < std::min(min_exponent_width_, kMaxExponentLength)) {
  115. buffer[--first_char_pos] = '0';
  116. }
  117. result_builder->AddSubstring(&buffer[first_char_pos],
  118. kMaxExponentLength - first_char_pos);
  119. }
  120. void DoubleToStringConverter::CreateDecimalRepresentation(
  121. const char* decimal_digits,
  122. int length,
  123. int decimal_point,
  124. int digits_after_point,
  125. StringBuilder* result_builder) const {
  126. // Create a representation that is padded with zeros if needed.
  127. if (decimal_point <= 0) {
  128. // "0.00000decimal_rep" or "0.000decimal_rep00".
  129. result_builder->AddCharacter('0');
  130. if (digits_after_point > 0) {
  131. result_builder->AddCharacter('.');
  132. result_builder->AddPadding('0', -decimal_point);
  133. DOUBLE_CONVERSION_ASSERT(length <= digits_after_point - (-decimal_point));
  134. result_builder->AddSubstring(decimal_digits, length);
  135. int remaining_digits = digits_after_point - (-decimal_point) - length;
  136. result_builder->AddPadding('0', remaining_digits);
  137. }
  138. } else if (decimal_point >= length) {
  139. // "decimal_rep0000.00000" or "decimal_rep.0000".
  140. result_builder->AddSubstring(decimal_digits, length);
  141. result_builder->AddPadding('0', decimal_point - length);
  142. if (digits_after_point > 0) {
  143. result_builder->AddCharacter('.');
  144. result_builder->AddPadding('0', digits_after_point);
  145. }
  146. } else {
  147. // "decima.l_rep000".
  148. DOUBLE_CONVERSION_ASSERT(digits_after_point > 0);
  149. result_builder->AddSubstring(decimal_digits, decimal_point);
  150. result_builder->AddCharacter('.');
  151. DOUBLE_CONVERSION_ASSERT(length - decimal_point <= digits_after_point);
  152. result_builder->AddSubstring(&decimal_digits[decimal_point],
  153. length - decimal_point);
  154. int remaining_digits = digits_after_point - (length - decimal_point);
  155. result_builder->AddPadding('0', remaining_digits);
  156. }
  157. if (digits_after_point == 0) {
  158. if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
  159. result_builder->AddCharacter('.');
  160. }
  161. if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
  162. result_builder->AddCharacter('0');
  163. }
  164. }
  165. }
  166. bool DoubleToStringConverter::ToShortestIeeeNumber(
  167. double value,
  168. StringBuilder* result_builder,
  169. DoubleToStringConverter::DtoaMode mode) const {
  170. DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE);
  171. if (Double(value).IsSpecial()) {
  172. return HandleSpecialValues(value, result_builder);
  173. }
  174. int decimal_point;
  175. bool sign;
  176. const int kDecimalRepCapacity = kBase10MaximalLength + 1;
  177. char decimal_rep[kDecimalRepCapacity];
  178. int decimal_rep_length;
  179. DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
  180. &sign, &decimal_rep_length, &decimal_point);
  181. bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
  182. if (sign && (value != 0.0 || !unique_zero)) {
  183. result_builder->AddCharacter('-');
  184. }
  185. int exponent = decimal_point - 1;
  186. if ((decimal_in_shortest_low_ <= exponent) &&
  187. (exponent < decimal_in_shortest_high_)) {
  188. CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
  189. decimal_point,
  190. (std::max)(0, decimal_rep_length - decimal_point),
  191. result_builder);
  192. } else {
  193. CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
  194. result_builder);
  195. }
  196. return true;
  197. }
  198. bool DoubleToStringConverter::ToFixed(double value,
  199. int requested_digits,
  200. StringBuilder* result_builder) const {
  201. DOUBLE_CONVERSION_ASSERT(kMaxFixedDigitsBeforePoint == 60);
  202. const double kFirstNonFixed = 1e60;
  203. if (Double(value).IsSpecial()) {
  204. return HandleSpecialValues(value, result_builder);
  205. }
  206. if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
  207. if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
  208. // Find a sufficiently precise decimal representation of n.
  209. int decimal_point;
  210. bool sign;
  211. // Add space for the '\0' byte.
  212. const int kDecimalRepCapacity =
  213. kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;
  214. char decimal_rep[kDecimalRepCapacity];
  215. int decimal_rep_length;
  216. DoubleToAscii(value, FIXED, requested_digits,
  217. decimal_rep, kDecimalRepCapacity,
  218. &sign, &decimal_rep_length, &decimal_point);
  219. bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
  220. if (sign && (value != 0.0 || !unique_zero)) {
  221. result_builder->AddCharacter('-');
  222. }
  223. CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
  224. requested_digits, result_builder);
  225. return true;
  226. }
  227. bool DoubleToStringConverter::ToExponential(
  228. double value,
  229. int requested_digits,
  230. StringBuilder* result_builder) const {
  231. if (Double(value).IsSpecial()) {
  232. return HandleSpecialValues(value, result_builder);
  233. }
  234. if (requested_digits < -1) return false;
  235. if (requested_digits > kMaxExponentialDigits) return false;
  236. int decimal_point;
  237. bool sign;
  238. // Add space for digit before the decimal point and the '\0' character.
  239. const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
  240. DOUBLE_CONVERSION_ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
  241. char decimal_rep[kDecimalRepCapacity];
  242. #ifndef NDEBUG
  243. // Problem: there is an assert in StringBuilder::AddSubstring() that
  244. // will pass this buffer to strlen(), and this buffer is not generally
  245. // null-terminated.
  246. memset(decimal_rep, 0, sizeof(decimal_rep));
  247. #endif
  248. int decimal_rep_length;
  249. if (requested_digits == -1) {
  250. DoubleToAscii(value, SHORTEST, 0,
  251. decimal_rep, kDecimalRepCapacity,
  252. &sign, &decimal_rep_length, &decimal_point);
  253. } else {
  254. DoubleToAscii(value, PRECISION, requested_digits + 1,
  255. decimal_rep, kDecimalRepCapacity,
  256. &sign, &decimal_rep_length, &decimal_point);
  257. DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= requested_digits + 1);
  258. for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
  259. decimal_rep[i] = '0';
  260. }
  261. decimal_rep_length = requested_digits + 1;
  262. }
  263. bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
  264. if (sign && (value != 0.0 || !unique_zero)) {
  265. result_builder->AddCharacter('-');
  266. }
  267. int exponent = decimal_point - 1;
  268. CreateExponentialRepresentation(decimal_rep,
  269. decimal_rep_length,
  270. exponent,
  271. result_builder);
  272. return true;
  273. }
  274. bool DoubleToStringConverter::ToPrecision(double value,
  275. int precision,
  276. StringBuilder* result_builder) const {
  277. if (Double(value).IsSpecial()) {
  278. return HandleSpecialValues(value, result_builder);
  279. }
  280. if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
  281. return false;
  282. }
  283. // Find a sufficiently precise decimal representation of n.
  284. int decimal_point;
  285. bool sign;
  286. // Add one for the terminating null character.
  287. const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
  288. char decimal_rep[kDecimalRepCapacity];
  289. int decimal_rep_length;
  290. DoubleToAscii(value, PRECISION, precision,
  291. decimal_rep, kDecimalRepCapacity,
  292. &sign, &decimal_rep_length, &decimal_point);
  293. DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= precision);
  294. bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
  295. if (sign && (value != 0.0 || !unique_zero)) {
  296. result_builder->AddCharacter('-');
  297. }
  298. // The exponent if we print the number as x.xxeyyy. That is with the
  299. // decimal point after the first digit.
  300. int exponent = decimal_point - 1;
  301. int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
  302. bool as_exponential =
  303. (-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
  304. (decimal_point - precision + extra_zero >
  305. max_trailing_padding_zeroes_in_precision_mode_);
  306. if ((flags_ & NO_TRAILING_ZERO) != 0) {
  307. // Truncate trailing zeros that occur after the decimal point (if exponential,
  308. // that is everything after the first digit).
  309. int stop = as_exponential ? 1 : std::max(1, decimal_point);
  310. while (decimal_rep_length > stop && decimal_rep[decimal_rep_length - 1] == '0') {
  311. --decimal_rep_length;
  312. }
  313. // Clamp precision to avoid the code below re-adding the zeros.
  314. precision = std::min(precision, decimal_rep_length);
  315. }
  316. if (as_exponential) {
  317. // Fill buffer to contain 'precision' digits.
  318. // Usually the buffer is already at the correct length, but 'DoubleToAscii'
  319. // is allowed to return less characters.
  320. for (int i = decimal_rep_length; i < precision; ++i) {
  321. decimal_rep[i] = '0';
  322. }
  323. CreateExponentialRepresentation(decimal_rep,
  324. precision,
  325. exponent,
  326. result_builder);
  327. } else {
  328. CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
  329. (std::max)(0, precision - decimal_point),
  330. result_builder);
  331. }
  332. return true;
  333. }
  334. #endif // not needed for ICU
  335. static BignumDtoaMode DtoaToBignumDtoaMode(
  336. DoubleToStringConverter::DtoaMode dtoa_mode) {
  337. switch (dtoa_mode) {
  338. case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST;
  339. case DoubleToStringConverter::SHORTEST_SINGLE:
  340. return BIGNUM_DTOA_SHORTEST_SINGLE;
  341. case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED;
  342. case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;
  343. default:
  344. DOUBLE_CONVERSION_UNREACHABLE();
  345. }
  346. }
  347. void DoubleToStringConverter::DoubleToAscii(double v,
  348. DtoaMode mode,
  349. int requested_digits,
  350. char* buffer,
  351. int buffer_length,
  352. bool* sign,
  353. int* length,
  354. int* point) {
  355. Vector<char> vector(buffer, buffer_length);
  356. DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
  357. DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
  358. if (Double(v).Sign() < 0) {
  359. *sign = true;
  360. v = -v;
  361. } else {
  362. *sign = false;
  363. }
  364. if (mode == PRECISION && requested_digits == 0) {
  365. vector[0] = '\0';
  366. *length = 0;
  367. return;
  368. }
  369. if (v == 0) {
  370. vector[0] = '0';
  371. vector[1] = '\0';
  372. *length = 1;
  373. *point = 1;
  374. return;
  375. }
  376. bool fast_worked;
  377. switch (mode) {
  378. case SHORTEST:
  379. fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
  380. break;
  381. #if 0 // not needed for ICU
  382. case SHORTEST_SINGLE:
  383. fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
  384. vector, length, point);
  385. break;
  386. case FIXED:
  387. fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
  388. break;
  389. case PRECISION:
  390. fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
  391. vector, length, point);
  392. break;
  393. #endif // not needed for ICU
  394. default:
  395. fast_worked = false;
  396. DOUBLE_CONVERSION_UNREACHABLE();
  397. }
  398. if (fast_worked) return;
  399. // If the fast dtoa didn't succeed use the slower bignum version.
  400. BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
  401. BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
  402. vector[*length] = '\0';
  403. }
  404. } // namespace double_conversion
  405. // ICU PATCH: Close ICU namespace
  406. U_NAMESPACE_END
  407. #endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING