Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Sync with upstream git repo

commit e5b3442

--HG--
rename : double-conversion/src/double.h => double-conversion/src/ieee.h
  • Loading branch information...
commit 64206912a2b294e2ee83109c154576f72602a408 1 parent 88c27fc
Bryan O'Sullivan authored
Showing with 12,969 additions and 206 deletions.
  1. +12 −0 double-conversion/AUTHORS
  2. +11 −0 double-conversion/Changelog
  3. +5 −2 double-conversion/SConstruct
  4. +56 −69 double-conversion/src/bignum-dtoa.cc
  5. +2 −0  double-conversion/src/bignum-dtoa.h
  6. +4 −0 double-conversion/src/bignum.h
  7. +5 −7 double-conversion/src/cached-powers.cc
  8. +54 −34 double-conversion/src/double-conversion.cc
  9. +45 −7 double-conversion/src/double-conversion.h
  10. +13 −7 double-conversion/src/fast-dtoa.cc
  11. +4 −0 double-conversion/src/fast-dtoa.h
  12. +1 −1  double-conversion/src/fixed-dtoa.cc
  13. +162 −9 double-conversion/src/{double.h → ieee.h}
  14. +159 −46 double-conversion/src/strtod.cc
  15. +4 −0 double-conversion/src/strtod.h
  16. +21 −5 double-conversion/src/utils.h
  17. +2 −1  double-conversion/test/cctest/SConscript
  18. +10,049 −0 double-conversion/test/cctest/gay-shortest-single.cc
  19. +44 −0 double-conversion/test/cctest/gay-shortest-single.h
  20. +84 −2 double-conversion/test/cctest/test-bignum-dtoa.cc
  21. +1,535 −3 double-conversion/test/cctest/test-conversions.cc
  22. +87 −2 double-conversion/test/cctest/test-dtoa.cc
  23. +107 −1 double-conversion/test/cctest/test-fast-dtoa.cc
  24. +1 −1  double-conversion/test/cctest/test-fixed-dtoa.cc
  25. +212 −8 double-conversion/test/cctest/{test-double.cc → test-ieee.cc}
  26. +290 −1 double-conversion/test/cctest/test-strtod.cc
