Source

double-conversion / src / bignum-dtoa.cc

The branch 'single' does not exist.
Diff from to

File 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
+  }
 }