Commits

Anonymous committed 20f2487

Single-precision printing support.

  • Participants
  • Parent commits 2d2b299
  • Branches single

Comments (0)

Files changed (22)

 print(test)
 env = Environment(CPPPATH='#/src')
 debug = ARGUMENTS.get('debug', 0)
+optimize = ARGUMENTS.get('optimize', 0)
 if int(debug):
   env.Append(CCFLAGS = '-g')
+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)

src/bignum-dtoa.cc

 #include "bignum-dtoa.h"
 
 #include "bignum.h"
-#include "double.h"
+#include "ieee.h"
 
 namespace double_conversion {
 
 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,
                 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);
   // 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.
   //  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);
   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);
 }
 
 // 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.
   // 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);
 
     // 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 is 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).
     // 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 is 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.
 
     // 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) is done later.
   }
 }
 
 //
 // 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
+  }
 }
 
 

src/bignum-dtoa.h

   // 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.

src/double-conversion.cc

 #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"
 
 }
 
 
-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);
   }
   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;
     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:
                                             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;
     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;

src/double-conversion.h

   // 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 {
+    ToShortestIeeeNumber(value, result_builder, SHORTEST);
+  }
+
+  // Same as ToShortest, but for single-precision floats.
+  bool ToShortestSingle(float value, StringBuilder* result_builder) const {
+    ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE);
+  }
 
 
   // Computes a decimal representation with a fixed number of digits after the
     // 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.
                             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

src/double.h

-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_DOUBLE_H_
-#define DOUBLE_CONVERSION_DOUBLE_H_
-
-#include "diy-fp.h"
-
-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); }
-
-// Helper functions for doubles.
-class Double {
- public:
-  static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000);
-  static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000);
-  static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);
-  static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000);
-  static const int kPhysicalSignificandSize = 52;  // Excludes the hidden bit.
-  static const int kSignificandSize = 53;
-
-  Double() : d64_(0) {}
-  explicit Double(double d) : d64_(double_to_uint64(d)) {}
-  explicit Double(uint64_t d64) : d64_(d64) {}
-  explicit Double(DiyFp diy_fp)
-    : d64_(DiyFpToUint64(diy_fp)) {}
-
-  // The value encoded by this Double 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());
-  }
-
-  // The value encoded by this Double must be strictly greater than 0.
-  DiyFp AsNormalizedDiyFp() const {
-    ASSERT(value() > 0.0);
-    uint64_t f = Significand();
-    int e = Exponent();
-
-    // The current double could be a denormal.
-    while ((f & kHiddenBit) == 0) {
-      f <<= 1;
-      e--;
-    }
-    // Do the final shifts in one go.
-    f <<= DiyFp::kSignificandSize - kSignificandSize;
-    e -= DiyFp::kSignificandSize - kSignificandSize;
-    return DiyFp(f, e);
-  }
-
-  // Returns the double's bit as uint64.
-  uint64_t AsUint64() const {
-    return d64_;
-  }
-
-  // Returns the next greater double. Returns +infinity on input +infinity.
-  double NextDouble() const {
-    if (d64_ == kInfinity) return Double(kInfinity).value();
-    if (Sign() < 0 && Significand() == 0) {
-      // -0.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;
-
-    uint64_t d64 = AsUint64();
-    int biased_e =
-        static_cast<int>((d64 & kExponentMask) >> kPhysicalSignificandSize);
-    return biased_e - kExponentBias;
-  }
-
-  uint64_t Significand() const {
-    uint64_t d64 = AsUint64();
-    uint64_t significand = d64 & kSignificandMask;
-    if (!IsDenormal()) {
-      return significand + kHiddenBit;
-    } else {
-      return significand;
-    }
-  }
-
-  // Returns true if the double is a denormal.
-  bool IsDenormal() const {
-    uint64_t d64 = AsUint64();
-    return (d64 & kExponentMask) == 0;
-  }
-
-  // We consider denormals not to be special.
-  // Hence only Infinity and NaN are special.
-  bool IsSpecial() const {
-    uint64_t d64 = AsUint64();
-    return (d64 & kExponentMask) == kExponentMask;
-  }
-
-  bool IsNan() const {
-    uint64_t d64 = AsUint64();
-    return ((d64 & kExponentMask) == kExponentMask) &&
-        ((d64 & kSignificandMask) != 0);
-  }
-
-  bool IsInfinite() const {
-    uint64_t d64 = AsUint64();
-    return ((d64 & kExponentMask) == kExponentMask) &&
-        ((d64 & kSignificandMask) == 0);
-  }
-
-  int Sign() const {
-    uint64_t d64 = AsUint64();
-    return (d64 & kSignMask) == 0? 1: -1;
-  }
-
-  // Precondition: the value encoded by this Double must be greater or equal
-  // than +0.0.
-  DiyFp UpperBoundary() const {
-    ASSERT(Sign() > 0);
-    return DiyFp(Significand() * 2 + 1, Exponent() - 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 Double must be greater than 0.
-  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.
-      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;
-  }
-
-  double value() const { return uint64_to_double(d64_); }
-
-  // Returns the significand size for a given order of magnitude.
-  // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
-  // This function returns the number of significant binary digits v will have
-  // once it's encoded into a double. In almost all cases this is equal to
-  // kSignificandSize. The only exceptions are denormals. They start with
-  // leading zeroes and their effective significand-size is hence smaller.
-  static int SignificandSizeForOrderOfMagnitude(int order) {
-    if (order >= (kDenormalExponent + kSignificandSize)) {
-      return kSignificandSize;
-    }
-    if (order <= kDenormalExponent) return 0;
-    return order - kDenormalExponent;
-  }
-
-  static double Infinity() {
-    return Double(kInfinity).value();
-  }
-
-  static double NaN() {
-    return Double(kNaN).value();
-  }
-
- private:
-  static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
-  static const int kDenormalExponent = -kExponentBias + 1;
-  static const int kMaxExponent = 0x7FF - kExponentBias;
-  static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000);
-  static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000);
-
-  const uint64_t d64_;
-
-  static uint64_t DiyFpToUint64(DiyFp diy_fp) {
-    uint64_t significand = diy_fp.f();
-    int exponent = diy_fp.e();
-    while (significand > kHiddenBit + kSignificandMask) {
-      significand >>= 1;
-      exponent++;
-    }
-    if (exponent >= kMaxExponent) {
-      return kInfinity;
-    }
-    if (exponent < kDenormalExponent) {
-      return 0;
-    }
-    while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) {
-      significand <<= 1;
-      exponent--;
-    }
-    uint64_t biased_exponent;
-    if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) {
-      biased_exponent = 0;
-    } else {
-      biased_exponent = static_cast<uint64_t>(exponent + kExponentBias);
-    }
-    return (significand & kSignificandMask) |
-        (biased_exponent << kPhysicalSignificandSize);
-  }
-};
-
-}  // namespace double_conversion
-
-#endif  // DOUBLE_CONVERSION_DOUBLE_H_
 
 #include "cached-powers.h"
 #include "diy-fp.h"
