Commit 7ac932c0 authored by floitschV8@gmail.com's avatar floitschV8@gmail.com

Add bignum fall-back when the fast dtoa doesn't succeed. This removes Gay's...

Add bignum fall-back when the fast dtoa doesn't succeed. This removes Gay's dtoa for the double->string direction. We still need it for the string->double direction.
Review URL: http://codereview.chromium.org/3468003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5840 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a298666f
......@@ -41,6 +41,7 @@ SOURCES = {
assembler.cc
ast.cc
bignum.cc
bignum-dtoa.cc
bootstrapper.cc
builtins.cc
cached-powers.cc
......
This diff is collapsed.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_BIGNUM_DTOA_H_
#define V8_BIGNUM_DTOA_H_
namespace v8 {
namespace internal {
enum BignumDtoaMode {
// Return the shortest correct representation.
// For example the output of 0.299999999999999988897 is (the less accurate but
// correct) 0.3.
BIGNUM_DTOA_SHORTEST,
// Return a fixed number of digits after the decimal point.
// For instance fixed(0.1, 4) becomes 0.1000
// If the input number is big, the output will be big.
BIGNUM_DTOA_FIXED,
// Return a fixed number of digits, no matter what the exponent is.
BIGNUM_DTOA_PRECISION
};
// Converts the given double 'v' to ascii.
// The result should be interpreted as buffer * 10^(point-length).
// The buffer will be null-terminated.
//
// The input v must be > 0 and different from NaN, and Infinity.
//
// The output depends on the given mode:
// - SHORTEST: produce the least amount of digits for which the internal
// identity requirement is still satisfied. If the digits are printed
// (together with the correct exponent) then reading this number will give
// 'v' again. The buffer will choose the representation that is closest to
// 'v'. If there are two at the same distance, than the number is round up.
// In this mode the 'requested_digits' parameter is ignored.
// - FIXED: produces digits necessary to print a given number with
// 'requested_digits' digits after the decimal point. The produced digits
// might be too short in which case the caller has to fill the gaps with '0's.
// Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
// Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
// buffer="2", point=0.
// Note: the length of the returned buffer has no meaning wrt the significance
// of its digits. That is, just because it contains '0's does not mean that
// any other digit would not satisfy the internal identity requirement.
// - PRECISION: produces 'requested_digits' where the first digit is not '0'.
// Even though the length of produced digits usually equals
// 'requested_digits', the function is allowed to return fewer digits, in
// which case the caller has to fill the missing digits with '0's.
// Halfway cases are again rounded up.
// 'BignumDtoa' expects the given buffer to be big enough to hold all digits
// and a terminating null-character.
void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
Vector<char> buffer, int* length, int* point);
} } // namespace v8::internal
#endif // V8_BIGNUM_DTOA_H_
......@@ -654,7 +654,7 @@ static double InternalStringToDouble(Iterator current,
buffer[buffer_pos] = '\0';
double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
return sign? -converted: converted;
return sign ? -converted : converted;
}
......@@ -711,11 +711,6 @@ double StringToDouble(Vector<const char> str,
}
extern "C" char* dtoa(double d, int mode, int ndigits,
int* decpt, int* sign, char** rve);
extern "C" void freedtoa(char* s);
const char* DoubleToCString(double v, Vector<char> buffer) {
StringBuilder builder(buffer.start(), buffer.length());
......@@ -739,21 +734,13 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
default: {
int decimal_point;
int sign;
char* decimal_rep;
bool used_gay_dtoa = false;
const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1;
char v8_dtoa_buffer[kV8DtoaBufferCapacity];
char decimal_rep[kV8DtoaBufferCapacity];
int length;
if (DoubleToAscii(v, DTOA_SHORTEST, 0,
Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
&sign, &length, &decimal_point)) {
decimal_rep = v8_dtoa_buffer;
} else {
decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
used_gay_dtoa = true;
length = StrLength(decimal_rep);
}
DoubleToAscii(v, DTOA_SHORTEST, 0,
Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
&sign, &length, &decimal_point);
if (sign) builder.AddCharacter('-');
......@@ -787,8 +774,6 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
if (exponent < 0) exponent = -exponent;
builder.AddFormatted("%d", exponent);
}
if (used_gay_dtoa) freedtoa(decimal_rep);
}
}
return builder.Finalize();
......@@ -845,11 +830,9 @@ char* DoubleToFixedCString(double value, int f) {
kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
char decimal_rep[kDecimalRepCapacity];
int decimal_rep_length;
bool status = DoubleToAscii(value, DTOA_FIXED, f,
Vector<char>(decimal_rep, kDecimalRepCapacity),
&sign, &decimal_rep_length, &decimal_point);
USE(status);
ASSERT(status);
DoubleToAscii(value, DTOA_FIXED, f,
Vector<char>(decimal_rep, kDecimalRepCapacity),
&sign, &decimal_rep_length, &decimal_point);
// Create a representation that is padded with zeros if needed.
int zero_prefix_length = 0;
......@@ -935,8 +918,6 @@ char* DoubleToExponentialCString(double value, int f) {
// Find a sufficiently precise decimal representation of n.
int decimal_point;
int sign;
char* decimal_rep = NULL;
bool used_gay_dtoa = false;
// f corresponds to the digits after the point. There is always one digit
// before the point. The number of requested_digits equals hence f + 1.
// And we have to add one character for the null-terminator.
......@@ -944,31 +925,18 @@ char* DoubleToExponentialCString(double value, int f) {
// Make sure that the buffer is big enough, even if we fall back to the
// shortest representation (which happens when f equals -1).
ASSERT(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1);
char v8_dtoa_buffer[kV8DtoaBufferCapacity];
char decimal_rep[kV8DtoaBufferCapacity];
int decimal_rep_length;
if (f == -1) {
if (DoubleToAscii(value, DTOA_SHORTEST, 0,
Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point)) {
f = decimal_rep_length - 1;
decimal_rep = v8_dtoa_buffer;
} else {
decimal_rep = dtoa(value, 0, 0, &decimal_point, &sign, NULL);
decimal_rep_length = StrLength(decimal_rep);
f = decimal_rep_length - 1;
used_gay_dtoa = true;
}
DoubleToAscii(value, DTOA_SHORTEST, 0,
Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point);
f = decimal_rep_length - 1;
} else {
if (DoubleToAscii(value, DTOA_PRECISION, f + 1,
Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point)) {
decimal_rep = v8_dtoa_buffer;
} else {
decimal_rep = dtoa(value, 2, f + 1, &decimal_point, &sign, NULL);
decimal_rep_length = StrLength(decimal_rep);
used_gay_dtoa = true;
}
DoubleToAscii(value, DTOA_PRECISION, f + 1,
Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point);
}
ASSERT(decimal_rep_length > 0);
ASSERT(decimal_rep_length <= f + 1);
......@@ -977,10 +945,6 @@ char* DoubleToExponentialCString(double value, int f) {
char* result =
CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
if (used_gay_dtoa) {
freedtoa(decimal_rep);
}
return result;
}
......@@ -1000,22 +964,14 @@ char* DoubleToPrecisionCString(double value, int p) {
// Find a sufficiently precise decimal representation of n.
int decimal_point;
int sign;
char* decimal_rep = NULL;
bool used_gay_dtoa = false;
// Add one for the terminating null character.
const int kV8DtoaBufferCapacity = kMaximalDigits + 1;
char v8_dtoa_buffer[kV8DtoaBufferCapacity];
char decimal_rep[kV8DtoaBufferCapacity];
int decimal_rep_length;
if (DoubleToAscii(value, DTOA_PRECISION, p,
Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point)) {
decimal_rep = v8_dtoa_buffer;
} else {
decimal_rep = dtoa(value, 2, p, &decimal_point, &sign, NULL);
decimal_rep_length = StrLength(decimal_rep);
used_gay_dtoa = true;
}
DoubleToAscii(value, DTOA_PRECISION, p,
Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point);
ASSERT(decimal_rep_length <= p);
int exponent = decimal_point - 1;
......@@ -1059,9 +1015,6 @@ char* DoubleToPrecisionCString(double value, int p) {
result = builder.Finalize();
}
if (used_gay_dtoa) {
freedtoa(decimal_rep);
}
return result;
}
......
......@@ -30,6 +30,7 @@
#include "v8.h"
#include "dtoa.h"
#include "bignum-dtoa.h"
#include "double.h"
#include "fast-dtoa.h"
#include "fixed-dtoa.h"
......@@ -37,7 +38,19 @@
namespace v8 {
namespace internal {
bool DoubleToAscii(double v, DtoaMode mode, int requested_digits,
static BignumDtoaMode DtoaToBignumDtoaMode(DtoaMode dtoa_mode) {
switch (dtoa_mode) {
case DTOA_SHORTEST: return BIGNUM_DTOA_SHORTEST;
case DTOA_FIXED: return BIGNUM_DTOA_FIXED;
case DTOA_PRECISION: return BIGNUM_DTOA_PRECISION;
default:
UNREACHABLE();
return BIGNUM_DTOA_SHORTEST; // To silence compiler.
}
}
void DoubleToAscii(double v, DtoaMode mode, int requested_digits,
Vector<char> buffer, int* sign, int* length, int* point) {
ASSERT(!Double(v).IsSpecial());
ASSERT(mode == DTOA_SHORTEST || requested_digits >= 0);
......@@ -54,25 +67,37 @@ bool DoubleToAscii(double v, DtoaMode mode, int requested_digits,
buffer[1] = '\0';
*length = 1;
*point = 1;
return true;
return;
}
if (mode == DTOA_PRECISION && requested_digits == 0) {
buffer[0] = '\0';
*length = 0;
return true;
return;
}
bool fast_worked;
switch (mode) {
case DTOA_SHORTEST:
return FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, length, point);
fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, length, point);
break;
case DTOA_FIXED:
return FastFixedDtoa(v, requested_digits, buffer, length, point);
fast_worked = FastFixedDtoa(v, requested_digits, buffer, length, point);
break;
case DTOA_PRECISION:
return FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
buffer, length, point);
fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
buffer, length, point);
break;
default:
UNREACHABLE();
fast_worked = false;
}
return false;
if (fast_worked) return;
// If the fast dtoa didn't succeed use the slower bignum version.
BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
BignumDtoa(v, bignum_mode, requested_digits, buffer, length, point);
buffer[*length] = '\0';
}
} } // namespace v8::internal
......@@ -32,13 +32,15 @@ namespace v8 {
namespace internal {
enum DtoaMode {
// 0.9999999999999999 becomes 0.1
// Return the shortest correct representation.
// For example the output of 0.299999999999999988897 is (the less accurate but
// correct) 0.3.
DTOA_SHORTEST,
// Fixed number of digits after the decimal point.
// Return a fixed number of digits after the decimal point.
// For instance fixed(0.1, 4) becomes 0.1000
// If the input number is big, the output will be big.
DTOA_FIXED,
// Fixed number of digits (independent of the decimal point).
// Return a fixed number of digits, no matter what the exponent is.
DTOA_PRECISION
};
......@@ -72,8 +74,10 @@ static const int kBase10MaximalLength = 17;
// which case the caller has to fill the missing digits with '0's.
// Halfway cases are again rounded away from 0.
// 'DoubleToAscii' expects the given buffer to be big enough to hold all digits
// and a terminating null-character.
bool DoubleToAscii(double v, DtoaMode mode, int requested_digits,
// and a terminating null-character. In SHORTEST-mode it expects a buffer of
// at least kBase10MaximalLength + 1. Otherwise, the size of the output is
// limited to requested_digits digits plus the null terminator.
void DoubleToAscii(double v, DtoaMode mode, int requested_digits,
Vector<char> buffer, int* sign, int* length, int* point);
} } // namespace v8::internal
......
......@@ -42,6 +42,7 @@ SOURCES = {
'test-api.cc',
'test-ast.cc',
'test-bignum.cc',
'test-bignum-dtoa.cc',
'test-circular-queue.cc',
'test-compiler.cc',
'test-conversions.cc',
......@@ -51,6 +52,7 @@ SOURCES = {
'test-decls.cc',
'test-diy-fp.cc',
'test-double.cc',
'test-dtoa.cc',
'test-fast-dtoa.cc',
'test-fixed-dtoa.cc',
'test-flags.cc',
......
This diff is collapsed.
This diff is collapsed.
......@@ -282,6 +282,8 @@
'../../src/ast.h',
'../../src/bignum.cc',
'../../src/bignum.h',
'../../src/bignum-dtoa.cc',
'../../src/bignum-dtoa.h',
'../../src/bootstrapper.cc',
'../../src/bootstrapper.h',
'../../src/builtins.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment