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

source code of qtbase/src/3rdparty/double-conversion/double-conversion/double-to-string.cc