Skip to content

Commit

Permalink
DoubleConversion 2022-07-07 (af09fd65)
Browse files Browse the repository at this point in the history
Code extracted from:

    https://github.com/google/double-conversion

at commit af09fd65fcf24eee95dc62813ba9123414635428 (master).
  • Loading branch information
floitschG authored and dzenanz committed Aug 5, 2022
1 parent 8f0ef9b commit 7f9a214
Show file tree
Hide file tree
Showing 12 changed files with 283 additions and 66 deletions.
2 changes: 1 addition & 1 deletion bignum-dtoa.cc
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,

// Let v = numerator / denominator < 10.
// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
// from left to right. Once 'count' digits have been produced we decide wether
// from left to right. Once 'count' digits have been produced we decide whether
// to round up or down. Remainders of exactly .5 round upwards. Numbers such
// as 9.999999 propagate a carry all the way, and change the
// exponent (decimal_point), when rounding upwards.
Expand Down
5 changes: 3 additions & 2 deletions bignum.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void Bignum::AssignHexString(Vector<const char> value) {
DOUBLE_CONVERSION_ASSERT(sizeof(uint64_t) * 8 >= kBigitSize + 4); // TODO: static_assert
// Accumulates converted hex digits until at least kBigitSize bits.
// Works with non-factor-of-four kBigitSizes.
uint64_t tmp = 0; // Accumulates converted hex digits until at least
uint64_t tmp = 0;
for (int cnt = 0; !value.is_empty(); value.pop_back()) {
tmp |= (HexCharValue(value.last()) << cnt);
if ((cnt += 4) >= kBigitSize) {
Expand All @@ -146,7 +146,8 @@ void Bignum::AssignHexString(Vector<const char> value) {
}
}
if (tmp > 0) {
RawBigit(used_bigits_++) = tmp;
DOUBLE_CONVERSION_ASSERT(tmp <= kBigitMask);
RawBigit(used_bigits_++) = (tmp & kBigitMask);
}
Clamp();
}
Expand Down
34 changes: 23 additions & 11 deletions double-to-string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ bool DoubleToStringConverter::HandleSpecialValues(
StringBuilder* result_builder) const {
Double double_inspect(value);
if (double_inspect.IsInfinite()) {
if (infinity_symbol_ == NULL) return false;
if (infinity_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
if (value < 0) {
result_builder->AddCharacter('-');
}
result_builder->AddString(infinity_symbol_);
return true;
}
if (double_inspect.IsNan()) {
if (nan_symbol_ == NULL) return false;
if (nan_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
result_builder->AddString(nan_symbol_);
return true;
}
Expand Down Expand Up @@ -92,19 +92,19 @@ void DoubleToStringConverter::CreateExponentialRepresentation(
result_builder->AddCharacter('+');
}
}
if (exponent == 0) {
result_builder->AddCharacter('0');
return;
}
DOUBLE_CONVERSION_ASSERT(exponent < 1e4);
// Changing this constant requires updating the comment of DoubleToStringConverter constructor
const int kMaxExponentLength = 5;
char buffer[kMaxExponentLength + 1];
buffer[kMaxExponentLength] = '\0';
int first_char_pos = kMaxExponentLength;
while (exponent > 0) {
buffer[--first_char_pos] = '0' + (exponent % 10);
exponent /= 10;
if (exponent == 0) {
buffer[--first_char_pos] = '0';
} else {
while (exponent > 0) {
buffer[--first_char_pos] = '0' + (exponent % 10);
exponent /= 10;
}
}
// Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength)
// For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2
Expand Down Expand Up @@ -327,9 +327,21 @@ bool DoubleToStringConverter::ToPrecision(double value,
int exponent = decimal_point - 1;

int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
bool as_exponential =
(-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
(decimal_point - precision + extra_zero >
max_trailing_padding_zeroes_in_precision_mode_)) {
max_trailing_padding_zeroes_in_precision_mode_);
if ((flags_ & NO_TRAILING_ZERO) != 0) {
// Truncate trailing zeros that occur after the decimal point (if exponential,
// that is everything after the first digit).
int stop = as_exponential ? 1 : std::max(1, decimal_point);
while (decimal_rep_length > stop && decimal_rep[decimal_rep_length - 1] == '0') {
--decimal_rep_length;
}
// Clamp precision to avoid the code below re-adding the zeros.
precision = std::min(precision, decimal_rep_length);
}
if (as_exponential) {
// Fill buffer to contain 'precision' digits.
// Usually the buffer is already at the correct length, but 'DoubleToAscii'
// is allowed to return less characters.
Expand Down
85 changes: 67 additions & 18 deletions double-to-string.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class DoubleToStringConverter {
// or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the
// function returns false.
static const int kMaxFixedDigitsBeforePoint = 60;
static const int kMaxFixedDigitsAfterPoint = 60;
static const int kMaxFixedDigitsAfterPoint = 100;

// When calling ToExponential with a requested_digits
// parameter > kMaxExponentialDigits then the function returns false.
Expand All @@ -50,12 +50,35 @@ class DoubleToStringConverter {
static const int kMinPrecisionDigits = 1;
static const int kMaxPrecisionDigits = 120;

// The maximal number of digits that are needed to emit a double in base 10.
// A higher precision can be achieved by using more digits, but the shortest
// accurate representation of any double will never use more digits than
// kBase10MaximalLength.
// Note that DoubleToAscii null-terminates its input. So the given buffer
// should be at least kBase10MaximalLength + 1 characters long.
static const int kBase10MaximalLength = 17;

// The maximal number of digits that are needed to emit a single in base 10.
// A higher precision can be achieved by using more digits, but the shortest
// accurate representation of any single will never use more digits than
// kBase10MaximalLengthSingle.
static const int kBase10MaximalLengthSingle = 9;

// The length of the longest string that 'ToShortest' can produce when the
// converter is instantiated with EcmaScript defaults (see
// 'EcmaScriptConverter')
// This value does not include the trailing '\0' character.
// This amount of characters is needed for negative values that hit the
// 'decimal_in_shortest_low' limit. For example: "-0.0000033333333333333333"
static const int kMaxCharsEcmaScriptShortest = 25;

enum Flags {
NO_FLAGS = 0,
EMIT_POSITIVE_EXPONENT_SIGN = 1,
EMIT_TRAILING_DECIMAL_POINT = 2,
EMIT_TRAILING_ZERO_AFTER_POINT = 4,
UNIQUE_ZERO = 8
UNIQUE_ZERO = 8,
NO_TRAILING_ZERO = 16
};

// Flags should be a bit-or combination of the possible Flags-enum.
Expand All @@ -67,9 +90,13 @@ class DoubleToStringConverter {
// Example: 2345.0 is converted to "2345.".
// - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point
// emits a trailing '0'-character. This flag requires the
// EXMIT_TRAILING_DECIMAL_POINT flag.
// EMIT_TRAILING_DECIMAL_POINT flag.
// Example: 2345.0 is converted to "2345.0".
// - UNIQUE_ZERO: "-0.0" is converted to "0.0".
// - NO_TRAILING_ZERO: Trailing zeros are removed from the fractional portion
// of the result in precision mode. Matches printf's %g.
// When EMIT_TRAILING_ZERO_AFTER_POINT is also given, one trailing zero is
// preserved.
//
// 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 All @@ -96,7 +123,7 @@ class DoubleToStringConverter {
// Example with max_leading_padding_zeroes_in_precision_mode = 6.
// ToPrecision(0.0000012345, 2) -> "0.0000012"
// ToPrecision(0.00000012345, 2) -> "1.2e-7"
// Similarily the converter may add up to
// Similarly the converter may add up to
// max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
// returning an exponential representation. A zero added by the
// EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
Expand Down Expand Up @@ -137,6 +164,14 @@ class DoubleToStringConverter {
}

// Returns a converter following the EcmaScript specification.
//
// Flags: UNIQUE_ZERO and EMIT_POSITIVE_EXPONENT_SIGN.
// Special values: "Infinity" and "NaN".
// Lower case 'e' for exponential values.
// decimal_in_shortest_low: -6
// decimal_in_shortest_high: 21
// max_leading_padding_zeroes_in_precision_mode: 6
// max_trailing_padding_zeroes_in_precision_mode: 0
static const DoubleToStringConverter& EcmaScriptConverter();

// Computes the shortest string of digits that correctly represent the input
Expand All @@ -146,7 +181,7 @@ class DoubleToStringConverter {
// Example with decimal_in_shortest_low = -6,
// decimal_in_shortest_high = 21,
// EMIT_POSITIVE_EXPONENT_SIGN activated, and
// EMIT_TRAILING_DECIMAL_POINT deactived:
// EMIT_TRAILING_DECIMAL_POINT deactivated:
// ToShortest(0.000001) -> "0.000001"
// ToShortest(0.0000001) -> "1e-7"
// ToShortest(111111111111111111111.0) -> "111111111111111110000"
Expand All @@ -162,6 +197,21 @@ class DoubleToStringConverter {
// Returns true if the conversion succeeds. The conversion always succeeds
// except when the input value is special and no infinity_symbol or
// nan_symbol has been given to the constructor.
//
// The length of the longest result is the maximum of the length of the
// following string representations (each with possible examples):
// - NaN and negative infinity: "NaN", "-Infinity", "-inf".
// - -10^(decimal_in_shortest_high - 1):
// "-100000000000000000000", "-1000000000000000.0"
// - the longest string in range [0; -10^decimal_in_shortest_low]. Generally,
// this string is 3 + kBase10MaximalLength - decimal_in_shortest_low.
// (Sign, '0', decimal point, padding zeroes for decimal_in_shortest_low,
// and the significant digits).
// "-0.0000033333333333333333", "-0.0012345678901234567"
// - the longest exponential representation. (A negative number with
// kBase10MaximalLength significant digits).
// "-1.7976931348623157e+308", "-1.7976931348623157E308"
// In addition, the buffer must be able to hold the trailing '\0' character.
bool ToShortest(double value, StringBuilder* result_builder) const {
return ToShortestIeeeNumber(value, result_builder, SHORTEST);
}
Expand Down Expand Up @@ -202,9 +252,11 @@ class DoubleToStringConverter {
// been provided to the constructor,
// - 'value' > 10^kMaxFixedDigitsBeforePoint, or
// - 'requested_digits' > kMaxFixedDigitsAfterPoint.
// The last two conditions imply that the result will never contain more than
// 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
// The last two conditions imply that the result for non-special values never
// contains more than
// 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
// (one additional character for the sign, and one for the decimal point).
// In addition, the buffer must be able to hold the trailing '\0' character.
bool ToFixed(double value,
int requested_digits,
StringBuilder* result_builder) const;
Expand Down Expand Up @@ -233,14 +285,17 @@ class DoubleToStringConverter {
// - the input value is special and no infinity_symbol or nan_symbol has
// been provided to the constructor,
// - 'requested_digits' > kMaxExponentialDigits.
// The last condition implies that the result will never contain more than
//
// The last condition implies that the result never contains more than
// kMaxExponentialDigits + 8 characters (the sign, the digit before the
// decimal point, the decimal point, the exponent character, the
// exponent's sign, and at most 3 exponent digits).
// In addition, the buffer must be able to hold the trailing '\0' character.
bool ToExponential(double value,
int requested_digits,
StringBuilder* result_builder) const;


// Computes 'precision' leading digits of the given 'value' and returns them
// either in exponential or decimal format, depending on
// max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the
Expand All @@ -250,7 +305,7 @@ class DoubleToStringConverter {
// Example with max_leading_padding_zeroes_in_precision_mode = 6.
// ToPrecision(0.0000012345, 2) -> "0.0000012"
// ToPrecision(0.00000012345, 2) -> "1.2e-7"
// Similarily the converter may add up to
// Similarly the converter may add up to
// max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
// returning an exponential representation. A zero added by the
// EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
Expand All @@ -272,9 +327,11 @@ class DoubleToStringConverter {
// been provided to the constructor,
// - precision < kMinPericisionDigits
// - precision > kMaxPrecisionDigits
// The last condition implies that the result will never contain more than
//
// The last condition implies that the result never contains more than
// kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the
// exponent character, the exponent's sign, and at most 3 exponent digits).
// In addition, the buffer must be able to hold the trailing '\0' character.
bool ToPrecision(double value,
int precision,
StringBuilder* result_builder) const;
Expand All @@ -294,14 +351,6 @@ class DoubleToStringConverter {
PRECISION
};

// The maximal number of digits that are needed to emit a double in base 10.
// A higher precision can be achieved by using more digits, but the shortest
// accurate representation of any double will never use more digits than
// kBase10MaximalLength.
// Note that DoubleToAscii null-terminates its input. So the given buffer
// should be at least kBase10MaximalLength + 1 characters long.
static const int kBase10MaximalLength = 17;

// Converts the given double 'v' to digit characters. 'v' must not be NaN,
// +Infinity, or -Infinity. In SHORTEST_SINGLE-mode this restriction also
// applies to 'v' after it has been casted to a single-precision float. That
Expand Down
4 changes: 2 additions & 2 deletions fast-dtoa.cc
Original file line number Diff line number Diff line change
Expand Up @@ -565,15 +565,15 @@ static bool Grisu3(double v,
// the difference between w and boundary_minus/plus (a power of 2) and to
// compute scaled_boundary_minus/plus by subtracting/adding from
// scaled_w. However the code becomes much less readable and the speed
// enhancements are not terriffic.
// enhancements are not terrific.
DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk);
DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk);

// DigitGen will generate the digits of scaled_w. Therefore we have
// v == (double) (scaled_w * 10^-mk).
// Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
// integer than it will be updated. For instance if scaled_w == 1.23 then
// the buffer will be filled with "123" und the decimal_exponent will be
// the buffer will be filled with "123" and the decimal_exponent will be
// decreased by 2.
int kappa;
bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
Expand Down
4 changes: 2 additions & 2 deletions fixed-dtoa.cc
Original file line number Diff line number Diff line change
Expand Up @@ -395,8 +395,8 @@ bool FastFixedDtoa(double v,
TrimZeros(buffer, length, decimal_point);
buffer[*length] = '\0';
if ((*length) == 0) {
// The string is empty and the decimal_point thus has no importance. Mimick
// Gay's dtoa and and set it to -fractional_count.
// The string is empty and the decimal_point thus has no importance. Mimic
// Gay's dtoa and set it to -fractional_count.
*decimal_point = -fractional_count;
}
return true;
Expand Down
25 changes: 25 additions & 0 deletions ieee.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,19 @@ class Double {
}

bool IsQuietNan() const {
#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__)
return IsNan() && ((AsUint64() & kQuietNanBit) == 0);
#else
return IsNan() && ((AsUint64() & kQuietNanBit) != 0);
#endif
}

bool IsSignalingNan() const {
#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__)
return IsNan() && ((AsUint64() & kQuietNanBit) != 0);
#else
return IsNan() && ((AsUint64() & kQuietNanBit) == 0);
#endif
}


Expand Down Expand Up @@ -236,7 +244,12 @@ class Double {
private:
static const int kDenormalExponent = -kExponentBias + 1;
static const uint64_t kInfinity = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF00000, 00000000);
#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__)
static const uint64_t kNaN = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF7FFFF, FFFFFFFF);
#else
static const uint64_t kNaN = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF80000, 00000000);
#endif


const uint64_t d64_;

Expand Down Expand Up @@ -336,11 +349,19 @@ class Single {
}

bool IsQuietNan() const {
#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__)
return IsNan() && ((AsUint32() & kQuietNanBit) == 0);
#else
return IsNan() && ((AsUint32() & kQuietNanBit) != 0);
#endif
}

bool IsSignalingNan() const {
#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__)
return IsNan() && ((AsUint32() & kQuietNanBit) != 0);
#else
return IsNan() && ((AsUint32() & kQuietNanBit) == 0);
#endif
}


Expand Down Expand Up @@ -410,7 +431,11 @@ class Single {
static const int kDenormalExponent = -kExponentBias + 1;
static const int kMaxExponent = 0xFF - kExponentBias;
static const uint32_t kInfinity = 0x7F800000;
#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__)
static const uint32_t kNaN = 0x7FBFFFFF;
#else
static const uint32_t kNaN = 0x7FC00000;
#endif

const uint32_t d32_;

Expand Down
Loading

0 comments on commit 7f9a214

Please sign in to comment.