diff options
Diffstat (limited to 'deps/v8/src/conversions.cc')
-rw-r--r-- | deps/v8/src/conversions.cc | 144 |
1 files changed, 80 insertions, 64 deletions
diff --git a/deps/v8/src/conversions.cc b/deps/v8/src/conversions.cc index 7867719968..2d4aaa0692 100644 --- a/deps/v8/src/conversions.cc +++ b/deps/v8/src/conversions.cc @@ -8,6 +8,7 @@ #include <stdarg.h> #include <cmath> +#include "src/allocation.h" #include "src/assert-scope.h" #include "src/char-predicates-inl.h" #include "src/codegen.h" @@ -168,7 +169,7 @@ const char* DoubleToCString(double v, Vector<char> buffer) { if (exponent < 0) exponent = -exponent; builder.AddDecimalInteger(exponent); } - return builder.Finalize(); + return builder.Finalize(); } } } @@ -411,76 +412,91 @@ char* DoubleToPrecisionCString(double value, int p) { return result; } - char* DoubleToRadixCString(double value, int radix) { DCHECK(radix >= 2 && radix <= 36); - + DCHECK(std::isfinite(value)); + DCHECK_NE(0.0, value); // Character array used for conversion. static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - // Buffer for the integer part of the result. 1024 chars is enough - // for max integer value in radix 2. We need room for a sign too. - static const int kBufferSize = 1100; - char integer_buffer[kBufferSize]; - integer_buffer[kBufferSize - 1] = '\0'; - - // Buffer for the decimal part of the result. We only generate up - // to kBufferSize - 1 chars for the decimal part. - char decimal_buffer[kBufferSize]; - decimal_buffer[kBufferSize - 1] = '\0'; - - // Make sure the value is positive. - bool is_negative = value < 0.0; - if (is_negative) value = -value; - - // Get the integer part and the decimal part. - double integer_part = std::floor(value); - double decimal_part = value - integer_part; + // Temporary buffer for the result. We start with the decimal point in the + // middle and write to the left for the integer part and to the right for the + // fractional part. 1024 characters for the exponent and 52 for the mantissa + // either way, with additional space for sign, decimal point and string + // termination should be sufficient. + static const int kBufferSize = 2200; + char buffer[kBufferSize]; + int integer_cursor = kBufferSize / 2; + int fraction_cursor = integer_cursor; + + bool negative = value < 0; + if (negative) value = -value; + + // Split the value into an integer part and a fractional part. + double integer = std::floor(value); + double fraction = value - integer; + // We only compute fractional digits up to the input double's precision. + double delta = 0.5 * (Double(value).NextDouble() - value); + delta = std::max(Double(0.0).NextDouble(), delta); + DCHECK_GT(delta, 0.0); + if (fraction > delta) { + // Insert decimal point. + buffer[fraction_cursor++] = '.'; + do { + // Shift up by one digit. + fraction *= radix; + delta *= radix; + // Write digit. + int digit = static_cast<int>(fraction); + buffer[fraction_cursor++] = chars[digit]; + // Calculate remainder. + fraction -= digit; + // Round to even. + if (fraction > 0.5 || (fraction == 0.5 && (digit & 1))) { + if (fraction + delta > 1) { + // We need to back trace already written digits in case of carry-over. + while (true) { + fraction_cursor--; + if (fraction_cursor == kBufferSize / 2) { + CHECK_EQ('.', buffer[fraction_cursor]); + // Carry over to the integer part. + integer += 1; + break; + } + char c = buffer[fraction_cursor]; + // Reconstruct digit. + int digit = c > '9' ? (c - 'a' + 10) : (c - '0'); + if (digit + 1 < radix) { + buffer[fraction_cursor++] = chars[digit + 1]; + break; + } + } + break; + } + } + } while (fraction > delta); + } - // Convert the integer part starting from the back. Always generate - // at least one digit. - int integer_pos = kBufferSize - 2; - do { - double remainder = modulo(integer_part, radix); - integer_buffer[integer_pos--] = chars[static_cast<int>(remainder)]; - integer_part -= remainder; - integer_part /= radix; - } while (integer_part >= 1.0); - // Sanity check. - DCHECK(integer_pos > 0); - // Add sign if needed. - if (is_negative) integer_buffer[integer_pos--] = '-'; - - // Convert the decimal part. Repeatedly multiply by the radix to - // generate the next char. Never generate more than kBufferSize - 1 - // chars. - // - // TODO(1093998): We will often generate a full decimal_buffer of - // chars because hitting zero will often not happen. The right - // solution would be to continue until the string representation can - // be read back and yield the original value. To implement this - // efficiently, we probably have to modify dtoa. - int decimal_pos = 0; - while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) { - decimal_part *= radix; - decimal_buffer[decimal_pos++] = - chars[static_cast<int>(std::floor(decimal_part))]; - decimal_part -= std::floor(decimal_part); + // Compute integer digits. Fill unrepresented digits with zero. + while (Double(integer / radix).Exponent() > 0) { + integer /= radix; + buffer[--integer_cursor] = '0'; } - decimal_buffer[decimal_pos] = '\0'; - - // Compute the result size. - int integer_part_size = kBufferSize - 2 - integer_pos; - // Make room for zero termination. - unsigned result_size = integer_part_size + decimal_pos; - // If the number has a decimal part, leave room for the period. - if (decimal_pos > 0) result_size++; - // Allocate result and fill in the parts. - SimpleStringBuilder builder(result_size + 1); - builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); - if (decimal_pos > 0) builder.AddCharacter('.'); - builder.AddSubstring(decimal_buffer, decimal_pos); - return builder.Finalize(); + do { + double remainder = modulo(integer, radix); + buffer[--integer_cursor] = chars[static_cast<int>(remainder)]; + integer = (integer - remainder) / radix; + } while (integer > 0); + + // Add sign and terminate string. + if (negative) buffer[--integer_cursor] = '-'; + buffer[fraction_cursor++] = '\0'; + DCHECK_LT(fraction_cursor, kBufferSize); + DCHECK_LE(0, integer_cursor); + // Allocate new string as return value. + char* result = NewArray<char>(fraction_cursor - integer_cursor); + memcpy(result, buffer + integer_cursor, fraction_cursor - integer_cursor); + return result; } |