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 |