Commits

Anonymous committed baa5675

Support for reading floats.

  • Participants
  • Parent commits 20f2487
  • Branches single

Comments (0)

Files changed (9)

 
   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;

src/double-conversion.cc

 
 // 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;
     }
 
     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.
       }
 
       // Rounding up may cause overflow.
-      if ((number & ((int64_t)1 << 53)) != 0) {
+      if ((number & ((int64_t)1 << kSignificandSize)) != 0) {
         exponent++;
         number >>= 1;
       }
     ++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;
 }
 
 
-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;
 
       }
 
       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;
   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;
   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;
 }

src/double-conversion.h

   // 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_;
   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);
 };
 
     }
   }
 
+  double PreviousDouble() const {
+    if (d64_ == (kInfinity | kSignMask)) return -Double::Infinity();
+    if (Sign() > 0 && Significand() == 0) {
+      return -0.0;
+    }
+    if (Sign() < 0) {
+      return Double(d64_ + 1).value();
+    } else {
+      return Double(d64_ - 1).value();
+    }
+  }
+
   int Exponent() const {
     if (IsDenormal()) return kDenormalExponent;
 
     *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.
 }
 
 
-static void TrimToMaxSignificantDigits(Vector<const char> buffer,
+static void CutToMaxSignificantDigits(Vector<const char> buffer,
                                        int exponent,
                                        char* significant_buffer,
                                        int* significant_exponent) {
       exponent + (buffer.length() - kMaxSignificantDecimalDigits);
 }
 
+
+// Trims the buffer and cuts it to at moste 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.
 }
 
 
-// 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);
   // 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());
   }
-  int comparison = Bignum::Compare(input, boundary);
+  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;
+  }
+  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 isCorrect = ComputeGuess(trimmed, exponent, &guess);
+  if (isCorrect) return guess;
+
+  DiyFp upper_boundary = Double(guess).UpperBoundary();
+  int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
   if (comparison < 0) {
     return guess;
   } else if (comparison > 0) {
   }
 }
 
+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 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);
-  }
-  if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
-    return Double::Infinity();
-  }
-  if (exponent + trimmed.length() <= kMinDecimalPower) {
-    return 0.0;
+  double double_guess;
+  bool isCorrect = 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;
   }
 
-  double guess;
-  if (DoubleStrtod(trimmed, exponent, &guess) ||
-      DiyFpStrtod(trimmed, exponent, &guess)) {
+  // 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 (isCorrect) {
+    f4 = f3;
+  } else {
+    double double_next2 = Double(double_next).NextDouble();
+    f4 = static_cast<float>(double_next2);
+  }
+
+  // If the guess doesn't lie near a single-precision boundary we can simply
+  // return its float-value.
+  if ((f1 == f2) && (f2 == f3) && (f3 == f4)) {
+    return float_guess;
+  }
+
+  // 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;
+  float next;
+  if (f1 != f2) {
+    ASSERT(f2 == f3 && f3 == f4);
+    guess = f1;
+    next = f2;
+  } else if (f2 != f3) {
+    ASSERT(f3 == f4);
+    guess = f2;
+    next = f3;
+  } else {
+    guess = f3;
+    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
 // 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_

test/cctest/test-conversions.cc

   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) == *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),
