Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions double-conversion/bignum-dtoa.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,21 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
// Generates 'requested_digits' after the decimal point.
static void BignumToFixed(int requested_digits, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char> buffer, int* length);
Vector<char> buffer, int* length,
bool round_half_to_even = false);
// Generates 'count' digits of numerator/denominator.
// Once 'count' digits have been produced rounds the result depending on the
// remainder (remainders of exactly .5 round upwards). Might update the
// decimal_point when rounding up (for example for 0.9999).
static void GenerateCountedDigits(int count, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char> buffer, int* length);
Vector<char> buffer, int* length,
bool round_half_to_even = false);


void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
Vector<char> buffer, int* length, int* decimal_point) {
Vector<char> buffer, int* length, int* decimal_point,
bool round_half_to_even) {
DOUBLE_CONVERSION_ASSERT(v > 0);
DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
uint64_t significand;
Expand Down Expand Up @@ -155,12 +158,14 @@ void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
case BIGNUM_DTOA_FIXED:
BignumToFixed(requested_digits, decimal_point,
&numerator, &denominator,
buffer, length);
buffer, length,
round_half_to_even);
break;
case BIGNUM_DTOA_PRECISION:
GenerateCountedDigits(requested_digits, decimal_point,
&numerator, &denominator,
buffer, length);
buffer, length,
round_half_to_even);
break;
default:
DOUBLE_CONVERSION_UNREACHABLE();
Expand Down Expand Up @@ -282,7 +287,8 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
// exponent (decimal_point), when rounding upwards.
static void GenerateCountedDigits(int count, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char> buffer, int* length) {
Vector<char> buffer, int* length,
bool round_half_to_even) {
DOUBLE_CONVERSION_ASSERT(count >= 0);
if (count <= 0) {
// No digits requested. The "last digit" store below would write buffer[count - 1].
Expand All @@ -302,7 +308,8 @@ static void GenerateCountedDigits(int count, int* decimal_point,
// Generate the last digit.
uint16_t digit;
digit = numerator->DivideModuloIntBignum(*denominator);
if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
if (compare > 0 || (compare == 0 && (round_half_to_even ? (digit % 2 != 0) : true))) {
digit++;
}
DOUBLE_CONVERSION_ASSERT(digit <= 10);
Expand Down Expand Up @@ -330,7 +337,8 @@ static void GenerateCountedDigits(int count, int* decimal_point,
// Input verifies: 1 <= (numerator + delta) / denominator < 10.
static void BignumToFixed(int requested_digits, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char> buffer, int* length) {
Vector<char> buffer, int* length,
bool round_half_to_even) {
// Note that we have to look at more than just the requested_digits, since
// a number could be rounded up. Example: v=0.5 with requested_digits=0.
// Even though the power of v equals 0 we can't just stop here.
Expand All @@ -350,9 +358,11 @@ static void BignumToFixed(int requested_digits, int* decimal_point,
// Initially the fraction lies in range (1, 10]. Multiply the denominator
// by 10 so that we can compare more easily.
denominator->Times10();
if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
if (compare > 0 || (compare == 0 && !round_half_to_even)) {
// If the fraction is >= 0.5 then we have to include the rounded
// digit.
// digit. In half-to-even, the preceding digit is 0 (which is even),
// so exact halfway cases round down to 0.
buffer[0] = '1';
*length = 1;
(*decimal_point)++;
Expand All @@ -367,7 +377,8 @@ static void BignumToFixed(int requested_digits, int* decimal_point,
int needed_digits = (*decimal_point) + requested_digits;
GenerateCountedDigits(needed_digits, decimal_point,
numerator, denominator,
buffer, length);
buffer, length,
round_half_to_even);
}
}

Expand Down
3 changes: 2 additions & 1 deletion double-conversion/bignum-dtoa.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ enum BignumDtoaMode {
// '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);
Vector<char> buffer, int* length, int* point,
bool round_half_to_even = false);

} // namespace double_conversion

Expand Down
62 changes: 35 additions & 27 deletions double-conversion/double-to-string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ bool DoubleToStringConverter::ToShortestIeeeNumber(
int decimal_rep_length;

DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
&sign, &decimal_rep_length, &decimal_point);
&sign, &decimal_rep_length, &decimal_point,
(flags_ & ROUND_HALF_TO_EVEN) != 0);

bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
if (sign && (value != 0.0 || !unique_zero)) {
Expand Down Expand Up @@ -233,7 +234,8 @@ bool DoubleToStringConverter::ToFixed(double value,
int decimal_rep_length;
DoubleToAscii(value, FIXED, requested_digits,
decimal_rep, kDecimalRepCapacity,
&sign, &decimal_rep_length, &decimal_point);
&sign, &decimal_rep_length, &decimal_point,
(flags_ & ROUND_HALF_TO_EVEN) != 0);

bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
if (sign && (value != 0.0 || !unique_zero)) {
Expand Down Expand Up @@ -274,11 +276,13 @@ bool DoubleToStringConverter::ToExponential(
if (requested_digits == -1) {
DoubleToAscii(value, SHORTEST, 0,
decimal_rep, kDecimalRepCapacity,
&sign, &decimal_rep_length, &decimal_point);
&sign, &decimal_rep_length, &decimal_point,
(flags_ & ROUND_HALF_TO_EVEN) != 0);
} else {
DoubleToAscii(value, PRECISION, requested_digits + 1,
decimal_rep, kDecimalRepCapacity,
&sign, &decimal_rep_length, &decimal_point);
&sign, &decimal_rep_length, &decimal_point,
(flags_ & ROUND_HALF_TO_EVEN) != 0);
DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= requested_digits + 1);

for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
Expand Down Expand Up @@ -322,7 +326,8 @@ bool DoubleToStringConverter::ToPrecision(double value,

DoubleToAscii(value, PRECISION, precision,
decimal_rep, kDecimalRepCapacity,
&sign, &decimal_rep_length, &decimal_point);
&sign, &decimal_rep_length, &decimal_point,
(flags_ & ROUND_HALF_TO_EVEN) != 0);
DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= precision);

bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
Expand Down Expand Up @@ -391,7 +396,8 @@ void DoubleToStringConverter::DoubleToAscii(double v,
int buffer_length,
bool* sign,
int* length,
int* point) {
int* point,
bool round_half_to_even) {
Vector<char> vector(buffer, buffer_length);
DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
Expand Down Expand Up @@ -423,31 +429,33 @@ void DoubleToStringConverter::DoubleToAscii(double v,
return;
}

bool fast_worked;
switch (mode) {
case SHORTEST:
fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
break;
case SHORTEST_SINGLE:
fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
vector, length, point);
break;
case FIXED:
fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
break;
case PRECISION:
fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
vector, length, point);
break;
default:
fast_worked = false;
DOUBLE_CONVERSION_UNREACHABLE();
bool fast_worked = false;
if (!round_half_to_even) {
switch (mode) {
case SHORTEST:
fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
break;
case SHORTEST_SINGLE:
fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
vector, length, point);
break;
case FIXED:
fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
break;
case PRECISION:
fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
vector, length, point);
break;
default:
fast_worked = false;
DOUBLE_CONVERSION_UNREACHABLE();
}
if (fast_worked) return;
}
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, vector, length, point);
BignumDtoa(v, bignum_mode, requested_digits, vector, length, point, round_half_to_even);
vector[*length] = '\0';
}

Expand Down
8 changes: 6 additions & 2 deletions double-conversion/double-to-string.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ class DoubleToStringConverter {
UNIQUE_ZERO = 8,
NO_TRAILING_ZERO = 16,
EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL = 32,
EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL = 64
EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL = 64,
ROUND_HALF_TO_EVEN = 128
};

// Flags should be a bit-or combination of the possible Flags-enum.
Expand All @@ -106,6 +107,8 @@ class DoubleToStringConverter {
// - EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL: in addition to a trailing
// decimal point emits a trailing '0'-character. This flag requires the
// EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL flag.
// - ROUND_HALF_TO_EVEN: round halfway cases towards the nearest even number
// (banker's rounding) instead of away from zero. Matches printf, std::to_chars, etc.
//
// Infinity symbol and nan_symbol provide the string representation for these
// special values. If the string is NULL and the special value is encountered
Expand Down Expand Up @@ -453,7 +456,8 @@ class DoubleToStringConverter {
int buffer_length,
bool* sign,
int* length,
int* point);
int* point,
bool round_half_to_even = false);

private:
// Implementation for ToShortest and ToShortestSingle.
Expand Down
Loading