| Index: src/conversions.cc
|
| diff --git a/src/conversions.cc b/src/conversions.cc
|
| index 7867719968d2f89e279dc9632d1c0341d02202fb..fb09d18a407f6780283e2b8bdcc468015a747884 100644
|
| --- a/src/conversions.cc
|
| +++ b/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,83 @@ 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 either way with additional space for sign
|
| + // and decimal point should be sufficient.
|
| + static const int kBufferSize = 2100;
|
| + 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);
|
| + 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;
|
| + // Compute integer digits.
|
| 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);
|
| - }
|
| - 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();
|
| + double multiple = std::floor(integer / radix);
|
| + int digit = static_cast<int>(integer - multiple * radix);
|
| + buffer[--integer_cursor] = chars[digit];
|
| + integer = multiple;
|
| + } while (integer > 0);
|
| +
|
| + // Add sign and terminate string.
|
| + if (negative) buffer[--integer_cursor] = '-';
|
| + buffer[fraction_cursor++] = '\0';
|
| + // 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;
|
| }
|
|
|
|
|
|
|