Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Unified Diff: src/conversions.cc

Issue 2520363002: Reimplement Number.prototype.toString with non-default radix. (Closed)
Patch Set: readd copyright headers Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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;
}

Powered by Google App Engine
This is Rietveld 408576698