12 double-conversion/AUTHORS
View
@@ -0,0 +1,12 @@
+# Below is a list of people and organizations that have contributed
+# to the double-conversion project. Names should be added to the
+# list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
+Mozilla Foundation
+
+Jeff Muizelaar <jmuizelaar@mozilla.com>
+Mike Hommey <mhommey@mozilla.com>
+Martin Olsson <mnemo@minimum.se>
11 double-conversion/Changelog
View
@@ -0,0 +1,11 @@
+2012-06-10:
+ Tagged v1.1.1.
+ Null terminate exponent buffer (only an issue when asserts are enabled).
+ Support more architectures.
+
+2012-02-05:
+ Merged in Single-branch with single-precision support.
+ Tagged v1.1 (based on b28450f33e1db493948a535d8f84e88fa211bd10).
+
+2012-02-05:
+ Tagged v1.0 (based on eda0196e9ac8fcdf59e92cb62885ee0af5391969).
7 double-conversion/SConstruct
View
@@ -2,10 +2,13 @@ double_conversion_sources = ['src/' + x for x in SConscript('src/SConscript')]
double_conversion_test_sources = ['test/cctest/' + x for x in SConscript('test/cctest/SConscript')]
test = double_conversion_sources + double_conversion_test_sources
print(test)
-env = Environment(CPPPATH='#/src')
+env = Environment(CPPPATH='#/src', LIBS=['m', 'stdc++'])
debug = ARGUMENTS.get('debug', 0)
+optimize = ARGUMENTS.get('optimize', 0)
if int(debug):
- env.Append(CCFLAGS = '-g')
+ env.Append(CCFLAGS = '-g -Wall -Werror')
+if int(optimize):
+ env.Append(CCFLAGS = '-O3')
print double_conversion_sources
print double_conversion_test_sources
env.Program('run_tests', double_conversion_sources + double_conversion_test_sources)
125 double-conversion/src/bignum-dtoa.cc
View
@@ -30,7 +30,7 @@
#include "bignum-dtoa.h"
#include "bignum.h"
-#include "double.h"
+#include "ieee.h"
namespace double_conversion {
@@ -49,7 +49,9 @@ static int NormalizedExponent(uint64_t significand, int exponent) {
static int EstimatePower(int exponent);
// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
// and denominator.
-static void InitialScaledStartValues(double v,
+static void InitialScaledStartValues(uint64_t significand,
+ int exponent,
+ bool lower_boundary_is_closer,
int estimated_power,
bool need_boundary_deltas,
Bignum* numerator,
@@ -88,9 +90,24 @@ void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
Vector<char> buffer, int* length, int* decimal_point) {
ASSERT(v > 0);
ASSERT(!Double(v).IsSpecial());
- uint64_t significand = Double(v).Significand();
+ uint64_t significand;
+ int exponent;
+ bool lower_boundary_is_closer;
+ if (mode == BIGNUM_DTOA_SHORTEST_SINGLE) {
+ float f = static_cast<float>(v);
+ ASSERT(f == v);
+ significand = Single(f).Significand();
+ exponent = Single(f).Exponent();
+ lower_boundary_is_closer = Single(f).LowerBoundaryIsCloser();
+ } else {
+ significand = Double(v).Significand();
+ exponent = Double(v).Exponent();
+ lower_boundary_is_closer = Double(v).LowerBoundaryIsCloser();
+ }
+ bool need_boundary_deltas =
+ (mode == BIGNUM_DTOA_SHORTEST || mode == BIGNUM_DTOA_SHORTEST_SINGLE);
+
bool is_even = (significand & 1) == 0;
- int exponent = Double(v).Exponent();
int normalized_exponent = NormalizedExponent(significand, exponent);
// estimated_power might be too low by 1.
int estimated_power = EstimatePower(normalized_exponent);
@@ -118,8 +135,8 @@ void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
// The maximum double is 1.7976931348623157e308 which needs fewer than
// 308*4 binary digits.
ASSERT(Bignum::kMaxSignificantBits >= 324*4);
- bool need_boundary_deltas = (mode == BIGNUM_DTOA_SHORTEST);
- InitialScaledStartValues(v, estimated_power, need_boundary_deltas,
+ InitialScaledStartValues(significand, exponent, lower_boundary_is_closer,
+ estimated_power, need_boundary_deltas,
&numerator, &denominator,
&delta_minus, &delta_plus);
// We now have v = (numerator / denominator) * 10^estimated_power.
@@ -130,6 +147,7 @@ void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
// 1 <= (numerator + delta_plus) / denominator < 10
switch (mode) {
case BIGNUM_DTOA_SHORTEST:
+ case BIGNUM_DTOA_SHORTEST_SINGLE:
GenerateShortestDigits(&numerator, &denominator,
&delta_minus, &delta_plus,
is_even, buffer, length);
@@ -388,7 +406,7 @@ static int EstimatePower(int exponent) {
const double k1Log10 = 0.30102999566398114; // 1/lg(10)
// For doubles len(f) == 53 (don't forget the hidden bit).
- const int kSignificandSize = 53;
+ const int kSignificandSize = Double::kSignificandSize;
double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
return static_cast<int>(estimate);
}
@@ -396,7 +414,8 @@ static int EstimatePower(int exponent) {
// See comments for InitialScaledStartValues.
static void InitialScaledStartValuesPositiveExponent(
- double v, int estimated_power, bool need_boundary_deltas,
+ uint64_t significand, int exponent,
+ int estimated_power, bool need_boundary_deltas,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
// A positive exponent implies a positive power.
@@ -405,8 +424,8 @@ static void InitialScaledStartValuesPositiveExponent(
// by 10^estimated_power.
// numerator = v.
- numerator->AssignUInt64(Double(v).Significand());
- numerator->ShiftLeft(Double(v).Exponent());
+ numerator->AssignUInt64(significand);
+ numerator->ShiftLeft(exponent);
// denominator = 10^estimated_power.
denominator->AssignPowerUInt16(10, estimated_power);
@@ -418,35 +437,20 @@ static void InitialScaledStartValuesPositiveExponent(
// Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
// denominator (of 2) delta_plus equals 2^e.
delta_plus->AssignUInt16(1);
- delta_plus->ShiftLeft(Double(v).Exponent());
- // Same for delta_minus (with adjustments below if f == 2^p-1).
+ delta_plus->ShiftLeft(exponent);
+ // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
delta_minus->AssignUInt16(1);
- delta_minus->ShiftLeft(Double(v).Exponent());
-
- // If the significand (without the hidden bit) is 0, then the lower
- // boundary is closer than just half a ulp (unit in the last place).
- // There is only one exception: if the next lower number is a denormal then
- // the distance is 1 ulp. This cannot be the case for exponent >= 0 (but we
- // have to test it in the other function where exponent < 0).
- uint64_t v_bits = Double(v).AsUint64();
- if ((v_bits & Double::kSignificandMask) == 0) {
- // The lower boundary is closer at half the distance of "normal" numbers.
- // Increase the common denominator and adapt all but the delta_minus.
- denominator->ShiftLeft(1); // *2
- numerator->ShiftLeft(1); // *2
- delta_plus->ShiftLeft(1); // *2
- }
+ delta_minus->ShiftLeft(exponent);
}
}
// See comments for InitialScaledStartValues
static void InitialScaledStartValuesNegativeExponentPositivePower(
- double v, int estimated_power, bool need_boundary_deltas,
+ uint64_t significand, int exponent,
+ int estimated_power, bool need_boundary_deltas,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
- uint64_t significand = Double(v).Significand();
- int exponent = Double(v).Exponent();
// v = f * 2^e with e < 0, and with estimated_power >= 0.
// This means that e is close to 0 (have a look at how estimated_power is
// computed).
@@ -469,36 +473,18 @@ static void InitialScaledStartValuesNegativeExponentPositivePower(
// Given that the denominator already includes v's exponent the distance
// to the boundaries is simply 1.
delta_plus->AssignUInt16(1);
- // Same for delta_minus (with adjustments below if f == 2^p-1).
+ // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
delta_minus->AssignUInt16(1);
-
- // If the significand (without the hidden bit) is 0, then the lower
- // boundary is closer than just one ulp (unit in the last place).
- // There is only one exception: if the next lower number is a denormal
- // then the distance is 1 ulp. Since the exponent is close to zero
- // (otherwise estimated_power would have been negative) this cannot happen
- // here either.
- uint64_t v_bits = Double(v).AsUint64();
- if ((v_bits & Double::kSignificandMask) == 0) {
- // The lower boundary is closer at half the distance of "normal" numbers.
- // Increase the denominator and adapt all but the delta_minus.
- denominator->ShiftLeft(1); // *2
- numerator->ShiftLeft(1); // *2
- delta_plus->ShiftLeft(1); // *2
- }
}
}
// See comments for InitialScaledStartValues
static void InitialScaledStartValuesNegativeExponentNegativePower(
- double v, int estimated_power, bool need_boundary_deltas,
+ uint64_t significand, int exponent,
+ int estimated_power, bool need_boundary_deltas,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
- const uint64_t kMinimalNormalizedExponent =
- UINT64_2PART_C(0x00100000, 00000000);
- uint64_t significand = Double(v).Significand();
- int exponent = Double(v).Exponent();
// Instead of multiplying the denominator with 10^estimated_power we
// multiply all values (numerator and deltas) by 10^-estimated_power.
@@ -535,18 +521,7 @@ static void InitialScaledStartValuesNegativeExponentNegativePower(
// delta_plus = 10^-estimated_power, and
// delta_minus = 10^-estimated_power.
// These assignments have been done earlier.
-
- // The special case where the lower boundary is twice as close.
- // This time we have to look out for the exception too.
- uint64_t v_bits = Double(v).AsUint64();
- if ((v_bits & Double::kSignificandMask) == 0 &&
- // The only exception where a significand == 0 has its boundaries at
- // "normal" distances:
- (v_bits & Double::kExponentMask) != kMinimalNormalizedExponent) {
- numerator->ShiftLeft(1); // *2
- denominator->ShiftLeft(1); // *2
- delta_plus->ShiftLeft(1); // *2
- }
+ // The adjustments if f == 2^p-1 (lower boundary is closer) are done later.
}
}
@@ -586,27 +561,39 @@ static void InitialScaledStartValuesNegativeExponentNegativePower(
//
// It is then easy to kickstart the digit-generation routine.
//
-// The boundary-deltas are only filled if need_boundary_deltas is set.
-static void InitialScaledStartValues(double v,
+// The boundary-deltas are only filled if the mode equals BIGNUM_DTOA_SHORTEST
+// or BIGNUM_DTOA_SHORTEST_SINGLE.
+
+static void InitialScaledStartValues(uint64_t significand,
+ int exponent,
+ bool lower_boundary_is_closer,
int estimated_power,
bool need_boundary_deltas,
Bignum* numerator,
Bignum* denominator,
Bignum* delta_minus,
Bignum* delta_plus) {
- if (Double(v).Exponent() >= 0) {
+ if (exponent >= 0) {
InitialScaledStartValuesPositiveExponent(
- v, estimated_power, need_boundary_deltas,
+ significand, exponent, estimated_power, need_boundary_deltas,
numerator, denominator, delta_minus, delta_plus);
} else if (estimated_power >= 0) {
InitialScaledStartValuesNegativeExponentPositivePower(
- v, estimated_power, need_boundary_deltas,
+ significand, exponent, estimated_power, need_boundary_deltas,
numerator, denominator, delta_minus, delta_plus);
} else {
InitialScaledStartValuesNegativeExponentNegativePower(
- v, estimated_power, need_boundary_deltas,
+ significand, exponent, estimated_power, need_boundary_deltas,
numerator, denominator, delta_minus, delta_plus);
}
+
+ if (need_boundary_deltas && lower_boundary_is_closer) {
+ // The lower boundary is closer at half the distance of "normal" numbers.
+ // Increase the common denominator and adapt all but the delta_minus.
+ denominator->ShiftLeft(1); // *2
+ numerator->ShiftLeft(1); // *2
+ delta_plus->ShiftLeft(1); // *2
+ }
}
2  double-conversion/src/bignum-dtoa.h
View
@@ -37,6 +37,8 @@ enum BignumDtoaMode {
// For example the output of 0.299999999999999988897 is (the less accurate but
// correct) 0.3.
BIGNUM_DTOA_SHORTEST,
+ // Same as BIGNUM_DTOA_SHORTEST but for single-precision floats.
+ BIGNUM_DTOA_SHORTEST_SINGLE,
// 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.
4 double-conversion/src/bignum.h
View
@@ -69,6 +69,10 @@ class Bignum {
bool ToHexString(char* buffer, int buffer_size) const;
+ // Returns
+ // -1 if a < b,
+ // 0 if a == b, and
+ // +1 if a > b.
static int Compare(const Bignum& a, const Bignum& b);
static bool Equal(const Bignum& a, const Bignum& b) {
return Compare(a, b) == 0;
12 double-conversion/src/cached-powers.cc
View
@@ -132,14 +132,12 @@ static const CachedPower kCachedPowers[] = {
};
static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers);
-static const int kCachedPowersOffset = -kCachedPowers[0].decimal_exponent;
+static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent.
static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10)
-const int PowersOfTenCache::kDecimalExponentDistance =
- kCachedPowers[1].decimal_exponent - kCachedPowers[0].decimal_exponent;
-const int PowersOfTenCache::kMinDecimalExponent =
- kCachedPowers[0].decimal_exponent;
-const int PowersOfTenCache::kMaxDecimalExponent =
- kCachedPowers[kCachedPowersLength - 1].decimal_exponent;
+// Difference between the decimal exponents in the table above.
+const int PowersOfTenCache::kDecimalExponentDistance = 8;
+const int PowersOfTenCache::kMinDecimalExponent = -348;
+const int PowersOfTenCache::kMaxDecimalExponent = 340;
void PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
int min_exponent,
88 double-conversion/src/double-conversion.cc
View
@@ -31,9 +31,9 @@
#include "double-conversion.h"
#include "bignum-dtoa.h"
-#include "double.h"
#include "fast-dtoa.h"
#include "fixed-dtoa.h"
+#include "ieee.h"
#include "strtod.h"
#include "utils.h"
@@ -98,7 +98,8 @@ void DoubleToStringConverter::CreateExponentialRepresentation(
}
ASSERT(exponent < 1e4);
const int kMaxExponentLength = 5;
- char buffer[kMaxExponentLength];
+ char buffer[kMaxExponentLength + 1];
+ buffer[kMaxExponentLength] = '\0';
int first_char_pos = kMaxExponentLength;
while (exponent > 0) {
buffer[--first_char_pos] = '0' + (exponent % 10);
@@ -157,8 +158,11 @@ void DoubleToStringConverter::CreateDecimalRepresentation(
}
-bool DoubleToStringConverter::ToShortest(double value,
- StringBuilder* result_builder) const {
+bool DoubleToStringConverter::ToShortestIeeeNumber(
+ double value,
+ StringBuilder* result_builder,
+ DoubleToStringConverter::DtoaMode mode) const {
+ ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE);
if (Double(value).IsSpecial()) {
return HandleSpecialValues(value, result_builder);
}
@@ -169,7 +173,7 @@ bool DoubleToStringConverter::ToShortest(double value,
char decimal_rep[kDecimalRepCapacity];
int decimal_rep_length;
- DoubleToAscii(value, SHORTEST, 0, decimal_rep, kDecimalRepCapacity,
+ DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
&sign, &decimal_rep_length, &decimal_point);
bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
@@ -338,6 +342,8 @@ static BignumDtoaMode DtoaToBignumDtoaMode(
DoubleToStringConverter::DtoaMode dtoa_mode) {
switch (dtoa_mode) {
case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST;
+ case DoubleToStringConverter::SHORTEST_SINGLE:
+ return BIGNUM_DTOA_SHORTEST_SINGLE;
case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED;
case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;
default:
@@ -357,7 +363,7 @@ void DoubleToStringConverter::DoubleToAscii(double v,
int* point) {
Vector<char> vector(buffer, buffer_length);
ASSERT(!Double(v).IsSpecial());
- ASSERT(mode == SHORTEST || requested_digits >= 0);
+ ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
if (Double(v).Sign() < 0) {
*sign = true;
@@ -385,6 +391,10 @@ void DoubleToStringConverter::DoubleToAscii(double v,
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;
@@ -454,14 +464,19 @@ static double SignedZero(bool sign) {
// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
template <int radix_log_2>
-static double RadixStringToDouble(const char* current,
- const char* end,
- bool sign,
- bool allow_trailing_junk,
- double junk_string_value,
- const char** trailing_pointer) {
+static double RadixStringToIeee(const char* current,
+ const char* end,
+ bool sign,
+ bool allow_trailing_junk,
+ double junk_string_value,
+ bool read_as_double,
+ const char** trailing_pointer) {
ASSERT(current != end);
+ const int kDoubleSize = Double::kSignificandSize;
+ const int kSingleSize = Single::kSignificandSize;
+ const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize;
+
// Skip leading 0s.
while (*current == '0') {
++current;
@@ -492,7 +507,7 @@ static double RadixStringToDouble(const char* current,
}
number = number * radix + digit;
- int overflow = static_cast<int>(number >> 53);
+ int overflow = static_cast<int>(number >> kSignificandSize);
if (overflow != 0) {
// Overflow occurred. Need to determine which direction to round the
// result.
@@ -531,7 +546,7 @@ static double RadixStringToDouble(const char* current,
}
// Rounding up may cause overflow.
- if ((number & ((int64_t)1 << 53)) != 0) {
+ if ((number & ((int64_t)1 << kSignificandSize)) != 0) {
exponent++;
number >>= 1;
}
@@ -540,7 +555,7 @@ static double RadixStringToDouble(const char* current,
++current;
} while (current != end);
- ASSERT(number < ((int64_t)1 << 53));
+ ASSERT(number < ((int64_t)1 << kSignificandSize));
ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
*trailing_pointer = current;
@@ -558,10 +573,11 @@ static double RadixStringToDouble(const char* current,
}
-double StringToDoubleConverter::StringToDouble(
+double StringToDoubleConverter::StringToIeee(
const char* input,
int length,
- int* processed_characters_count) {
+ int* processed_characters_count,
+ bool read_as_double) {
const char* current = input;
const char* end = input + length;
@@ -604,7 +620,6 @@ double StringToDoubleConverter::StringToDouble(
int significant_digits = 0;
int insignificant_digits = 0;
bool nonzero_digit_dropped = false;
- bool fractional_part = false;
bool sign = false;
@@ -676,12 +691,13 @@ double StringToDoubleConverter::StringToDouble(
}
const char* tail_pointer = NULL;
- double result = RadixStringToDouble<4>(current,
- end,
- sign,
- allow_trailing_junk,
- junk_string_value_,
- &tail_pointer);
+ double result = RadixStringToIeee<4>(current,
+ end,
+ sign,
+ allow_trailing_junk,
+ junk_string_value_,
+ read_as_double,
+ &tail_pointer);
if (tail_pointer != NULL) {
if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end);
*processed_characters_count = tail_pointer - input;
@@ -748,10 +764,8 @@ double StringToDoubleConverter::StringToDouble(
}
}
- // We don't emit a '.', but adjust the exponent instead.
- fractional_part = true;
-
// There is a fractional part.
+ // We don't emit a '.', but adjust the exponent instead.
while (*current >= '0' && *current <= '9') {
if (significant_digits < kMaxSignificantDigits) {
ASSERT(buffer_pos < kBufferSize);
@@ -842,12 +856,13 @@ double StringToDoubleConverter::StringToDouble(
if (octal) {
double result;
const char* tail_pointer = NULL;
- result = RadixStringToDouble<3>(buffer,
- buffer + buffer_pos,
- sign,
- allow_trailing_junk,
- junk_string_value_,
- &tail_pointer);
+ result = RadixStringToIeee<3>(buffer,
+ buffer + buffer_pos,
+ sign,
+ allow_trailing_junk,
+ junk_string_value_,
+ read_as_double,
+ &tail_pointer);
ASSERT(tail_pointer != NULL);
*processed_characters_count = current - input;
return result;
@@ -861,7 +876,12 @@ double StringToDoubleConverter::StringToDouble(
ASSERT(buffer_pos < kBufferSize);
buffer[buffer_pos] = '\0';
- double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
+ double converted;
+ if (read_as_double) {
+ converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
+ } else {
+ converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
+ }
*processed_characters_count = current - input;
return sign? -converted: converted;
}
52 double-conversion/src/double-conversion.h
View
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2012 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:
@@ -154,7 +154,14 @@ 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.
- bool ToShortest(double value, StringBuilder* result_builder) const;
+ bool ToShortest(double value, StringBuilder* result_builder) const {
+ return ToShortestIeeeNumber(value, result_builder, SHORTEST);
+ }
+
+ // Same as ToShortest, but for single-precision floats.
+ bool ToShortestSingle(float value, StringBuilder* result_builder) const {
+ return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE);
+ }
// Computes a decimal representation with a fixed number of digits after the
@@ -269,6 +276,8 @@ class DoubleToStringConverter {
// For example the output of 0.299999999999999988897 is (the less accurate
// but correct) 0.3.
SHORTEST,
+ // Same as SHORTEST, but for single-precision floats.
+ SHORTEST_SINGLE,
// Produce 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.
@@ -285,7 +294,11 @@ class DoubleToStringConverter {
// should be at least kBase10MaximalLength + 1 characters long.
static const int kBase10MaximalLength = 17;
- // Converts the given double 'v' to ascii.
+ // Converts the given double 'v' to ascii. '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 is, in this
+ // mode static_cast<float>(v) must not be NaN, +Infinity or -Infinity.
+ //
// The result should be interpreted as buffer * 10^(point-length).
//
// The output depends on the given mode:
@@ -296,6 +309,7 @@ class DoubleToStringConverter {
// 'v'. If there are two at the same distance, than the one farther away
// from 0 is chosen (halfway cases - ending with 5 - are rounded up).
// In this mode the 'requested_digits' parameter is ignored.
+ // - SHORTEST_SINGLE: same as SHORTEST but with single-precision.
// - 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 remainder
@@ -313,9 +327,11 @@ class DoubleToStringConverter {
// DoubleToAscii expects the given buffer to be big enough to hold all
// digits and a terminating null-character. In SHORTEST-mode it expects a
// buffer of at least kBase10MaximalLength + 1. In all other modes the
- // requested_digits parameter (+ 1 for the null-character) limits the size of
- // the output. The given length is only used in debug mode to ensure the
- // buffer is big enough.
+ // requested_digits parameter and the padding-zeroes limit the size of the
+ // output. Don't forget the decimal point, the exponent character and the
+ // terminating null-character when computing the maximal output size.
+ // The given length is only used in debug mode to ensure the buffer is big
+ // enough.
static void DoubleToAscii(double v,
DtoaMode mode,
int requested_digits,
@@ -326,6 +342,11 @@ class DoubleToStringConverter {
int* point);
private:
+ // Implementation for ToShortest and ToShortestSingle.
+ bool ToShortestIeeeNumber(double value,
+ StringBuilder* result_builder,
+ DtoaMode mode) const;
+
// If the value is a special value (NaN or Infinity) constructs the
// corresponding string using the configured infinity/nan-symbol.
// If either of them is NULL or the value is not special then the
@@ -481,7 +502,19 @@ class StringToDoubleConverter {
// in the 'processed_characters_count'. Trailing junk is never included.
double StringToDouble(const char* buffer,
int length,
- int* processed_characters_count);
+ int* processed_characters_count) {
+ return StringToIeee(buffer, length, processed_characters_count, true);
+ }
+
+ // Same as StringToDouble but reads a float.
+ // Note that this is not equivalent to static_cast<float>(StringToDouble(...))
+ // due to potential double-rounding.
+ float StringToFloat(const char* buffer,
+ int length,
+ int* processed_characters_count) {
+ return static_cast<float>(StringToIeee(buffer, length,
+ processed_characters_count, false));
+ }
private:
const int flags_;
@@ -490,6 +523,11 @@ class StringToDoubleConverter {
const char* const infinity_symbol_;
const char* const nan_symbol_;
+ double StringToIeee(const char* buffer,
+ int length,
+ int* processed_characters_count,
+ bool read_as_double);
+
DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
};
20 double-conversion/src/fast-dtoa.cc
View
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2012 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:
@@ -29,9 +29,7 @@
#include "cached-powers.h"
#include "diy-fp.h"
-#include "double.h"
-
-#include <stdio.h>
+#include "ieee.h"
namespace double_conversion {
@@ -243,7 +241,7 @@ static void BiggestPowerTen(uint32_t number,
int number_bits,
uint32_t* power,
int* exponent_plus_one) {
- ASSERT(number < (1 << (number_bits + 1)));
+ ASSERT(number < (1u << (number_bits + 1)));
// 1233/4096 is approximately 1/lg(10).
int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12);
// We increment to skip over the first entry in the kPowersOf10 table.
@@ -518,6 +516,7 @@ static bool DigitGenCounted(DiyFp w,
// digits might correctly yield 'v' when read again, the closest will be
// computed.
static bool Grisu3(double v,
+ FastDtoaMode mode,
Vector<char> buffer,
int* length,
int* decimal_exponent) {
@@ -527,7 +526,13 @@ static bool Grisu3(double v,
// boundary_minus and boundary_plus will round to v when convert to a double.
// Grisu3 will never output representations that lie exactly on a boundary.
DiyFp boundary_minus, boundary_plus;
- Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
+ if (mode == FAST_DTOA_SHORTEST) {
+ Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
+ } else {
+ ASSERT(mode == FAST_DTOA_SHORTEST_SINGLE);
+ float single_v = static_cast<float>(v);
+ Single(single_v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
+ }
ASSERT(boundary_plus.e() == w.e());
DiyFp ten_mk; // Cached power of ten: 10^-k
int mk; // -k
@@ -639,7 +644,8 @@ bool FastDtoa(double v,
int decimal_exponent = 0;
switch (mode) {
case FAST_DTOA_SHORTEST:
- result = Grisu3(v, buffer, length, &decimal_exponent);
+ case FAST_DTOA_SHORTEST_SINGLE:
+ result = Grisu3(v, mode, buffer, length, &decimal_exponent);
break;
case FAST_DTOA_PRECISION:
result = Grisu3Counted(v, requested_digits,
4 double-conversion/src/fast-dtoa.h
View
@@ -37,6 +37,8 @@ enum FastDtoaMode {
// result will be the most accurate number of this length. Longer
// representations might be more accurate.
FAST_DTOA_SHORTEST,
+ // Same as FAST_DTOA_SHORTEST but for single-precision floats.
+ FAST_DTOA_SHORTEST_SINGLE,
// Computes a representation where the precision (number of digits) is
// given as input. The precision is independent of the decimal point.
FAST_DTOA_PRECISION
@@ -45,6 +47,8 @@ enum FastDtoaMode {
// FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not
// include the terminating '\0' character.
static const int kFastDtoaMaximalLength = 17;
+// Same for single-precision numbers.
+static const int kFastDtoaMaximalSingleLength = 9;
// Provides a decimal representation of v.
// The result should be interpreted as buffer * 10^(point - length).
2  double-conversion/src/fixed-dtoa.cc
View
@@ -28,7 +28,7 @@
#include <math.h>
#include "fixed-dtoa.h"
-#include "double.h"
+#include "ieee.h"
namespace double_conversion {
171 double-conversion/src/double.h → double-conversion/src/ieee.h
View
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2012 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:
@@ -35,6 +35,8 @@ namespace double_conversion {
// We assume that doubles and uint64_t have the same endianness.
static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
+static uint32_t float_to_uint32(float f) { return BitCast<uint32_t>(f); }
+static float uint32_to_float(uint32_t d32) { return BitCast<float>(d32); }
// Helper functions for doubles.
class Double {
@@ -96,6 +98,16 @@ class Double {
}
}
+ double PreviousDouble() const {
+ if (d64_ == (kInfinity | kSignMask)) return -Double::Infinity();
+ if (Sign() < 0) {
+ return Double(d64_ + 1).value();
+ } else {
+ if (Significand() == 0) return -0.0;
+ return Double(d64_ - 1).value();
+ }
+ }
+
int Exponent() const {
if (IsDenormal()) return kDenormalExponent;
@@ -159,16 +171,9 @@ class Double {
void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
ASSERT(value() > 0.0);
DiyFp v = this->AsDiyFp();
- bool significand_is_zero = (v.f() == kHiddenBit);
DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
DiyFp m_minus;
- if (significand_is_zero && v.e() != kDenormalExponent) {
- // The boundary is closer. Think of v = 1000e10 and v- = 9999e9.
- // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
- // at a distance of 1e8.
- // The only exception is for the smallest normal: the largest denormal is
- // at the same distance as its successor.
- // Note: denormals have the same exponent as the smallest normals.
+ if (LowerBoundaryIsCloser()) {
m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
} else {
m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
@@ -179,6 +184,19 @@ class Double {
*out_m_minus = m_minus;
}
+ bool LowerBoundaryIsCloser() const {
+ // The boundary is closer if the significand is of the form f == 2^p-1 then
+ // the lower boundary is closer.
+ // Think of v = 1000e10 and v- = 9999e9.
+ // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+ // at a distance of 1e8.
+ // The only exception is for the smallest normal: the largest denormal is
+ // at the same distance as its successor.
+ // Note: denormals have the same exponent as the smallest normals.
+ bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0);
+ return physical_significand_is_zero && (Exponent() != kDenormalExponent);
+ }
+
double value() const { return uint64_to_double(d64_); }
// Returns the significand size for a given order of magnitude.
@@ -240,6 +258,141 @@ class Double {
}
};
+class Single {
+ public:
+ static const uint32_t kSignMask = 0x80000000;
+ static const uint32_t kExponentMask = 0x7F800000;
+ static const uint32_t kSignificandMask = 0x007FFFFF;
+ static const uint32_t kHiddenBit = 0x00800000;
+ static const int kPhysicalSignificandSize = 23; // Excludes the hidden bit.
+ static const int kSignificandSize = 24;
+
+ Single() : d32_(0) {}
+ explicit Single(float f) : d32_(float_to_uint32(f)) {}
+ explicit Single(uint32_t d32) : d32_(d32) {}
+
+ // The value encoded by this Single must be greater or equal to +0.0.
+ // It must not be special (infinity, or NaN).
+ DiyFp AsDiyFp() const {
+ ASSERT(Sign() > 0);
+ ASSERT(!IsSpecial());
+ return DiyFp(Significand(), Exponent());
+ }
+
+ // Returns the single's bit as uint64.
+ uint32_t AsUint32() const {
+ return d32_;
+ }
+
+ int Exponent() const {
+ if (IsDenormal()) return kDenormalExponent;
+
+ uint32_t d32 = AsUint32();
+ int biased_e =
+ static_cast<int>((d32 & kExponentMask) >> kPhysicalSignificandSize);
+ return biased_e - kExponentBias;
+ }
+
+ uint32_t Significand() const {
+ uint32_t d32 = AsUint32();
+ uint32_t significand = d32 & kSignificandMask;
+ if (!IsDenormal()) {
+ return significand + kHiddenBit;
+ } else {
+ return significand;
+ }
+ }
+
+ // Returns true if the single is a denormal.
+ bool IsDenormal() const {
+ uint32_t d32 = AsUint32();
+ return (d32 & kExponentMask) == 0;
+ }
+
+ // We consider denormals not to be special.
+ // Hence only Infinity and NaN are special.
+ bool IsSpecial() const {
+ uint32_t d32 = AsUint32();
+ return (d32 & kExponentMask) == kExponentMask;
+ }
+
+ bool IsNan() const {
+ uint32_t d32 = AsUint32();
+ return ((d32 & kExponentMask) == kExponentMask) &&
+ ((d32 & kSignificandMask) != 0);
+ }
+
+ bool IsInfinite() const {
+ uint32_t d32 = AsUint32();
+ return ((d32 & kExponentMask) == kExponentMask) &&
+ ((d32 & kSignificandMask) == 0);
+ }
+
+ int Sign() const {
+ uint32_t d32 = AsUint32();
+ return (d32 & kSignMask) == 0? 1: -1;
+ }
+
+ // Computes the two boundaries of this.
+ // The bigger boundary (m_plus) is normalized. The lower boundary has the same
+ // exponent as m_plus.
+ // Precondition: the value encoded by this Single must be greater than 0.
+ void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
+ ASSERT(value() > 0.0);
+ DiyFp v = this->AsDiyFp();
+ DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
+ DiyFp m_minus;
+ if (LowerBoundaryIsCloser()) {
+ m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
+ } else {
+ m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
+ }
+ m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
+ m_minus.set_e(m_plus.e());
+ *out_m_plus = m_plus;
+ *out_m_minus = m_minus;
+ }
+
+ // Precondition: the value encoded by this Single must be greater or equal
+ // than +0.0.
+ DiyFp UpperBoundary() const {
+ ASSERT(Sign() > 0);
+ return DiyFp(Significand() * 2 + 1, Exponent() - 1);
+ }
+
+ bool LowerBoundaryIsCloser() const {
+ // The boundary is closer if the significand is of the form f == 2^p-1 then
+ // the lower boundary is closer.
+ // Think of v = 1000e10 and v- = 9999e9.
+ // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+ // at a distance of 1e8.
+ // The only exception is for the smallest normal: the largest denormal is
+ // at the same distance as its successor.
+ // Note: denormals have the same exponent as the smallest normals.
+ bool physical_significand_is_zero = ((AsUint32() & kSignificandMask) == 0);
+ return physical_significand_is_zero && (Exponent() != kDenormalExponent);
+ }
+
+ float value() const { return uint32_to_float(d32_); }
+
+ static float Infinity() {
+ return Single(kInfinity).value();
+ }
+
+ static float NaN() {
+ return Single(kNaN).value();
+ }
+
+ private:
+ static const int kExponentBias = 0x7F + kPhysicalSignificandSize;
+ static const int kDenormalExponent = -kExponentBias + 1;
+ static const int kMaxExponent = 0xFF - kExponentBias;
+ static const uint32_t kInfinity = 0x7F800000;
+ static const uint32_t kNaN = 0x7FC00000;
+
+ const uint32_t d32_;
+};
+
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_DOUBLE_H_
205 double-conversion/src/strtod.cc
View
@@ -31,7 +31,7 @@
#include "strtod.h"
#include "bignum.h"
#include "cached-powers.h"
-#include "double.h"
+#include "ieee.h"
namespace double_conversion {
@@ -108,7 +108,7 @@ static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
}
-static void TrimToMaxSignificantDigits(Vector<const char> buffer,
+static void CutToMaxSignificantDigits(Vector<const char> buffer,
int exponent,
char* significant_buffer,
int* significant_exponent) {
@@ -125,6 +125,30 @@ static void TrimToMaxSignificantDigits(Vector<const char> buffer,
exponent + (buffer.length() - kMaxSignificantDecimalDigits);
}
+
+// Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits.
+// If possible the input-buffer is reused, but if the buffer needs to be
+// modified (due to cutting), then the input needs to be copied into the
+// buffer_copy_space.
+static void TrimAndCut(Vector<const char> buffer, int exponent,
+ char* buffer_copy_space, int space_size,
+ Vector<const char>* trimmed, int* updated_exponent) {
+ Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
+ Vector<const char> right_trimmed = TrimTrailingZeros(left_trimmed);
+ exponent += left_trimmed.length() - right_trimmed.length();
+ if (right_trimmed.length() > kMaxSignificantDecimalDigits) {
+ ASSERT(space_size >= kMaxSignificantDecimalDigits);
+ CutToMaxSignificantDigits(right_trimmed, exponent,
+ buffer_copy_space, updated_exponent);
+ *trimmed = Vector<const char>(buffer_copy_space,
+ kMaxSignificantDecimalDigits);
+ } else {
+ *trimmed = right_trimmed;
+ *updated_exponent = exponent;
+ }
+}
+
+
// Reads digits from the buffer and converts them to a uint64.
// Reads in as many digits as fit into a uint64.
// When the string starts with "1844674407370955161" no further digit is read.
@@ -357,22 +381,17 @@ static bool DiyFpStrtod(Vector<const char> buffer,
}
-// Returns the correct double for the buffer*10^exponent.
-// The variable guess should be a close guess that is either the correct double
-// or its lower neighbor (the nearest double less than the correct one).
+// Returns
+// - -1 if buffer*10^exponent < diy_fp.
+// - 0 if buffer*10^exponent == diy_fp.
+// - +1 if buffer*10^exponent > diy_fp.
// Preconditions:
// buffer.length() + exponent <= kMaxDecimalPower + 1
// buffer.length() + exponent > kMinDecimalPower
// buffer.length() <= kMaxDecimalSignificantDigits
-static double BignumStrtod(Vector<const char> buffer,
- int exponent,
- double guess) {
- if (guess == Double::Infinity()) {
- return guess;
- }
-
- DiyFp upper_boundary = Double(guess).UpperBoundary();
-
+static int CompareBufferWithDiyFp(Vector<const char> buffer,
+ int exponent,
+ DiyFp diy_fp) {
ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
ASSERT(buffer.length() + exponent > kMinDecimalPower);
ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
@@ -381,21 +400,65 @@ static double BignumStrtod(Vector<const char> buffer,
// consume at most one bigit (< 64 bits).
// ln(10) == 3.3219...
ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
- Bignum input;
- Bignum boundary;
- input.AssignDecimalString(buffer);
- boundary.AssignUInt64(upper_boundary.f());
+ Bignum buffer_bignum;
+ Bignum diy_fp_bignum;
+ buffer_bignum.AssignDecimalString(buffer);
+ diy_fp_bignum.AssignUInt64(diy_fp.f());
if (exponent >= 0) {
- input.MultiplyByPowerOfTen(exponent);
+ buffer_bignum.MultiplyByPowerOfTen(exponent);
} else {
- boundary.MultiplyByPowerOfTen(-exponent);
+ diy_fp_bignum.MultiplyByPowerOfTen(-exponent);
}
- if (upper_boundary.e() > 0) {
- boundary.ShiftLeft(upper_boundary.e());
+ if (diy_fp.e() > 0) {
+ diy_fp_bignum.ShiftLeft(diy_fp.e());
} else {
- input.ShiftLeft(-upper_boundary.e());
+ buffer_bignum.ShiftLeft(-diy_fp.e());
+ }
+ return Bignum::Compare(buffer_bignum, diy_fp_bignum);
+}
+
+
+// Returns true if the guess is the correct double.
+// Returns false, when guess is either correct or the next-lower double.
+static bool ComputeGuess(Vector<const char> trimmed, int exponent,
+ double* guess) {
+ if (trimmed.length() == 0) {
+ *guess = 0.0;
+ return true;
+ }
+ if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
+ *guess = Double::Infinity();
+ return true;
+ }
+ if (exponent + trimmed.length() <= kMinDecimalPower) {
+ *guess = 0.0;
+ return true;
+ }
+
+ if (DoubleStrtod(trimmed, exponent, guess) ||
+ DiyFpStrtod(trimmed, exponent, guess)) {
+ return true;
}
- int comparison = Bignum::Compare(input, boundary);
+ if (*guess == Double::Infinity()) {
+ return true;
+ }
+ return false;
+}
+
+double Strtod(Vector<const char> buffer, int exponent) {
+ char copy_buffer[kMaxSignificantDecimalDigits];
+ Vector<const char> trimmed;
+ int updated_exponent;
+ TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
+ &trimmed, &updated_exponent);
+ exponent = updated_exponent;
+
+ double guess;
+ bool is_correct = ComputeGuess(trimmed, exponent, &guess);
+ if (is_correct) return guess;
+
+ DiyFp upper_boundary = Double(guess).UpperBoundary();
+ int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
if (comparison < 0) {
return guess;
} else if (comparison > 0) {
@@ -408,34 +471,84 @@ static double BignumStrtod(Vector<const char> buffer,
}
}
-
-double Strtod(Vector<const char> buffer, int exponent) {
- Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
- Vector<const char> trimmed = TrimTrailingZeros(left_trimmed);
- exponent += left_trimmed.length() - trimmed.length();
- if (trimmed.length() == 0) return 0.0;
- if (trimmed.length() > kMaxSignificantDecimalDigits) {
- char significant_buffer[kMaxSignificantDecimalDigits];
- int significant_exponent;
- TrimToMaxSignificantDigits(trimmed, exponent,
- significant_buffer, &significant_exponent);
- return Strtod(Vector<const char>(significant_buffer,
- kMaxSignificantDecimalDigits),
- significant_exponent);
+float Strtof(Vector<const char> buffer, int exponent) {
+ char copy_buffer[kMaxSignificantDecimalDigits];
+ Vector<const char> trimmed;
+ int updated_exponent;
+ TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
+ &trimmed, &updated_exponent);
+ exponent = updated_exponent;
+
+ double double_guess;
+ bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
+
+ float float_guess = static_cast<float>(double_guess);
+ if (float_guess == double_guess) {
+ // This shortcut triggers for integer values.
+ return float_guess;
}
- if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
- return Double::Infinity();
+
+ // We must catch double-rounding. Say the double has been rounded up, and is
+ // now a boundary of a float, and rounds up again. This is why we have to
+ // look at previous too.
+ // Example (in decimal numbers):
+ // input: 12349
+ // high-precision (4 digits): 1235
+ // low-precision (3 digits):
+ // when read from input: 123
+ // when rounded from high precision: 124.
+ // To do this we simply look at the neigbors of the correct result and see
+ // if they would round to the same float. If the guess is not correct we have
+ // to look at four values (since two different doubles could be the correct
+ // double).
+
+ double double_next = Double(double_guess).NextDouble();
+ double double_previous = Double(double_guess).PreviousDouble();
+
+ float f1 = static_cast<float>(double_previous);
+ float f2 = float_guess;
+ float f3 = static_cast<float>(double_next);
+ float f4;
+ if (is_correct) {
+ f4 = f3;
+ } else {
+ double double_next2 = Double(double_next).NextDouble();
+ f4 = static_cast<float>(double_next2);
}
- if (exponent + trimmed.length() <= kMinDecimalPower) {
- return 0.0;
+ ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
+
+ // If the guess doesn't lie near a single-precision boundary we can simply
+ // return its float-value.
+ if (f1 == f4) {
+ return float_guess;
}
- double guess;
- if (DoubleStrtod(trimmed, exponent, &guess) ||
- DiyFpStrtod(trimmed, exponent, &guess)) {
+ ASSERT((f1 != f2 && f2 == f3 && f3 == f4) ||
+ (f1 == f2 && f2 != f3 && f3 == f4) ||
+ (f1 == f2 && f2 == f3 && f3 != f4));
+
+ // guess and next are the two possible canditates (in the same way that
+ // double_guess was the lower candidate for a double-precision guess).
+ float guess = f1;
+ float next = f4;
+ DiyFp upper_boundary;
+ if (guess == 0.0f) {
+ float min_float = 1e-45f;
+ upper_boundary = Double(static_cast<double>(min_float) / 2).AsDiyFp();
+ } else {
+ upper_boundary = Single(guess).UpperBoundary();
+ }
+ int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
+ if (comparison < 0) {
+ return guess;
+ } else if (comparison > 0) {
+ return next;
+ } else if ((Single(guess).Significand() & 1) == 0) {
+ // Round towards even.
return guess;
+ } else {
+ return next;
}
- return BignumStrtod(trimmed, exponent, guess);
}
} // namespace double_conversion
4 double-conversion/src/strtod.h
View
@@ -36,6 +36,10 @@ namespace double_conversion {
// contain a dot or a sign. It must not start with '0', and must not be empty.
double Strtod(Vector<const char> buffer, int exponent);
+// The buffer must only contain digits in the range [0-9]. It must not
+// contain a dot or a sign. It must not start with '0', and must not be empty.
+float Strtof(Vector<const char> buffer, int exponent);
+
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_STRTOD_H_
26 double-conversion/src/utils.h
View
@@ -32,9 +32,15 @@
#include <string.h>
#include <assert.h>
+#ifndef ASSERT
#define ASSERT(condition) (assert(condition))
+#endif
+#ifndef UNIMPLEMENTED
#define UNIMPLEMENTED() (abort())
+#endif
+#ifndef UNREACHABLE
#define UNREACHABLE() (abort())
+#endif
// Double operations detection based on target architecture.
// Linux uses a 80bit wide floating point stack on x86. This induces double
@@ -47,10 +53,14 @@
// disabled.)
// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
#if defined(_M_X64) || defined(__x86_64__) || \
- defined(__ARMEL__) || \
+ defined(__ARMEL__) || defined(__avr32__) || \
+ defined(__hppa__) || defined(__ia64__) || \
+ defined(__mips__) || defined(__powerpc__) || \
+ defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
+ defined(__SH4__) || defined(__alpha__) || \
defined(_MIPS_ARCH_MIPS32R2)
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#elif defined(_M_IX86) || defined(__i386__)
+#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
#if defined(_WIN32)
// Windows uses a 64bit wide floating point stack.
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
@@ -90,15 +100,19 @@ typedef unsigned __int64 uint64_t;
// size_t which represents the number of elements of the given
// array. You should only use ARRAY_SIZE on statically allocated
// arrays.
+#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+#endif
// A macro to disallow the evil copy constructor and operator= functions
// This should be used in the private: declarations for a class
+#ifndef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
+#endif
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
@@ -106,9 +120,11 @@ typedef unsigned __int64 uint64_t;
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
+#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName(); \
DISALLOW_COPY_AND_ASSIGN(TypeName)
+#endif
namespace double_conversion {
@@ -218,7 +234,7 @@ class StringBuilder {
void AddSubstring(const char* s, int n) {
ASSERT(!is_finalized() && position_ + n < buffer_.length());
ASSERT(static_cast<size_t>(n) <= strlen(s));
- memcpy(&buffer_[position_], s, n * kCharSize);
+ memmove(&buffer_[position_], s, n * kCharSize);
position_ += n;
}
@@ -283,7 +299,7 @@ inline Dest BitCast(const Source& source) {
typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
Dest dest;
- memcpy(&dest, &source, sizeof(dest));
+ memmove(&dest, &source, sizeof(dest));
return dest;
}
@@ -294,4 +310,4 @@ inline Dest BitCast(Source* source) {
} // namespace double_conversion
-#endif // DOUBLE_CONVERSION_UTILS_H_
+#endif // DOUBLE_CONVERSION_UTILS_H_
3  double-conversion/test/cctest/SConscript
View
@@ -3,14 +3,15 @@ double_conversion_test_sources = [
'gay-fixed.cc',
'gay-precision.cc',
'gay-shortest.cc',
+ 'gay-shortest-single.cc',
'test-bignum.cc',
'test-bignum-dtoa.cc',
'test-conversions.cc',
'test-diy-fp.cc',
- 'test-double.cc',
'test-dtoa.cc',
'test-fast-dtoa.cc',
'test-fixed-dtoa.cc',
+ 'test-ieee.cc',
'test-strtod.cc',
]
Return('double_conversion_test_sources')
10,049 double-conversion/test/cctest/gay-shortest-single.cc
View
10,049 additions, 0 deletions not shown
44 double-conversion/test/cctest/gay-shortest-single.h
View
@@ -0,0 +1,44 @@
+// Copyright 2011, 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 GAY_SHORTEST_SINGLE_H_
+#define GAY_SHORTEST_SINGLE_H_
+
+namespace double_conversion {
+
+struct PrecomputedShortestSingle {
+ float v;
+ const char* representation;
+ int decimal_point;
+};
+
+Vector<const PrecomputedShortestSingle>
+ PrecomputedShortestSingleRepresentations();
+
+} // namespace double_conversion
+
+#endif // GAY_SHORTEST_SINGLE_H_
86 double-conversion/test/cctest/test-bignum-dtoa.cc
View
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2012 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:
@@ -30,10 +30,11 @@
#include "bignum-dtoa.h"
#include "cctest.h"
-#include "double.h"
#include "gay-fixed.h"
#include "gay-precision.h"
#include "gay-shortest.h"
+#include "gay-shortest-single.h"
+#include "ieee.h"
#include "utils.h"
using namespace double_conversion;
@@ -252,6 +253,69 @@ TEST(BignumDtoaVariousDoubles) {
}
+TEST(BignumDtoaShortestVariousFloats) {
+ char buffer_container[kBufferSize];
+ Vector<char> buffer(buffer_container, kBufferSize);
+ int length;
+ int point;
+
+ float min_float = 1e-45f;
+ BignumDtoa(min_float, BIGNUM_DTOA_SHORTEST_SINGLE, 0,
+ buffer, &length, &point);
+ CHECK_EQ("1", buffer.start());
+ CHECK_EQ(-44, point);
+
+
+ float max_float = 3.4028234e38f;
+ BignumDtoa(max_float, BIGNUM_DTOA_SHORTEST_SINGLE, 0,
+ buffer, &length, &point);
+ CHECK_EQ("34028235", buffer.start());
+ CHECK_EQ(39, point);
+
+ BignumDtoa(4294967272.0f, BIGNUM_DTOA_SHORTEST_SINGLE, 0,
+ buffer, &length, &point);
+ CHECK_EQ("42949673", buffer.start());
+ CHECK_EQ(10, point);
+
+ BignumDtoa(3.32306998946228968226e+35f, BIGNUM_DTOA_SHORTEST_SINGLE, 0,
+ buffer, &length, &point);
+ CHECK_EQ("332307", buffer.start());
+ CHECK_EQ(36, point);
+
+ BignumDtoa(1.23405349260765015351e-41f, BIGNUM_DTOA_SHORTEST_SINGLE, 0,
+ buffer, &length, &point);
+ CHECK_EQ("12341", buffer.start());
+ CHECK_EQ(-40, point);
+
+ BignumDtoa(3.3554432e7, BIGNUM_DTOA_SHORTEST_SINGLE, 0,
+ buffer, &length, &point);
+ CHECK_EQ("33554432", buffer.start());
+ CHECK_EQ(8, point);
+
+ BignumDtoa(3.26494756798464e14f, BIGNUM_DTOA_SHORTEST_SINGLE, 0,
+ buffer, &length, &point);
+ CHECK_EQ("32649476", buffer.start());
+ CHECK_EQ(15, point);
+
+ BignumDtoa(3.91132223637771935344e37f, BIGNUM_DTOA_SHORTEST_SINGLE, 0,
+ buffer, &length, &point);
+ CHECK_EQ("39113222", buffer.start());
+ CHECK_EQ(38, point);
+
+ uint32_t smallest_normal32 = 0x00800000;
+ double v = Single(smallest_normal32).value();
+ BignumDtoa(v, BIGNUM_DTOA_SHORTEST_SINGLE, 0, buffer, &length, &point);
+ CHECK_EQ("11754944", buffer.start());
+ CHECK_EQ(-37, point);
+
+ uint32_t largest_denormal32 = 0x007FFFFF;
+ v = Single(largest_denormal32).value();
+ BignumDtoa(v, BIGNUM_DTOA_SHORTEST_SINGLE, 0, buffer, &length, &point);
+ CHECK_EQ("11754942", buffer.start());
+ CHECK_EQ(-37, point);
+}
+
+
TEST(BignumDtoaGayShortest) {
char buffer_container[kBufferSize];
Vector<char> buffer(buffer_container, kBufferSize);
@@ -270,6 +334,24 @@ TEST(BignumDtoaGayShortest) {
}
+TEST(BignumDtoaGayShortestSingle) {
+ char buffer_container[kBufferSize];
+ Vector<char> buffer(buffer_container, kBufferSize);
+ int length;
+ int point;
+
+ Vector<const PrecomputedShortestSingle> precomputed =
+ PrecomputedShortestSingleRepresentations();
+ for (int i = 0; i < precomputed.length(); ++i) {
+ const PrecomputedShortestSingle current_test = precomputed[i];
+ float v = current_test.v;
+ BignumDtoa(v, BIGNUM_DTOA_SHORTEST_SINGLE, 0, buffer, &length, &point);
+ CHECK_EQ(current_test.decimal_point, point);
+ CHECK_EQ(current_test.representation, buffer.start());
+ }
+}
+
+
TEST(BignumDtoaGayFixed) {
char buffer_container[kBufferSize];
Vector<char> buffer(buffer_container, kBufferSize);
1,538 double-conversion/test/cctest/test-conversions.cc
View
@@ -1,10 +1,10 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
#include <string.h>
#include "cctest.h"
-#include "double.h"
#include "double-conversion.h"
+#include "ieee.h"
#include "utils.h"
// DoubleToString is already tested in test-dtoa.cc.
@@ -168,6 +168,162 @@ TEST(DoubleToShortest) {
}
+TEST(DoubleToShortestSingle) {
+ const int kBufferSize = 128;
+ char buffer[kBufferSize];
+ StringBuilder builder(buffer, kBufferSize);
+ int flags = DoubleToStringConverter::UNIQUE_ZERO |
+ DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
+ DoubleToStringConverter dc(flags, NULL, NULL, 'e', -6, 21, 0, 0);
+
+ CHECK(dc.ToShortestSingle(0.0f, &builder));
+ CHECK_EQ("0", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(12345.0f, &builder));
+ CHECK_EQ("12345", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(12345e23f, &builder));
+ CHECK_EQ("1.2345e+27", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(1e21f, &builder));
+ CHECK_EQ("1e+21", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(1e20f, &builder));
+ CHECK_EQ("100000000000000000000", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(111111111111111111111.0f, &builder));
+ CHECK_EQ("111111110000000000000", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(1111111111111111111111.0f, &builder));
+ CHECK_EQ("1.11111114e+21", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(11111111111111111111111.0f, &builder));
+ CHECK_EQ("1.1111111e+22", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(-0.00001f, &builder));
+ CHECK_EQ("-0.00001", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(-0.000001f, &builder));
+ CHECK_EQ("-0.000001", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(-0.0000001f, &builder));
+ CHECK_EQ("-1e-7", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc.ToShortestSingle(-0.0f, &builder));
+ CHECK_EQ("0", builder.Finalize());
+
+ flags = DoubleToStringConverter::NO_FLAGS;
+ DoubleToStringConverter dc2(flags, NULL, NULL, 'e', -1, 1, 0, 0);
+ builder.Reset();
+ CHECK(dc2.ToShortestSingle(0.1f, &builder));
+ CHECK_EQ("0.1", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc2.ToShortestSingle(0.01f, &builder));
+ CHECK_EQ("1e-2", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc2.ToShortestSingle(1.0f, &builder));
+ CHECK_EQ("1", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc2.ToShortestSingle(10.0f, &builder));
+ CHECK_EQ("1e1", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc2.ToShortestSingle(-0.0f, &builder));
+ CHECK_EQ("-0", builder.Finalize());
+
+ flags = DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT |
+ DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT;
+ DoubleToStringConverter dc3(flags, NULL, NULL, 'E', -5, 5, 0, 0);
+
+ builder.Reset();
+ CHECK(dc3.ToShortestSingle(0.1f, &builder));
+ CHECK_EQ("0.1", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc3.ToShortestSingle(1.0f, &builder));
+ CHECK_EQ("1.0", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc3.ToShortestSingle(10000.0f, &builder));
+ CHECK_EQ("10000.0", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc3.ToShortestSingle(100000.0f, &builder));
+ CHECK_EQ("1E5", builder.Finalize());
+
+ // Test the examples in the comments of ToShortestSingle.
+ flags = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
+ DoubleToStringConverter dc4(flags, NULL, NULL, 'e', -6, 21, 0, 0);
+
+ builder.Reset();
+ CHECK(dc4.ToShortestSingle(0.000001f, &builder));
+ CHECK_EQ("0.000001", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc4.ToShortestSingle(0.0000001f, &builder));
+ CHECK_EQ("1e-7", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc4.ToShortestSingle(111111111111111111111.0f, &builder));
+ CHECK_EQ("111111110000000000000", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc4.ToShortestSingle(100000000000000000000.0f, &builder));
+ CHECK_EQ("100000000000000000000", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc4.ToShortestSingle(1111111111111111111111.0f, &builder));
+ CHECK_EQ("1.11111114e+21", builder.Finalize());
+
+ // Test special value handling.
+ DoubleToStringConverter dc5(flags, NULL, NULL, 'e', 0, 0, 0, 0);
+
+ builder.Reset();
+ CHECK(!dc5.ToShortestSingle(Single::Infinity(), &builder));
+
+ builder.Reset();
+ CHECK(!dc5.ToShortestSingle(-Single::Infinity(), &builder));
+
+ builder.Reset();
+ CHECK(!dc5.ToShortestSingle(Single::NaN(), &builder));
+
+ builder.Reset();
+ CHECK(!dc5.ToShortestSingle(-Single::NaN(), &builder));
+
+ DoubleToStringConverter dc6(flags, "Infinity", "NaN", 'e', 0, 0, 0, 0);
+
+ builder.Reset();
+ CHECK(dc6.ToShortestSingle(Single::Infinity(), &builder));
+ CHECK_EQ("Infinity", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc6.ToShortestSingle(-Single::Infinity(), &builder));
+ CHECK_EQ("-Infinity", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc6.ToShortestSingle(Single::NaN(), &builder));
+ CHECK_EQ("NaN", builder.Finalize());
+
+ builder.Reset();
+ CHECK(dc6.ToShortestSingle(-Single::NaN(), &builder));
+ CHECK_EQ("NaN", builder.Finalize());
+}
+
+
TEST(DoubleToFixed) {
const int kBufferSize = 128;
char buffer[kBufferSize];
@@ -1568,7 +1724,8 @@ static double StrToD(const char* str, int flags, double empty_string_value,
NULL, NULL);
double result = converter.StringToDouble(str, strlen(str),
processed_characters_count);
- *processed_all = ((strlen(str) == *processed_characters_count));
+ *processed_all =
+ ((strlen(str) == static_cast<unsigned>(*processed_characters_count)));
return result;
}
@@ -3037,3 +3194,1378 @@ TEST(StringToDoubleCommentExamples) {
CHECK_EQ(Double::NaN(), StrToD("NaN", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);
}
+
+
+static float StrToF(const char* str, int flags, float empty_string_value,
+ int* processed_characters_count, bool* processed_all) {
+ StringToDoubleConverter converter(flags, empty_string_value, Single::NaN(),
+ NULL, NULL);
+ float result = converter.StringToFloat(str, strlen(str),
+ processed_characters_count);
+ *processed_all =
+ ((strlen(str) == static_cast<unsigned>(*processed_characters_count)));
+ return result;
+}
+
+
+TEST(StringToFloatVarious) {
+ int flags;
+ int processed;
+ bool all_used;
+
+ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN |
+ StringToDoubleConverter::ALLOW_TRAILING_SPACES;
+
+ CHECK_EQ(0.0f, StrToF("", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF("", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(0.0f, StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(42.0f, StrToF("42", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(42.0f, StrToF(" + 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(-42.0f, StrToF(" - 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Double::NaN(), StrToF("x", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" x", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF("42x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF("42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" + 42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" - 42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+
+ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN |
+ StringToDoubleConverter::ALLOW_TRAILING_SPACES |
+ StringToDoubleConverter::ALLOW_TRAILING_JUNK;
+
+ CHECK_EQ(0.0f, StrToF("", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF("", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(0.0f, StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(42.0f, StrToF("42", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(42.0f, StrToF(" + 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(-42.0f, StrToF(" - 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Double::NaN(), StrToF("x", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" x", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(42.0f, StrToF("42x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(2, processed);
+
+ CHECK_EQ(42.0f, StrToF("42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(3, processed);
+
+ CHECK_EQ(42.0f, StrToF(" + 42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(6, processed);
+
+ CHECK_EQ(-42.0f, StrToF(" - 42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(6, processed);
+
+
+ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN |
+ StringToDoubleConverter::ALLOW_TRAILING_JUNK;
+
+ CHECK_EQ(0.0f, StrToF("", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF("", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(0.0f, StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(42.0f, StrToF("42", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(42.0f, StrToF(" + 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(5, processed);
+
+ CHECK_EQ(-42.0f, StrToF(" - 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(5, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF("x", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" x", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(42.0f, StrToF("42x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(2, processed);
+
+ CHECK_EQ(42.0f, StrToF("42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(2, processed);
+
+ CHECK_EQ(42.0f, StrToF(" + 42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(5, processed);
+
+ CHECK_EQ(-42.0f, StrToF(" - 42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(5, processed);
+
+ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
+ StringToDoubleConverter::ALLOW_TRAILING_JUNK;
+
+ CHECK_EQ(42.0f, StrToF(" +42 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(4, processed);
+
+ CHECK_EQ(-42.0f, StrToF(" -42 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(4, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" + 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" - 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+
+ flags = StringToDoubleConverter::NO_FLAGS;
+
+ CHECK_EQ(0.0f, StrToF("", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF("", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Double::NaN(), StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(42.0f, StrToF("42", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Double::NaN(), StrToF(" + 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" - 42 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF("x", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" x", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF("42x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF("42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" + 42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Double::NaN(), StrToF(" - 42 x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+
+ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES;
+
+ CHECK_EQ(0.0f, StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(42.0f, StrToF(" 42", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Double::NaN(), StrToF("42 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+
+ flags = StringToDoubleConverter::ALLOW_TRAILING_SPACES;
+
+ CHECK_EQ(0.0f, StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(42.0f, StrToF("42 ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Double::NaN(), StrToF(" 42", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+}
+
+TEST(StringToFloatEmptyString) {
+ int flags;
+ int processed;
+ bool all_used;
+
+ flags = StringToDoubleConverter::NO_FLAGS;
+ CHECK_EQ(0.0f, StrToF("", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF("", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF("", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ flags = StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN;
+ CHECK_EQ(0.0f, StrToF("", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF("", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF("", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES;
+ CHECK_EQ(0.0f, StrToF("", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF("", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF("", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(0.0f, StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK(all_used);
+
+ flags = StringToDoubleConverter::ALLOW_TRAILING_SPACES;
+ CHECK_EQ(0.0f, StrToF("", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF("", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF("", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(0.0f, StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK(all_used);
+
+ flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK;
+ CHECK_EQ(0.0f, StrToF("", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(1.0f, StrToF("", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF("", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" x", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+}
+
+TEST(StringToFloatHexString) {
+ int flags;
+ int processed;
+ bool all_used;
+ double d;
+ float f;
+
+ flags = StringToDoubleConverter::ALLOW_HEX |
+ StringToDoubleConverter::ALLOW_LEADING_SPACES |
+ StringToDoubleConverter::ALLOW_TRAILING_SPACES |
+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN;
+
+ // Check that no double rounding occurs:
+ const char* double_rounding_example1 = "0x100000100000008";
+ d = StrToD(double_rounding_example1, flags, 0.0, &processed, &all_used);
+ f = StrToF(double_rounding_example1, flags, 0.0f, &processed, &all_used);
+ CHECK(f != static_cast<float>(d));
+ CHECK_EQ(72057602627862528.0f, StrToF(double_rounding_example1,
+ flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ const char* double_rounding_example2 = "0x1000002FFFFFFF8";
+ d = StrToD(double_rounding_example2, flags, 0.0, &processed, &all_used);
+ f = StrToF(double_rounding_example2, flags, 0.0f, &processed, &all_used);
+ CHECK(f != static_cast<float>(d));
+ CHECK_EQ(72057602627862528.0f, StrToF(double_rounding_example2,
+ flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(18.0f, StrToF("0x12", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(0.0f, StrToF("0x0", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(static_cast<float>(0x123456789),
+ StrToF("0x123456789", flags, Single::NaN(), &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(18.0f, StrToF(" 0x12 ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(0.0f, StrToF(" 0x0 ", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(static_cast<float>(0x123456789),
+ StrToF(" 0x123456789 ", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(static_cast<float>(0xabcdef),
+ StrToF("0xabcdef", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(static_cast<float>(0xabcdef),
+ StrToF("0xABCDEF", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(static_cast<float>(0xabcdef),
+ StrToF(" 0xabcdef ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(static_cast<float>(0xabcdef),
+ StrToF(" 0xABCDEF ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF(" ", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF("0x", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" 0x ", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" 0x 3", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("0x3g", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("0x3.23", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("x3", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("0x3 foo", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" 0x3 foo", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("+ 0x3 foo", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("+", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("-", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(-5.0f, StrToF("-0x5", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(-5.0f, StrToF(" - 0x5 ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(5.0f, StrToF(" + 0x5 ", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF("- -0x5", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("- +0x5", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ flags = StringToDoubleConverter::ALLOW_HEX;
+
+ CHECK_EQ(18.0f, StrToF("0x12", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(0.0f, StrToF("0x0", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(static_cast<float>(0x123456789),
+ StrToF("0x123456789", flags, Single::NaN(), &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF(" 0x12 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" 0x0 ", flags, 1.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" 0x123456789 ", flags, Single::NaN(),
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(static_cast<float>(0xabcdef),
+ StrToF("0xabcdef", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(static_cast<float>(0xabcdef),
+ StrToF("0xABCDEF", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(),
+ StrToF(" 0xabcdef ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(),
+ StrToF(" 0xABCDEF ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(),
+ StrToF(" ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("0x", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" 0x ", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" 0x 3", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("0x3g", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("0x3.23", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("x3", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("+ 0x3 foo", flags, 0.0f,
+ &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("+", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("-", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(-5.0f, StrToF("-0x5", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(Single::NaN(), StrToF(" - 0x5 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF(" + 0x5 ", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("- -0x5", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("- +0x5", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0f, &processed, &all_used));
+ CHECK_EQ(0, processed);
+
+ flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK |
+ StringToDoubleConverter::ALLOW_HEX;
+
+ CHECK_EQ(18.0f, StrToF("0x12", flags, 0.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(0.0f, StrToF("0x0", flags, 1.0f, &processed, &all_used));
+ CHECK(all_used);
+
+ CHECK_EQ(static_cast<float>(0x123456789),