Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(352)

Side by Side Diff: third_party/WebKit/Source/wtf/dtoa/double-conversion.cc

Issue 2764243002: Move files in wtf/ to platform/wtf/ (Part 9). (Closed)
Patch Set: Rebase. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "double-conversion.h"
29
30 #include "bignum-dtoa.h"
31 #include "double.h"
32 #include "fast-dtoa.h"
33 #include "fixed-dtoa.h"
34 #include "strtod.h"
35 #include "utils.h"
36 #include <limits.h>
37 #include <math.h>
38
39 namespace WTF {
40
41 namespace double_conversion {
42
43 const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter( ) {
44 int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
45 static DoubleToStringConverter converter(flags,
46 "Infinity",
47 "NaN",
48 'e',
49 -6, 21,
50 6, 0);
51 return converter;
52 }
53
54
55 bool DoubleToStringConverter::HandleSpecialValues(
56 double value,
57 StringBuilder* result_buil der) const {
58 Double double_inspect(value);
59 if (double_inspect.IsInfinite()) {
60 if (infinity_symbol_ == NULL) return false;
61 if (value < 0) {
62 result_builder->AddCharacter('-');
63 }
64 result_builder->AddString(infinity_symbol_);
65 return true;
66 }
67 if (double_inspect.IsNan()) {
68 if (nan_symbol_ == NULL) return false;
69 result_builder->AddString(nan_symbol_);
70 return true;
71 }
72 return false;
73 }
74
75
76 void DoubleToStringConverter::CreateExponentialRepresentation(
77 const char* de cimal_digits,
78 int length,
79 int exponent,
80 StringBuilder* result_builder) const {
81 ASSERT(length != 0);
82 result_builder->AddCharacter(decimal_digits[0]);
83 if (length != 1) {
84 result_builder->AddCharacter('.');
85 result_builder->AddSubstring(&decimal_digits[1], length-1);
86 }
87 result_builder->AddCharacter(exponent_character_);
88 if (exponent < 0) {
89 result_builder->AddCharacter('-');
90 exponent = -exponent;
91 } else {
92 if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
93 result_builder->AddCharacter('+');
94 }
95 }
96 if (exponent == 0) {
97 result_builder->AddCharacter('0');
98 return;
99 }
100 ASSERT(exponent < 1e4);
101 const int kMaxExponentLength = 5;
102 char buffer[kMaxExponentLength + 1];
103 int first_char_pos = kMaxExponentLength;
104 buffer[first_char_pos] = '\0';
105 while (exponent > 0) {
106 buffer[--first_char_pos] = '0' + (exponent % 10);
107 exponent /= 10;
108 }
109 result_builder->AddSubstring(&buffer[first_char_pos],
110 kMaxExponentLength - first_char_pos);
111 }
112
113
114 void DoubleToStringConverter::CreateDecimalRepresentation(
115 const char* decima l_digits,
116 int length,
117 int decimal_point,
118 int digits_after_p oint,
119 StringBuilder* res ult_builder) const {
120 // Create a representation that is padded with zeros if needed.
121 if (decimal_point <= 0) {
122 // "0.00000decimal_rep".
123 result_builder->AddCharacter('0');
124 if (digits_after_point > 0) {
125 result_builder->AddCharacter('.');
126 result_builder->AddPadding('0', -decimal_point);
127 ASSERT(length <= digits_after_point - (-decimal_point));
128 result_builder->AddSubstring(decimal_digits, length);
129 int remaining_digits = digits_after_point - (-decimal_point) - l ength;
130 result_builder->AddPadding('0', remaining_digits);
131 }
132 } else if (decimal_point >= length) {
133 // "decimal_rep0000.00000" or "decimal_rep.0000"
134 result_builder->AddSubstring(decimal_digits, length);
135 result_builder->AddPadding('0', decimal_point - length);
136 if (digits_after_point > 0) {
137 result_builder->AddCharacter('.');
138 result_builder->AddPadding('0', digits_after_point);
139 }
140 } else {
141 // "decima.l_rep000"
142 ASSERT(digits_after_point > 0);
143 result_builder->AddSubstring(decimal_digits, decimal_point);
144 result_builder->AddCharacter('.');
145 ASSERT(length - decimal_point <= digits_after_point);
146 result_builder->AddSubstring(&decimal_digits[decimal_point],
147 length - decimal_point);
148 int remaining_digits = digits_after_point - (length - decimal_point) ;
149 result_builder->AddPadding('0', remaining_digits);
150 }
151 if (digits_after_point == 0) {
152 if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
153 result_builder->AddCharacter('.');
154 }
155 if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
156 result_builder->AddCharacter('0');
157 }
158 }
159 }
160
161
162 bool DoubleToStringConverter::ToShortest(double value,
163 StringBuilder* result_builder) cons t {
164 if (Double(value).IsSpecial()) {
165 return HandleSpecialValues(value, result_builder);
166 }
167
168 int decimal_point;
169 bool sign;
170 const int kDecimalRepCapacity = kBase10MaximalLength + 1;
171 char decimal_rep[kDecimalRepCapacity];
172 int decimal_rep_length;
173
174 DoubleToAscii(value, SHORTEST, 0, decimal_rep, kDecimalRepCapacity,
175 &sign, &decimal_rep_length, &decimal_point);
176
177 bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
178 if (sign && (value != 0.0 || !unique_zero)) {
179 result_builder->AddCharacter('-');
180 }
181
182 int exponent = decimal_point - 1;
183 if ((decimal_in_shortest_low_ <= exponent) &&
184 (exponent < decimal_in_shortest_high_)) {
185 CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
186 decimal_point,
187 Max(0, decimal_rep_length - decimal_poin t),
188 result_builder);
189 } else {
190 CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exp onent,
191 result_builder);
192 }
193 return true;
194 }
195
196
197 bool DoubleToStringConverter::ToFixed(double value,
198 int requested_digits,
199 StringBuilder* result_builder) const {
200 ASSERT(kMaxFixedDigitsBeforePoint == 60);
201 const double kFirstNonFixed = 1e60;
202
203 if (Double(value).IsSpecial()) {
204 return HandleSpecialValues(value, result_builder);
205 }
206
207 if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
208 if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
209
210 // Find a sufficiently precise decimal representation of n.
211 int decimal_point;
212 bool sign;
213 // Add space for the '\0' byte.
214 const int kDecimalRepCapacity =
215 kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;
216 char decimal_rep[kDecimalRepCapacity];
217 int decimal_rep_length;
218 DoubleToAscii(value, FIXED, requested_digits,
219 decimal_rep, kDecimalRepCapacity,
220 &sign, &decimal_rep_length, &decimal_point);
221
222 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
223 if (sign && (value != 0.0 || !unique_zero)) {
224 result_builder->AddCharacter('-');
225 }
226
227 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_poi nt,
228 requested_digits, result_builder);
229 return true;
230 }
231
232
233 bool DoubleToStringConverter::ToExponential(
234 double value,
235 int requested_digits,
236 StringBuilder* result_builder) c onst {
237 if (Double(value).IsSpecial()) {
238 return HandleSpecialValues(value, result_builder);
239 }
240
241 if (requested_digits < -1) return false;
242 if (requested_digits > kMaxExponentialDigits) return false;
243
244 int decimal_point;
245 bool sign;
246 // Add space for digit before the decimal point and the '\0' character.
247 const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
248 ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
249 char decimal_rep[kDecimalRepCapacity];
250 int decimal_rep_length;
251
252 if (requested_digits == -1) {
253 DoubleToAscii(value, SHORTEST, 0,
254 decimal_rep, kDecimalRepCapacity,
255 &sign, &decimal_rep_length, &decimal_point);
256 } else {
257 DoubleToAscii(value, PRECISION, requested_digits + 1,
258 decimal_rep, kDecimalRepCapacity,
259 &sign, &decimal_rep_length, &decimal_point);
260 ASSERT(decimal_rep_length <= requested_digits + 1);
261
262 for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
263 decimal_rep[i] = '0';
264 }
265 decimal_rep_length = requested_digits + 1;
266 }
267
268 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
269 if (sign && (value != 0.0 || !unique_zero)) {
270 result_builder->AddCharacter('-');
271 }
272
273 int exponent = decimal_point - 1;
274 CreateExponentialRepresentation(decimal_rep,
275 decimal_rep_length,
276 exponent,
277 result_builder);
278 return true;
279 }
280
281
282 bool DoubleToStringConverter::ToPrecision(double value,
283 int precision,
284 StringBuilder* result_builder) con st {
285 if (Double(value).IsSpecial()) {
286 return HandleSpecialValues(value, result_builder);
287 }
288
289 if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
290 return false;
291 }
292
293 // Find a sufficiently precise decimal representation of n.
294 int decimal_point;
295 bool sign;
296 // Add one for the terminating null character.
297 const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
298 char decimal_rep[kDecimalRepCapacity];
299 int decimal_rep_length;
300
301 DoubleToAscii(value, PRECISION, precision,
302 decimal_rep, kDecimalRepCapacity,
303 &sign, &decimal_rep_length, &decimal_point);
304 ASSERT(decimal_rep_length <= precision);
305
306 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
307 if (sign && (value != 0.0 || !unique_zero)) {
308 result_builder->AddCharacter('-');
309 }
310
311 // The exponent if we print the number as x.xxeyyy. That is with the
312 // decimal point after the first digit.
313 int exponent = decimal_point - 1;
314
315 int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
316 if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
317 (decimal_point - precision + extra_zero >
318 max_trailing_padding_zeroes_in_precision_mode_)) {
319 // Fill buffer to contain 'precision' digits.
320 // Usually the buffer is already at the correct length, but 'Dou bleToAscii'
321 // is allowed to return less characters.
322 for (int i = decimal_rep_length; i < precision; ++i) {
323 decimal_rep[i] = '0';
324 }
325
326 CreateExponentialRepresentation(decimal_rep,
327 precision,
328 exponent,
329 result_builder);
330 } else {
331 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, dec imal_point,
332 Max(0, precision - decimal_point),
333 result_builder);
334 }
335 return true;
336 }
337
338
339 static BignumDtoaMode DtoaToBignumDtoaMode(
340 DoubleToStringConverter::DtoaMode dtoa_mode) {
341 switch (dtoa_mode) {
342 case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST ;
343 case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED;
344 case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISIO N;
345 default:
346 UNREACHABLE();
347 return BIGNUM_DTOA_SHORTEST; // To silence compiler.
348 }
349 }
350
351
352 void DoubleToStringConverter::DoubleToAscii(double v,
353 DtoaMode mode,
354 int requested_digits,
355 char* buffer,
356 int buffer_length,
357 bool* sign,
358 int* length,
359 int* point) {
360 Vector<char> vector(buffer, buffer_length);
361 ASSERT(!Double(v).IsSpecial());
362 ASSERT(mode == SHORTEST || requested_digits >= 0);
363
364 if (Double(v).Sign() < 0) {
365 *sign = true;
366 v = -v;
367 } else {
368 *sign = false;
369 }
370
371 if (mode == PRECISION && requested_digits == 0) {
372 vector[0] = '\0';
373 *length = 0;
374 return;
375 }
376
377 if (v == 0) {
378 vector[0] = '0';
379 vector[1] = '\0';
380 *length = 1;
381 *point = 1;
382 return;
383 }
384
385 bool fast_worked;
386 switch (mode) {
387 case SHORTEST:
388 fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
389 break;
390 case FIXED:
391 fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
392 break;
393 case PRECISION:
394 fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
395 vector, length, point);
396 break;
397 default:
398 UNREACHABLE();
399 fast_worked = false;
400 }
401 if (fast_worked) return;
402
403 // If the fast dtoa didn't succeed use the slower bignum version.
404 BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
405 BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
406 vector[*length] = '\0';
407 }
408
409
410 // Maximum number of significant digits in decimal representation.
411 // The longest possible double in decimal representation is
412 // (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
413 // (768 digits). If we parse a number whose first digits are equal to a
414 // mean of 2 adjacent doubles (that could have up to 769 digits) the result
415 // must be rounded to the bigger one unless the tail consists of zeros, so
416 // we don't need to preserve all the digits.
417 const int kMaxSignificantDigits = 772;
418
419
420 static double SignedZero(bool sign) {
421 return sign ? -0.0 : 0.0;
422 }
423
424
425 double StringToDoubleConverter::StringToDouble(
426 const char* input,
427 size_t length,
428 size_t* processed_characters_ count) {
429 const char* current = input;
430 const char* end = input + length;
431
432 *processed_characters_count = 0;
433
434 // To make sure that iterator dereferencing is valid the following
435 // convention is used:
436 // 1. Each '++current' statement is followed by check for equality to 'e nd'.
437 // 3. If 'current' becomes equal to 'end' the function returns or goes t o
438 // 'parsing_done'.
439 // 4. 'current' is not dereferenced after the 'parsing_done' label.
440 // 5. Code before 'parsing_done' may rely on 'current != end'.
441 if (current == end) return 0.0;
442
443 // The longest form of simplified number is: "-<significant digits>.1eXX X\0".
444 const int kBufferSize = kMaxSignificantDigits + 10;
445 char buffer[kBufferSize]; // NOLINT: size is known at compile time.
446 int buffer_pos = 0;
447
448 // Exponent will be adjusted if insignificant digits of the integer part
449 // or insignificant leading zeros of the fractional part are dropped.
450 int exponent = 0;
451 int significant_digits = 0;
452 int insignificant_digits = 0;
453 bool nonzero_digit_dropped = false;
454 bool sign = false;
455
456 if (*current == '+' || *current == '-') {
457 sign = (*current == '-');
458 ++current;
459 if (current == end) return 0.0;
460 }
461
462 bool leading_zero = false;
463 if (*current == '0') {
464 ++current;
465 if (current == end) {
466 *processed_characters_count = current - input;
467 return SignedZero(sign);
468 }
469
470 leading_zero = true;
471
472 // Ignore leading zeros in the integer part.
473 while (*current == '0') {
474 ++current;
475 if (current == end) {
476 *processed_characters_count = current - input;
477 return SignedZero(sign);
478 }
479 }
480 }
481
482 // Copy significant digits of the integer part (if any) to the buffer.
483 while (*current >= '0' && *current <= '9') {
484 if (significant_digits < kMaxSignificantDigits) {
485 ASSERT(buffer_pos < kBufferSize);
486 buffer[buffer_pos++] = static_cast<char>(*current);
487 significant_digits++;
488 } else {
489 insignificant_digits++; // Move the digit into the exponential part.
490 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0' ;
491 }
492 ++current;
493 if (current == end) goto parsing_done;
494 }
495
496 if (*current == '.') {
497 ++current;
498 if (current == end) {
499 if (significant_digits == 0 && !leading_zero) {
500 return 0.0;
501 } else {
502 goto parsing_done;
503 }
504 }
505
506 if (significant_digits == 0) {
507 // Integer part consists of 0 or is absent. Significant digits s tart after
508 // leading zeros (if any).
509 while (*current == '0') {
510 ++current;
511 if (current == end) {
512 *processed_characters_count = current - input;
513 return SignedZero(sign);
514 }
515 exponent--; // Move this 0 into the exponent.
516 }
517 }
518
519 // There is a fractional part.
520 while (*current >= '0' && *current <= '9') {
521 if (significant_digits < kMaxSignificantDigits) {
522 ASSERT(buffer_pos < kBufferSize);
523 buffer[buffer_pos++] = static_cast<char>(*current);
524 significant_digits++;
525 exponent--;
526 } else {
527 // Ignore insignificant digits in the fractional part.
528 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
529 }
530 ++current;
531 if (current == end) goto parsing_done;
532 }
533 }
534
535 if (!leading_zero && exponent == 0 && significant_digits == 0) {
536 // If leading_zeros is true then the string contains zeros.
537 // If exponent < 0 then string was [+-]\.0*...
538 // If significant_digits != 0 the string is not equal to 0.
539 // Otherwise there are no digits in the string.
540 return 0.0;
541 }
542
543 // Parse exponential part.
544 if (*current == 'e' || *current == 'E') {
545 ++current;
546 if (current == end) {
547 --current;
548 goto parsing_done;
549 }
550 char sign = 0;
551 if (*current == '+' || *current == '-') {
552 sign = static_cast<char>(*current);
553 ++current;
554 if (current == end) {
555 current -= 2;
556 goto parsing_done;
557 }
558 }
559
560 if (*current < '0' || *current > '9') {
561 if (sign)
562 --current;
563 --current;
564 goto parsing_done;
565 }
566
567 const int max_exponent = INT_MAX / 2;
568 ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2 );
569 int num = 0;
570 do {
571 // Check overflow.
572 int digit = *current - '0';
573 if (num >= max_exponent / 10
574 && !(num == max_exponent / 10 && digit <= max_exponent % 10) ) {
575 num = max_exponent;
576 } else {
577 num = num * 10 + digit;
578 }
579 ++current;
580 } while (current != end && *current >= '0' && *current <= '9');
581
582 exponent += (sign == '-' ? -num : num);
583 }
584
585 parsing_done:
586 exponent += insignificant_digits;
587
588 if (nonzero_digit_dropped) {
589 buffer[buffer_pos++] = '1';
590 exponent--;
591 }
592
593 ASSERT(buffer_pos < kBufferSize);
594 buffer[buffer_pos] = '\0';
595
596 double converted = Strtod(Vector<const char>(buffer, buffer_pos), expone nt);
597 *processed_characters_count = current - input;
598 return sign? -converted: converted;
599 }
600
601 } // namespace double_conversion
602
603 } // namespace WTF
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/wtf/dtoa/double-conversion.h ('k') | third_party/WebKit/Source/wtf/dtoa/fast-dtoa.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698