+           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(18.0f, StrToF("0x12 ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(4, processed);
+
+  CHECK_EQ(0.0f, StrToF("0x0 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(3, 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(static_cast<float>(0xabcdef),
+           StrToF("0xabcdef ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(8, processed);
+
+  CHECK_EQ(static_cast<float>(0xabcdef),
+           StrToF("0xABCDEF ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(8, processed);
+
+  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(3.0f, StrToF("0x3g", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(3.0f, StrToF("0x3.234", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 0x3g", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 0x3.234", 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_LEADING_SPACES |
+      StringToDoubleConverter::ALLOW_TRAILING_SPACES |
+      StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN |
+      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(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(static_cast<float>(0xabc),
+           StrToF(" 0xabc def ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(7, processed);
+
+  CHECK_EQ(static_cast<float>(0xabc),
+           StrToF(" 0xABC DEF ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(7, processed);
+
+  CHECK_EQ(static_cast<float>(0x12),
+           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(" ", 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((float)0x3, StrToF("0x3g", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ((float)0x3, StrToF("0x3.234", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("x3", flags, 0.0f,
+                                 &processed, &all_used));
+  CHECK_EQ(0, processed);
+}
+
+
+TEST(StringToFloatOctalString) {
+  int flags;
+  int processed;
+  bool all_used;
+  double d;
+  float f;
+
+  flags = StringToDoubleConverter::ALLOW_OCTALS |
+      StringToDoubleConverter::ALLOW_LEADING_SPACES |
+      StringToDoubleConverter::ALLOW_TRAILING_SPACES |
+      StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN;
+
+  // Check that no double rounding occurs:
+  const char* double_rounding_example1 = "04000000040000000010";
+  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 = "04000000137777777770";
+  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(10.0f, StrToF("012", flags, 0.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0f, StrToF("00", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF("012", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF(" 012", flags, 0.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0f, StrToF(" 00", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF(" 012", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(123456789.0f,
+           StrToF(" 0123456789", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF(" 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF(" + 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF(" - 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF(" 012 ", flags, 0.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0f, StrToF(" 00 ", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF(" 012 ", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(123456789.0f,
+           StrToF(" 0123456789 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF(" 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF(" + 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF(" - 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF("012 ", flags, 0.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0f, StrToF("00 ", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF("012 ", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF("01234567e0", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+
+  flags = StringToDoubleConverter::ALLOW_OCTALS;
+  CHECK_EQ(10.0f, StrToF("012", flags, 0.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0f, StrToF("00", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF("012", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 00", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 0123456789", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" + 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" - 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012 ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 00 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 0123456789 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" + 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" - 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("012 ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("00 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("012 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF("0123456789 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF("01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF("01234567e0", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+
+  flags = StringToDoubleConverter::ALLOW_OCTALS |
+      StringToDoubleConverter::ALLOW_TRAILING_JUNK;
+  CHECK_EQ(10.0f, StrToF("012", flags, 0.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0f, StrToF("00", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF("012", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 00", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 0123456789", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" + 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" - 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012 ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 00 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 0123456789 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" + 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" - 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(10.0f, StrToF("012 ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(0.0f, StrToF("00 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(2, processed);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(10, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(8, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF("012foo ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(0.0f, StrToF("00foo ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(2, processed);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789foo ", flags, Single::NaN(),
+                  &processed, &all_used));
+  CHECK_EQ(10, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567foo ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(8, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567foo", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(9, processed);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567foo", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(9, processed);
+
+  CHECK_EQ(10.0f, StrToF("012 foo ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(0.0f, StrToF("00 foo ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(2, processed);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789 foo ", flags, Single::NaN(),
+                  &processed, &all_used));
+  CHECK_EQ(10, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567 foo ", flags, Single::NaN(),
+                  &processed, &all_used));
+  CHECK_EQ(8, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567 foo", flags, Single::NaN(),
+                  &processed, &all_used));
+  CHECK_EQ(9, processed);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567 foo", flags, Single::NaN(), &processed,
+                  &all_used));
+  CHECK_EQ(9, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567e0", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(8, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567e", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(8, processed);
+
+  flags = StringToDoubleConverter::ALLOW_OCTALS |
+      StringToDoubleConverter::ALLOW_TRAILING_SPACES |
+      StringToDoubleConverter::ALLOW_TRAILING_JUNK;
+  CHECK_EQ(10.0f, StrToF("012", flags, 0.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0f, StrToF("00", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF("012", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 00", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 0123456789", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" + 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" - 01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012 ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 00 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF(" 012 ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 0123456789 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" + 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(),
+           StrToF(" - 01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(10.0f, StrToF("012 ", flags, 0.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0f, StrToF("00 ", flags, 1.0f, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567 ", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567", flags, Single::NaN(), &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(10.0f, StrToF("012foo ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(0.0f, StrToF("00foo ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(2, processed);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789foo ", flags, Single::NaN(),
+                  &processed, &all_used));
+  CHECK_EQ(10, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567foo ", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(8, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567foo", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(9, processed);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567foo", flags, Single::NaN(), &processed, &all_used));
+  CHECK_EQ(9, processed);
+
+  CHECK_EQ(10.0f, StrToF("012 foo ", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(4, processed);
+
+  CHECK_EQ(0.0f, StrToF("00 foo ", flags, 1.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(123456789.0f,
+           StrToF("0123456789 foo ", flags, Single::NaN(),
+                  &processed, &all_used));
+  CHECK_EQ(11, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("01234567 foo ", flags, Single::NaN(),
+                  &processed, &all_used));
+  CHECK_EQ(9, processed);
+
+  CHECK_EQ(342391.0f,
+           StrToF("+01234567 foo", flags, Single::NaN(),
+                  &processed, &all_used));
+  CHECK_EQ(10, processed);
+
+  CHECK_EQ(-342391.0f,
+           StrToF("-01234567 foo", flags, Single::NaN(),
+                  &processed, &all_used));
+  CHECK_EQ(10, processed);
+}
+
+
+TEST(StringToFloatSpecialValues) {
+  int processed;
+  int flags = StringToDoubleConverter::NO_FLAGS;
+
+  {
+    // Use 1.0 as junk_string_value.
+    StringToDoubleConverter converter(flags, 0.0f, 1.0f, "infinity", "NaN");
+
+    CHECK_EQ(Single::NaN(), converter.StringToDouble("+NaN", 4, &processed));
+    CHECK_EQ(4, processed);
+
+    CHECK_EQ(-Single::Infinity(),
+             converter.StringToDouble("-infinity", 9, &processed));
+    CHECK_EQ(9, processed);
+
+    CHECK_EQ(1.0f, converter.StringToDouble("Infinity", 8, &processed));
+    CHECK_EQ(0, processed);
+
+    CHECK_EQ(1.0f, converter.StringToDouble("++NaN", 5, &processed));
+    CHECK_EQ(0, processed);
+  }
+
+  {
+    // Use 1.0 as junk_string_value.
+    StringToDoubleConverter converter(flags, 0.0f, 1.0f, "+infinity", "1NaN");
+
+    // The '+' is consumed before trying to match the infinity string.
+    CHECK_EQ(1.0f, converter.StringToDouble("+infinity", 9, &processed));
+    CHECK_EQ(0, processed);
+
+    // The match for "1NaN" triggers, and doesn't let the 1234.0 complete.
+    CHECK_EQ(1.0f, converter.StringToDouble("1234.0", 6, &processed));
+    CHECK_EQ(0, processed);
+  }
+}

test/cctest/test-ieee.cc

   CHECK_EQ(4e-324, Double(0.0).NextDouble());
   CHECK_EQ(0.0, Double(-0.0).NextDouble());
   CHECK_EQ(-0.0, Double(-4e-324).NextDouble());
+  CHECK(Double(Double(-0.0).NextDouble()).Sign() > 0);
+  CHECK(Double(Double(-4e-324).NextDouble()).Sign() < 0);
   Double d0(-4e-324);
   Double d1(d0.NextDouble());
   Double d2(d1.NextDouble());
   CHECK_EQ(-0.0, d1.value());
+  CHECK(d1.Sign() < 0);
   CHECK_EQ(0.0, d2.value());
+  CHECK(d2.Sign() > 0);
   CHECK_EQ(4e-324, d2.NextDouble());
   CHECK_EQ(-1.7976931348623157e308, Double(-Double::Infinity()).NextDouble());
   CHECK_EQ(Double::Infinity(),
            Double(UINT64_2PART_C(0x7fefffff, ffffffff)).NextDouble());
 }
+
+
+TEST(PreviousDouble) {
+  CHECK_EQ(0.0, Double(4e-324).PreviousDouble());
+  CHECK_EQ(-0.0, Double(0.0).PreviousDouble());
+  CHECK(Double(Double(0.0).PreviousDouble()).Sign() < 0);
+  CHECK_EQ(-4e-324, Double(-0.0).PreviousDouble());
+  Double d0(4e-324);
+  Double d1(d0.PreviousDouble());
+  Double d2(d1.PreviousDouble());
+  CHECK_EQ(0.0, d1.value());
+  CHECK(d1.Sign() > 0);
+  CHECK_EQ(-0.0, d2.value());
+  CHECK(d2.Sign() < 0);
+  CHECK_EQ(-4e-324, d2.PreviousDouble());
+  CHECK_EQ(1.7976931348623157e308, Double(Double::Infinity()).PreviousDouble());
+  CHECK_EQ(-Double::Infinity(),
+           Double(UINT64_2PART_C(0xffefffff, ffffffff)).PreviousDouble());
+}

test/cctest/test-strtod.cc

 }
 
 
+static float StrtofChar(const char* str, int exponent) {
+  return Strtof(StringToVector(str), exponent);
+}
+
+
 TEST(Strtod) {
   Vector<const char> vector;
 
 }
 
 
+TEST(Strtof) {
+  Vector<const char> vector;
+
+  vector = StringToVector("0");
+  CHECK_EQ(0.0f, Strtof(vector, 1));
+  CHECK_EQ(0.0f, Strtof(vector, 2));
+  CHECK_EQ(0.0f, Strtof(vector, -2));
+  CHECK_EQ(0.0f, Strtof(vector, -999));
+  CHECK_EQ(0.0f, Strtof(vector, +999));
+
+  vector = StringToVector("1");
+  CHECK_EQ(1.0f, Strtof(vector, 0));
+  CHECK_EQ(10.0f, Strtof(vector, 1));
+  CHECK_EQ(100.0f, Strtof(vector, 2));
+  CHECK_EQ(1e20f, Strtof(vector, 20));
+  CHECK_EQ(1e22f, Strtof(vector, 22));
+  CHECK_EQ(1e23f, Strtof(vector, 23));
+  CHECK_EQ(1e35f, Strtof(vector, 35));
+  CHECK_EQ(1e36f, Strtof(vector, 36));
+  CHECK_EQ(1e37f, Strtof(vector, 37));
+  CHECK_EQ(1e-1f, Strtof(vector, -1));
+  CHECK_EQ(1e-2f, Strtof(vector, -2));
+  CHECK_EQ(1e-5f, Strtof(vector, -5));
+  CHECK_EQ(1e-20f, Strtof(vector, -20));
+  CHECK_EQ(1e-22f, Strtof(vector, -22));
+  CHECK_EQ(1e-23f, Strtof(vector, -23));
+  CHECK_EQ(1e-25f, Strtof(vector, -25));
+  CHECK_EQ(1e-39f, Strtof(vector, -39));
+
+  vector = StringToVector("2");
+  CHECK_EQ(2.0f, Strtof(vector, 0));
+  CHECK_EQ(20.0f, Strtof(vector, 1));
+  CHECK_EQ(200.0f, Strtof(vector, 2));
+  CHECK_EQ(2e20f, Strtof(vector, 20));
+  CHECK_EQ(2e22f, Strtof(vector, 22));
+  CHECK_EQ(2e23f, Strtof(vector, 23));
+  CHECK_EQ(2e35f, Strtof(vector, 35));
+  CHECK_EQ(2e36f, Strtof(vector, 36));
+  CHECK_EQ(2e37f, Strtof(vector, 37));
+  CHECK_EQ(2e-1f, Strtof(vector, -1));
+  CHECK_EQ(2e-2f, Strtof(vector, -2));
+  CHECK_EQ(2e-5f, Strtof(vector, -5));
+  CHECK_EQ(2e-20f, Strtof(vector, -20));
+  CHECK_EQ(2e-22f, Strtof(vector, -22));
+  CHECK_EQ(2e-23f, Strtof(vector, -23));
+  CHECK_EQ(2e-25f, Strtof(vector, -25));
+  CHECK_EQ(2e-39f, Strtof(vector, -39));
+
+  vector = StringToVector("9");
+  CHECK_EQ(9.0f, Strtof(vector, 0));
+  CHECK_EQ(90.0f, Strtof(vector, 1));
+  CHECK_EQ(900.0f, Strtof(vector, 2));
+  CHECK_EQ(9e20f, Strtof(vector, 20));
+  CHECK_EQ(9e22f, Strtof(vector, 22));
+  CHECK_EQ(9e23f, Strtof(vector, 23));
+  CHECK_EQ(9e35f, Strtof(vector, 35));
+  CHECK_EQ(9e36f, Strtof(vector, 36));
+  CHECK_EQ(9e37f, Strtof(vector, 37));
+  CHECK_EQ(9e-1f, Strtof(vector, -1));
+  CHECK_EQ(9e-2f, Strtof(vector, -2));
+  CHECK_EQ(9e-5f, Strtof(vector, -5));
+  CHECK_EQ(9e-20f, Strtof(vector, -20));
+  CHECK_EQ(9e-22f, Strtof(vector, -22));
+  CHECK_EQ(9e-23f, Strtof(vector, -23));
+  CHECK_EQ(9e-25f, Strtof(vector, -25));
+  CHECK_EQ(9e-39f, Strtof(vector, -39));
+
+  vector = StringToVector("12345");
+  CHECK_EQ(12345.0f, Strtof(vector, 0));
+  CHECK_EQ(123450.0f, Strtof(vector, 1));
+  CHECK_EQ(1234500.0f, Strtof(vector, 2));
+  CHECK_EQ(12345e20f, Strtof(vector, 20));
+  CHECK_EQ(12345e22f, Strtof(vector, 22));
+  CHECK_EQ(12345e23f, Strtof(vector, 23));
+  CHECK_EQ(12345e30f, Strtof(vector, 30));
+  CHECK_EQ(12345e31f, Strtof(vector, 31));
+  CHECK_EQ(12345e32f, Strtof(vector, 32));
+  CHECK_EQ(12345e-1f, Strtof(vector, -1));
+  CHECK_EQ(12345e-2f, Strtof(vector, -2));
+  CHECK_EQ(12345e-5f, Strtof(vector, -5));
+  CHECK_EQ(12345e-20f, Strtof(vector, -20));
+  CHECK_EQ(12345e-22f, Strtof(vector, -22));
+  CHECK_EQ(12345e-23f, Strtof(vector, -23));
+  CHECK_EQ(12345e-25f, Strtof(vector, -25));
+  CHECK_EQ(12345e-39f, Strtof(vector, -39));
+
+  vector = StringToVector("12345678901234");
+  CHECK_EQ(12345678901234.0f, Strtof(vector, 0));
+  CHECK_EQ(123456789012340.0f, Strtof(vector, 1));
+  CHECK_EQ(1234567890123400.0f, Strtof(vector, 2));
+  CHECK_EQ(12345678901234e20f, Strtof(vector, 20));
+  CHECK_EQ(12345678901234e22f, Strtof(vector, 22));
+  CHECK_EQ(12345678901234e23f, Strtof(vector, 23));
+  CHECK_EQ(12345678901234e-1f, Strtof(vector, -1));
+  CHECK_EQ(12345678901234e-2f, Strtof(vector, -2));
+  CHECK_EQ(12345678901234e-5f, Strtof(vector, -5));
+  CHECK_EQ(12345678901234e-20f, Strtof(vector, -20));
+  CHECK_EQ(12345678901234e-22f, Strtof(vector, -22));
+  CHECK_EQ(12345678901234e-23f, Strtof(vector, -23));
+  CHECK_EQ(12345678901234e-25f, Strtof(vector, -25));
+  CHECK_EQ(12345678901234e-39f, Strtof(vector, -39));
+
+  vector = StringToVector("123456789012345");
+  CHECK_EQ(123456789012345.0f, Strtof(vector, 0));
+  CHECK_EQ(1234567890123450.0f, Strtof(vector, 1));
+  CHECK_EQ(12345678901234500.0f, Strtof(vector, 2));
+  CHECK_EQ(123456789012345e20f, Strtof(vector, 20));
+  CHECK_EQ(123456789012345e22f, Strtof(vector, 22));
+  CHECK_EQ(123456789012345e23f, Strtof(vector, 23));
+  CHECK_EQ(123456789012345e-1f, Strtof(vector, -1));
+  CHECK_EQ(123456789012345e-2f, Strtof(vector, -2));
+  CHECK_EQ(123456789012345e-5f, Strtof(vector, -5));
+  CHECK_EQ(123456789012345e-20f, Strtof(vector, -20));
+  CHECK_EQ(123456789012345e-22f, Strtof(vector, -22));
+  CHECK_EQ(123456789012345e-23f, Strtof(vector, -23));
+  CHECK_EQ(123456789012345e-25f, Strtof(vector, -25));
+  CHECK_EQ(123456789012345e-39f, Strtof(vector, -39));
+
+  CHECK_EQ(0.0f, StrtofChar("0", 12345));
+  CHECK_EQ(0.0f, StrtofChar("", 1324));
+  CHECK_EQ(0.0f, StrtofChar("000000000", 123));
+  CHECK_EQ(0.0f, StrtofChar("2", -324));
+  CHECK_EQ(1e-45f, StrtofChar("1", -45));
+  // It would be more readable to put non-zero literals on the left side (i.e.
+  //   CHECK_EQ(1e-46, StrtofChar("1", -45))), but then Gcc complains that
+  // they are truncated to zero.
+  CHECK_EQ(0.0f, StrtofChar("1", -46));
+  CHECK_EQ(0.0f, StrtofChar("1", -47));
+  CHECK_EQ(1e-45f, StrtofChar("1", -45));
+  CHECK_EQ(1e-45f, StrtofChar("8", -46));
+  CHECK_EQ(0.0f, StrtofChar("200000", -51));
+  CHECK_EQ(100000e-50f, StrtofChar("100000", -50));
+  CHECK_EQ(0.0f, StrtofChar("100000", -51));
+  CHECK_EQ(0.0f, StrtofChar("900000", -52));
+  CHECK_EQ(0.0f, StrtofChar("000000001", -47));
+  CHECK_EQ(0.0f, StrtofChar("000000001", -47));
+  CHECK_EQ(0.0f, StrtofChar("00000000200000", -51));
+  CHECK_EQ(800000e-50f, StrtofChar("000000800000", -50));
+  CHECK_EQ(0.0f, StrtofChar("00000000100000", -51));
+  CHECK_EQ(1e-45f, StrtofChar("00000000900000", -51));
+
+  // It would be more readable to put the literals (and not Double::Infinity())
+  // on the left side (i.e. CHECK_EQ(3e38, StrtofChar("3", 38))), but then Gcc