Chromium Code Reviews| 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 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 407 } | 408 } |
| 408 result = builder.Finalize(); | 409 result = builder.Finalize(); |
| 409 } | 410 } |
| 410 | 411 |
| 411 return result; | 412 return result; |
| 412 } | 413 } |
| 413 | 414 |
| 414 | 415 |
| 415 char* DoubleToRadixCString(double value, int radix) { | 416 char* DoubleToRadixCString(double value, int radix) { |
| 416 DCHECK(radix >= 2 && radix <= 36); | 417 DCHECK(radix >= 2 && radix <= 36); |
| 418 DCHECK(std::isfinite(value)); | |
| 419 DCHECK_NE(0.0, value); | |
| 417 | 420 |
| 418 // Character array used for conversion. | 421 // Character array used for conversion. |
| 419 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; | 422 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; |
| 420 | 423 |
| 421 // Buffer for the integer part of the result. 1024 chars is enough | 424 // 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. | 425 // for max integer value in radix 2. We need room for a sign too. |
| 423 static const int kBufferSize = 1100; | 426 static const int kBufferSize = 1100; |
| 424 char integer_buffer[kBufferSize]; | 427 char buffer[kBufferSize]; |
| 425 integer_buffer[kBufferSize - 1] = '\0'; | 428 int cursor = kBufferSize; |
| 429 buffer[--cursor] = '\0'; | |
| 430 bool negative = value < 0; | |
| 431 if (negative) value = -value; | |
| 426 | 432 |
| 427 // Buffer for the decimal part of the result. We only generate up | 433 // Shift the number by power of the radix until we can represent it |
| 428 // to kBufferSize - 1 chars for the decimal part. | 434 // in its full precision as an uint64_t. |
| 429 char decimal_buffer[kBufferSize]; | 435 int decimal_point_shift = 0; |
| 430 decimal_buffer[kBufferSize - 1] = '\0'; | 436 if (Double(value).Exponent() < 0) { |
| 437 while (Double(value).Exponent() < 0) { | |
| 438 value *= radix; | |
| 439 decimal_point_shift--; | |
| 440 } | |
| 441 } else { | |
| 442 while (Double(value / radix).Exponent() > 0) { | |
| 443 value /= radix; | |
| 444 // Insert trailing zeros. | |
| 445 buffer[--cursor] = '0'; | |
| 446 } | |
| 447 } | |
| 431 | 448 |
| 432 // Make sure the value is positive. | 449 // Construct string from right to left (least significant to most). |
| 433 bool is_negative = value < 0.0; | 450 uint64_t int_value = static_cast<uint64_t>(value); |
|
Tobias Tebbi
2016/11/22 18:46:54
(2/7).toString(3) gives "0.02120102120102120102120
| |
| 434 if (is_negative) value = -value; | 451 while (decimal_point_shift < 0) { |
| 452 uint64_t multiple = int_value / radix; | |
| 453 uint64_t remainder = int_value - multiple * radix; | |
| 454 // Skip trailing zeros after the decimal point. | |
| 455 if (remainder > 0) { | |
| 456 // Compute digits up to decimal point. | |
| 457 while (decimal_point_shift < 0) { | |
| 458 uint64_t multiple = int_value / radix; | |
| 459 uint64_t remainder = int_value - multiple * radix; | |
| 460 buffer[--cursor] = chars[remainder]; | |
| 461 int_value = multiple; | |
| 462 decimal_point_shift++; | |
| 463 } | |
| 464 // Insert decimal point if there have been fractional digits. | |
| 465 if (decimal_point_shift == 0) buffer[--cursor] = '.'; | |
| 466 break; | |
| 467 } | |
| 468 int_value = multiple; | |
| 469 decimal_point_shift++; | |
| 470 } | |
| 471 // Compute integer digits. | |
| 472 do { | |
| 473 uint64_t multiple = int_value / radix; | |
| 474 uint64_t remainder = int_value - multiple * radix; | |
| 475 buffer[--cursor] = chars[remainder]; | |
| 476 int_value = multiple; | |
| 477 } while (int_value > 0); | |
| 435 | 478 |
| 436 // Get the integer part and the decimal part. | 479 if (negative) buffer[--cursor] = '-'; |
| 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. | 480 // Allocate result and fill in the parts. |
| 479 SimpleStringBuilder builder(result_size + 1); | 481 char* result = NewArray<char>(kBufferSize - cursor); |
| 480 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); | 482 memcpy(result, buffer + cursor, kBufferSize - cursor); |
| 481 if (decimal_pos > 0) builder.AddCharacter('.'); | 483 return result; |
| 482 builder.AddSubstring(decimal_buffer, decimal_pos); | |
| 483 return builder.Finalize(); | |
| 484 } | 484 } |
| 485 | 485 |
| 486 | 486 |
| 487 // ES6 18.2.4 parseFloat(string) | 487 // ES6 18.2.4 parseFloat(string) |
| 488 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string, | 488 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string, |
| 489 int flags, double empty_string_val) { | 489 int flags, double empty_string_val) { |
| 490 Handle<String> flattened = String::Flatten(string); | 490 Handle<String> flattened = String::Flatten(string); |
| 491 { | 491 { |
| 492 DisallowHeapAllocation no_gc; | 492 DisallowHeapAllocation no_gc; |
| 493 String::FlatContent flat = flattened->GetFlatContent(); | 493 String::FlatContent flat = flattened->GetFlatContent(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 555 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated. | 555 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated. |
| 556 Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer)); | 556 Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer)); |
| 557 const char* reverse_string = DoubleToCString(d, reverse_vector); | 557 const char* reverse_string = DoubleToCString(d, reverse_vector); |
| 558 for (int i = 0; i < length; ++i) { | 558 for (int i = 0; i < length; ++i) { |
| 559 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false; | 559 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false; |
| 560 } | 560 } |
| 561 return true; | 561 return true; |
| 562 } | 562 } |
| 563 } // namespace internal | 563 } // namespace internal |
| 564 } // namespace v8 | 564 } // namespace v8 |
| OLD | NEW |