Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
double-to-string.cc
Go to the documentation of this file.
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
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('-');
62 }
63 result_builder->AddString(infinity_symbol_);
64 return true;
65 }
66 if (double_inspect.IsNan()) {
67 if (nan_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
68 result_builder->AddString(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 {
81 result_builder->AddCharacter(decimal_digits[0]);
82 if (length == 1) {
84 result_builder->AddCharacter('.');
86 result_builder->AddCharacter('0');
87 }
88 }
89 } else {
90 result_builder->AddCharacter('.');
91 result_builder->AddSubstring(&decimal_digits[1], length-1);
92 }
93 result_builder->AddCharacter(exponent_character_);
94 if (exponent < 0) {
95 result_builder->AddCharacter('-');
96 exponent = -exponent;
97 } else {
98 if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
99 result_builder->AddCharacter('+');
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(min_exponent_width_, kMaxExponentLength)) {
119 buffer[--first_char_pos] = '0';
120 }
121 result_builder->AddSubstring(&buffer[first_char_pos],
122 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('0');
136 if (digits_after_point > 0) {
137 result_builder->AddCharacter('.');
138 result_builder->AddPadding('0', -decimal_point);
139 DOUBLE_CONVERSION_ASSERT(length <= digits_after_point - (-decimal_point));
140 result_builder->AddSubstring(decimal_digits, length);
141 int remaining_digits = digits_after_point - (-decimal_point) - length;
142 result_builder->AddPadding('0', remaining_digits);
143 }
144 } else if (decimal_point >= length) {
145 // "decimal_rep0000.00000" or "decimal_rep.0000".
146 result_builder->AddSubstring(decimal_digits, length);
147 result_builder->AddPadding('0', decimal_point - length);
148 if (digits_after_point > 0) {
149 result_builder->AddCharacter('.');
150 result_builder->AddPadding('0', digits_after_point);
151 }
152 } else {
153 // "decima.l_rep000".
154 DOUBLE_CONVERSION_ASSERT(digits_after_point > 0);
155 result_builder->AddSubstring(decimal_digits, decimal_point);
156 result_builder->AddCharacter('.');
157 DOUBLE_CONVERSION_ASSERT(length - decimal_point <= digits_after_point);
158 result_builder->AddSubstring(&decimal_digits[decimal_point],
159 length - decimal_point);
160 int remaining_digits = digits_after_point - (length - decimal_point);
161 result_builder->AddPadding('0', remaining_digits);
162 }
163 if (digits_after_point == 0) {
164 if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
165 result_builder->AddCharacter('.');
166 }
167 if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
168 result_builder->AddCharacter('0');
169 }
170 }
171}
172
173
174bool DoubleToStringConverter::ToShortestIeeeNumber(
175 double value,
176 StringBuilder* result_builder,
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(value, mode, 0, decimal_rep, kDecimalRepCapacity,
190 &sign, &decimal_rep_length, &decimal_point);
191
192 bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
193 if (sign && (value != 0.0 || !unique_zero)) {
194 result_builder->AddCharacter('-');
195 }
196
197 int exponent = decimal_point - 1;
198 if ((decimal_in_shortest_low_ <= exponent) &&
199 (exponent < decimal_in_shortest_high_)) {
200 CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
201 decimal_point,
202 (std::max)(0, decimal_rep_length - decimal_point),
203 result_builder);
204 } else {
205 CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
206 result_builder);
207 }
208 return true;
209}
210
211
213 int requested_digits,
214 StringBuilder* result_builder) const {
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 =
231 char decimal_rep[kDecimalRepCapacity];
232 int decimal_rep_length;
233 DoubleToAscii(value, FIXED, requested_digits,
234 decimal_rep, kDecimalRepCapacity,
235 &sign, &decimal_rep_length, &decimal_point);
236
237 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
238 if (sign && (value != 0.0 || !unique_zero)) {
239 result_builder->AddCharacter('-');
240 }
241
242 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
243 requested_digits, result_builder);
244 return true;
245}
246
247
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(decimal_rep, 0, sizeof(decimal_rep));
270#endif
271 int decimal_rep_length;
272
273 if (requested_digits == -1) {
275 decimal_rep, kDecimalRepCapacity,
276 &sign, &decimal_rep_length, &decimal_point);
277 } else {
278 DoubleToAscii(value, PRECISION, requested_digits + 1,
279 decimal_rep, kDecimalRepCapacity,
280 &sign, &decimal_rep_length, &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('-');
292 }
293
294 int exponent = decimal_point - 1;
295 CreateExponentialRepresentation(decimal_rep,
296 decimal_rep_length,
297 exponent,
298 result_builder);
299 return true;
300}
301
302
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(value, PRECISION, precision,
323 decimal_rep, kDecimalRepCapacity,
324 &sign, &decimal_rep_length, &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('-');
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(1, 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(precision, 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_rep,
360 precision,
361 exponent,
362 result_builder);
363 } else {
364 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
365 (std::max)(0, precision - decimal_point),
366 result_builder);
367 }
368 return true;
369}
370
371
384
385
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(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
423 break;
424 case SHORTEST_SINGLE:
425 fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
426 vector, length, point);
427 break;
428 case FIXED:
429 fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
430 break;
431 case PRECISION:
432 fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
433 vector, length, point);
434 break;
435 default:
436 fast_worked = false;
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(mode);
443 BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
444 vector[*length] = '\0';
445}
446
447} // namespace double_conversion
static int sign(SkScalar x)
Definition SkPath.cpp:2141
bool ToFixed(double value, int requested_digits, StringBuilder *result_builder) const
static const DoubleToStringConverter & EcmaScriptConverter()
bool ToExponential(double value, int requested_digits, StringBuilder *result_builder) const
static void DoubleToAscii(double v, DtoaMode mode, int requested_digits, char *buffer, int buffer_length, bool *sign, int *length, int *point)
bool ToPrecision(double value, int precision, StringBuilder *result_builder) const
void AddString(const char *s)
Definition utils.h:327
FlutterSemanticsFlag flags
static const uint8_t buffer[]
uint8_t value
size_t length
void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, Vector< char > buffer, int *length, int *decimal_point)
static BignumDtoaMode DtoaToBignumDtoaMode(DoubleToStringConverter::DtoaMode dtoa_mode)
bool FastDtoa(double v, FastDtoaMode mode, int requested_digits, Vector< char > buffer, int *length, int *decimal_point)
Definition fast-dtoa.cc:635
bool FastFixedDtoa(double v, int fractional_count, Vector< char > buffer, int *length, int *decimal_point)
#define DOUBLE_CONVERSION_NULLPTR
Definition utils.h:41
#define DOUBLE_CONVERSION_ASSERT(condition)
Definition utils.h:46
#define DOUBLE_CONVERSION_UNREACHABLE()
Definition utils.h:77