-#include "double.h"
+#include "ieee.h"
 
 #include <stdio.h>
 
 // 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) {
   // 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
   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,
   // 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
 // 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).

src/fixed-dtoa.cc

 #include <math.h>
 
 #include "fixed-dtoa.h"
-#include "double.h"
+#include "ieee.h"
 
 namespace double_conversion {
 
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef DOUBLE_CONVERSION_DOUBLE_H_
+#define DOUBLE_CONVERSION_DOUBLE_H_
+
+#include "diy-fp.h"
+
+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 {
+ public:
+  static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000);
+  static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000);
+  static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);
+  static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000);
+  static const int kPhysicalSignificandSize = 52;  // Excludes the hidden bit.
+  static const int kSignificandSize = 53;
+
+  Double() : d64_(0) {}
+  explicit Double(double d) : d64_(double_to_uint64(d)) {}
+  explicit Double(uint64_t d64) : d64_(d64) {}
+  explicit Double(DiyFp diy_fp)
+    : d64_(DiyFpToUint64(diy_fp)) {}
+
+  // The value encoded by this Double 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());
+  }
+
+  // The value encoded by this Double must be strictly greater than 0.
+  DiyFp AsNormalizedDiyFp() const {
+    ASSERT(value() > 0.0);
+    uint64_t f = Significand();
+    int e = Exponent();
+
+    // The current double could be a denormal.
+    while ((f & kHiddenBit) == 0) {
+      f <<= 1;
+      e--;
+    }
+    // Do the final shifts in one go.
+    f <<= DiyFp::kSignificandSize - kSignificandSize;
+    e -= DiyFp::kSignificandSize - kSignificandSize;
+    return DiyFp(f, e);
+  }
+
+  // Returns the double's bit as uint64.
+  uint64_t AsUint64() const {
+    return d64_;
+  }
+
+  // Returns the next greater double. Returns +infinity on input +infinity.
+  double NextDouble() const {
+    if (d64_ == kInfinity) return Double(kInfinity).value();
+    if (Sign() < 0 && Significand() == 0) {
+      // -0.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;
+
+    uint64_t d64 = AsUint64();
+    int biased_e =
+        static_cast<int>((d64 & kExponentMask) >> kPhysicalSignificandSize);
+    return biased_e - kExponentBias;
+  }
+
+  uint64_t Significand() const {
+    uint64_t d64 = AsUint64();
+    uint64_t significand = d64 & kSignificandMask;
+    if (!IsDenormal()) {
+      return significand + kHiddenBit;
+    } else {
+      return significand;
+    }
+  }
+
+  // Returns true if the double is a denormal.
+  bool IsDenormal() const {
+    uint64_t d64 = AsUint64();
+    return (d64 & kExponentMask) == 0;
+  }
+
+  // We consider denormals not to be special.
+  // Hence only Infinity and NaN are special.
+  bool IsSpecial() const {
+    uint64_t d64 = AsUint64();
+    return (d64 & kExponentMask) == kExponentMask;
+  }
+
+  bool IsNan() const {
+    uint64_t d64 = AsUint64();
+    return ((d64 & kExponentMask) == kExponentMask) &&
+        ((d64 & kSignificandMask) != 0);
+  }
+
+  bool IsInfinite() const {
+    uint64_t d64 = AsUint64();
+    return ((d64 & kExponentMask) == kExponentMask) &&
+        ((d64 & kSignificandMask) == 0);
+  }
+
+  int Sign() const {
+    uint64_t d64 = AsUint64();
+    return (d64 & kSignMask) == 0? 1: -1;
+  }
+
+  // Precondition: the value encoded by this Double must be greater or equal
+  // than +0.0.
+  DiyFp UpperBoundary() const {
+    ASSERT(Sign() > 0);
+    return DiyFp(Significand() * 2 + 1, Exponent() - 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 Double must be greater than 0.
+  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 (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;
+  }
+
+  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.
+  // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
+  // This function returns the number of significant binary digits v will have
+  // once it's encoded into a double. In almost all cases this is equal to
+  // kSignificandSize. The only exceptions are denormals. They start with
+  // leading zeroes and their effective significand-size is hence smaller.
+  static int SignificandSizeForOrderOfMagnitude(int order) {
+    if (order >= (kDenormalExponent + kSignificandSize)) {
+      return kSignificandSize;
+    }
+    if (order <= kDenormalExponent) return 0;
+    return order - kDenormalExponent;
+  }
+
+  static double Infinity() {
+    return Double(kInfinity).value();
+  }
+
+  static double NaN() {
+    return Double(kNaN).value();
+  }
+
+ private:
+  static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
+  static const int kDenormalExponent = -kExponentBias + 1;
+  static const int kMaxExponent = 0x7FF - kExponentBias;
+  static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000);
+  static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000);
+
+  const uint64_t d64_;
+
+  static uint64_t DiyFpToUint64(DiyFp diy_fp) {
+    uint64_t significand = diy_fp.f();
+    int exponent = diy_fp.e();
+    while (significand > kHiddenBit + kSignificandMask) {
+      significand >>= 1;
+      exponent++;
+    }
+    if (exponent >= kMaxExponent) {
+      return kInfinity;
+    }
+    if (exponent < kDenormalExponent) {
+      return 0;
+    }
+    while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) {
+      significand <<= 1;
+      exponent--;
+    }
+    uint64_t biased_exponent;
+    if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) {
+      biased_exponent = 0;
+    } else {
+      biased_exponent = static_cast<uint64_t>(exponent + kExponentBias);
+    }
+    return (significand & kSignificandMask) |
+        (biased_exponent << kPhysicalSignificandSize);
+  }
+};
+
+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();
+    bool significand_is_zero = (v.f() == kHiddenBit);
+    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;
+  }
+
+  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_
 #include "strtod.h"
 #include "bignum.h"
 #include "cached-powers.h"
-#include "double.h"
+#include "ieee.h"
 
 namespace double_conversion {
 

test/cctest/SConscript

     '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')