OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/conversions.h" | 5 #include "src/conversions.h" |
6 | 6 |
7 #include <limits.h> | 7 #include <limits.h> |
8 #include <stdarg.h> | 8 #include <stdarg.h> |
9 #include <cmath> | 9 #include <cmath> |
10 | 10 |
| 11 #include "src/allocation.h" |
11 #include "src/assert-scope.h" | 12 #include "src/assert-scope.h" |
12 #include "src/char-predicates-inl.h" | 13 #include "src/char-predicates-inl.h" |
13 #include "src/codegen.h" | 14 #include "src/codegen.h" |
14 #include "src/conversions-inl.h" | 15 #include "src/conversions-inl.h" |
15 #include "src/dtoa.h" | 16 #include "src/dtoa.h" |
16 #include "src/factory.h" | 17 #include "src/factory.h" |
17 #include "src/list-inl.h" | 18 #include "src/list-inl.h" |
18 #include "src/strtod.h" | 19 #include "src/strtod.h" |
19 #include "src/utils.h" | 20 #include "src/utils.h" |
20 | 21 |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 if (length != 1) { | 162 if (length != 1) { |
162 builder.AddCharacter('.'); | 163 builder.AddCharacter('.'); |
163 builder.AddString(decimal_rep + 1); | 164 builder.AddString(decimal_rep + 1); |
164 } | 165 } |
165 builder.AddCharacter('e'); | 166 builder.AddCharacter('e'); |
166 builder.AddCharacter((decimal_point >= 0) ? '+' : '-'); | 167 builder.AddCharacter((decimal_point >= 0) ? '+' : '-'); |
167 int exponent = decimal_point - 1; | 168 int exponent = decimal_point - 1; |
168 if (exponent < 0) exponent = -exponent; | 169 if (exponent < 0) exponent = -exponent; |
169 builder.AddDecimalInteger(exponent); | 170 builder.AddDecimalInteger(exponent); |
170 } | 171 } |
171 return builder.Finalize(); | 172 return builder.Finalize(); |
172 } | 173 } |
173 } | 174 } |
174 } | 175 } |
175 | 176 |
176 | 177 |
177 const char* IntToCString(int n, Vector<char> buffer) { | 178 const char* IntToCString(int n, Vector<char> buffer) { |
178 bool negative = false; | 179 bool negative = false; |
179 if (n < 0) { | 180 if (n < 0) { |
180 // We must not negate the most negative int. | 181 // We must not negate the most negative int. |
181 if (n == kMinInt) return DoubleToCString(n, buffer); | 182 if (n == kMinInt) return DoubleToCString(n, buffer); |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 } | 405 } |
405 builder.AddPadding('0', extra + (p - builder.position())); | 406 builder.AddPadding('0', extra + (p - builder.position())); |
406 } | 407 } |
407 } | 408 } |
408 result = builder.Finalize(); | 409 result = builder.Finalize(); |
409 } | 410 } |
410 | 411 |
411 return result; | 412 return result; |
412 } | 413 } |
413 | 414 |
| 415 char* DoubleToRadixCString(double value, int radix) { |
| 416 DCHECK(radix >= 2 && radix <= 36); |
| 417 DCHECK(std::isfinite(value)); |
| 418 DCHECK_NE(0.0, value); |
| 419 // Character array used for conversion. |
| 420 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; |
| 421 |
| 422 // Temporary buffer for the result. We start with the decimal point in the |
| 423 // middle and write to the left for the integer part and to the right for the |
| 424 // fractional part. 1024 characters either way with additional space for sign |
| 425 // and decimal point should be sufficient. |
| 426 static const int kBufferSize = 2100; |
| 427 char buffer[kBufferSize]; |
| 428 int integer_cursor = kBufferSize / 2; |
| 429 int fraction_cursor = integer_cursor; |
| 430 |
| 431 bool negative = value < 0; |
| 432 if (negative) value = -value; |
| 433 |
| 434 // Split the value into an integer part and a fractional part. |
| 435 double integer = std::floor(value); |
| 436 double fraction = value - integer; |
| 437 // We only compute fractional digits up to the input double's precision. |
| 438 double delta = 0.5 * (Double(value).NextDouble() - value); |
| 439 if (fraction > delta) { |
| 440 // Insert decimal point. |
| 441 buffer[fraction_cursor++] = '.'; |
| 442 do { |
| 443 // Shift up by one digit. |
| 444 fraction *= radix; |
| 445 delta *= radix; |
| 446 // Write digit. |
| 447 int digit = static_cast<int>(fraction); |
| 448 buffer[fraction_cursor++] = chars[digit]; |
| 449 // Calculate remainder. |
| 450 fraction -= digit; |
| 451 // Round to even. |
| 452 if (fraction > 0.5 || (fraction == 0.5 && (digit & 1))) { |
| 453 if (fraction + delta > 1) { |
| 454 // We need to back trace already written digits in case of carry-over. |
| 455 while (true) { |
| 456 fraction_cursor--; |
| 457 if (fraction_cursor == kBufferSize / 2) { |
| 458 CHECK_EQ('.', buffer[fraction_cursor]); |
| 459 // Carry over to the integer part. |
| 460 integer += 1; |
| 461 break; |
| 462 } |
| 463 char c = buffer[fraction_cursor]; |
| 464 // Reconstruct digit. |
| 465 int digit = c > '9' ? (c - 'a' + 10) : (c - '0'); |
| 466 if (digit + 1 < radix) { |
| 467 buffer[fraction_cursor++] = chars[digit + 1]; |
| 468 break; |
| 469 } |
| 470 } |
| 471 break; |
| 472 } |
| 473 } |
| 474 } while (fraction > delta); |
| 475 } |
| 476 |
| 477 // Compute integer digits. |
| 478 do { |
| 479 double multiple = std::floor(integer / radix); |
| 480 int digit = static_cast<int>(integer - multiple * radix); |
| 481 buffer[--integer_cursor] = chars[digit]; |
| 482 integer = multiple; |
| 483 } while (integer > 0); |
| 484 |
| 485 // Add sign and terminate string. |
| 486 if (negative) buffer[--integer_cursor] = '-'; |
| 487 buffer[fraction_cursor++] = '\0'; |
| 488 // Allocate new string as return value. |
| 489 char* result = NewArray<char>(fraction_cursor - integer_cursor); |
| 490 memcpy(result, buffer + integer_cursor, fraction_cursor - integer_cursor); |
| 491 return result; |
| 492 } |
| 493 |
414 | 494 |
415 char* DoubleToRadixCString(double value, int radix) { | |
416 DCHECK(radix >= 2 && radix <= 36); | |
417 | |
418 // Character array used for conversion. | |
419 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; | |
420 | |
421 // Buffer for the integer part of the result. 1024 chars is enough | |
422 // for max integer value in radix 2. We need room for a sign too. | |
423 static const int kBufferSize = 1100; | |
424 char integer_buffer[kBufferSize]; | |
425 integer_buffer[kBufferSize - 1] = '\0'; | |
426 | |
427 // Buffer for the decimal part of the result. We only generate up | |
428 // to kBufferSize - 1 chars for the decimal part. | |
429 char decimal_buffer[kBufferSize]; | |
430 decimal_buffer[kBufferSize - 1] = '\0'; | |
431 | |
432 // Make sure the value is positive. | |
433 bool is_negative = value < 0.0; | |
434 if (is_negative) value = -value; | |
435 | |
436 // Get the integer part and the decimal part. | |
437 double integer_part = std::floor(value); | |
438 double decimal_part = value - integer_part; | |
439 | |
440 // Convert the integer part starting from the back. Always generate | |
441 // at least one digit. | |
442 int integer_pos = kBufferSize - 2; | |
443 do { | |
444 double remainder = modulo(integer_part, radix); | |
445 integer_buffer[integer_pos--] = chars[static_cast<int>(remainder)]; | |
446 integer_part -= remainder; | |
447 integer_part /= radix; | |
448 } while (integer_part >= 1.0); | |
449 // Sanity check. | |
450 DCHECK(integer_pos > 0); | |
451 // Add sign if needed. | |
452 if (is_negative) integer_buffer[integer_pos--] = '-'; | |
453 | |
454 // Convert the decimal part. Repeatedly multiply by the radix to | |
455 // generate the next char. Never generate more than kBufferSize - 1 | |
456 // chars. | |
457 // | |
458 // TODO(1093998): We will often generate a full decimal_buffer of | |
459 // chars because hitting zero will often not happen. The right | |
460 // solution would be to continue until the string representation can | |
461 // be read back and yield the original value. To implement this | |
462 // efficiently, we probably have to modify dtoa. | |
463 int decimal_pos = 0; | |
464 while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) { | |
465 decimal_part *= radix; | |
466 decimal_buffer[decimal_pos++] = | |
467 chars[static_cast<int>(std::floor(decimal_part))]; | |
468 decimal_part -= std::floor(decimal_part); | |
469 } | |
470 decimal_buffer[decimal_pos] = '\0'; | |
471 | |
472 // Compute the result size. | |
473 int integer_part_size = kBufferSize - 2 - integer_pos; | |
474 // Make room for zero termination. | |
475 unsigned result_size = integer_part_size + decimal_pos; | |
476 // If the number has a decimal part, leave room for the period. | |
477 if (decimal_pos > 0) result_size++; | |
478 // Allocate result and fill in the parts. | |
479 SimpleStringBuilder builder(result_size + 1); | |
480 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); | |
481 if (decimal_pos > 0) builder.AddCharacter('.'); | |
482 builder.AddSubstring(decimal_buffer, decimal_pos); | |
483 return builder.Finalize(); | |
484 } | |
485 | |
486 | |
487 // ES6 18.2.4 parseFloat(string) | 495 // ES6 18.2.4 parseFloat(string) |
488 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string, | 496 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string, |
489 int flags, double empty_string_val) { | 497 int flags, double empty_string_val) { |
490 Handle<String> flattened = String::Flatten(string); | 498 Handle<String> flattened = String::Flatten(string); |
491 { | 499 { |
492 DisallowHeapAllocation no_gc; | 500 DisallowHeapAllocation no_gc; |
493 String::FlatContent flat = flattened->GetFlatContent(); | 501 String::FlatContent flat = flattened->GetFlatContent(); |
494 DCHECK(flat.IsFlat()); | 502 DCHECK(flat.IsFlat()); |
495 if (flat.IsOneByte()) { | 503 if (flat.IsOneByte()) { |
496 return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags, | 504 return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated. | 563 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated. |
556 Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer)); | 564 Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer)); |
557 const char* reverse_string = DoubleToCString(d, reverse_vector); | 565 const char* reverse_string = DoubleToCString(d, reverse_vector); |
558 for (int i = 0; i < length; ++i) { | 566 for (int i = 0; i < length; ++i) { |
559 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false; | 567 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false; |
560 } | 568 } |
561 return true; | 569 return true; |
562 } | 570 } |
563 } // namespace internal | 571 } // namespace internal |
564 } // namespace v8 | 572 } // namespace v8 |
OLD | NEW |