[llvm-commits] [llvm] r92150 - in /llvm/trunk: include/llvm/ADT/APFloat.h lib/Support/APFloat.cpp unittests/ADT/APFloatTest.cpp

John McCall rjmccall at apple.com
Thu Dec 24 15:18:09 PST 2009


Author: rjmccall
Date: Thu Dec 24 17:18:09 2009
New Revision: 92150

URL: http://llvm.org/viewvc/llvm-project?rev=92150&view=rev
Log:
Implement support for converting to string at "natural precision", and fix some
major bugs in long-precision conversion.


Modified:
    llvm/trunk/include/llvm/ADT/APFloat.h
    llvm/trunk/lib/Support/APFloat.cpp
    llvm/trunk/unittests/ADT/APFloatTest.cpp

Modified: llvm/trunk/include/llvm/ADT/APFloat.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/APFloat.h?rev=92150&r1=92149&r2=92150&view=diff

==============================================================================
--- llvm/trunk/include/llvm/ADT/APFloat.h (original)
+++ llvm/trunk/include/llvm/ADT/APFloat.h Thu Dec 24 17:18:09 2009
@@ -304,7 +304,8 @@
     ///   precision to output.  If there are fewer digits available,
     ///   zero padding will not be used unless the value is
     ///   integral and small enough to be expressed in
-    ///   FormatPrecision digits.
+    ///   FormatPrecision digits.  0 means to use the natural
+    ///   precision of the number.
     /// \param FormatMaxPadding The maximum number of zeros to
     ///   consider inserting before falling back to scientific
     ///   notation.  0 means to always use scientific notation.
@@ -315,10 +316,10 @@
     /// 1.01E+4              4             2       1.01E+4
     /// 1.01E+4              5             1       1.01E+4
     /// 1.01E-2              5             2       0.0101
-    /// 1.01E-2              4             2       1.01E-2
+    /// 1.01E-2              4             2       0.0101
     /// 1.01E-2              4             1       1.01E-2
     void toString(SmallVectorImpl<char> &Str,
-                  unsigned FormatPrecision = 8,
+                  unsigned FormatPrecision = 0,
                   unsigned FormatMaxPadding = 3);
 
   private:

Modified: llvm/trunk/lib/Support/APFloat.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/APFloat.cpp?rev=92150&r1=92149&r2=92150&view=diff

==============================================================================
--- llvm/trunk/lib/Support/APFloat.cpp (original)
+++ llvm/trunk/lib/Support/APFloat.cpp Thu Dec 24 17:18:09 2009
@@ -3253,7 +3253,7 @@
 
     // Truncate the significand down to its active bit count, but
     // don't try to drop below 32.
-    unsigned newPrecision = std::min(32U, significand.getActiveBits());
+    unsigned newPrecision = std::max(32U, significand.getActiveBits());
     significand.trunc(newPrecision);
   }
 
@@ -3339,6 +3339,16 @@
                     partCountForBits(semantics->precision),
                     significandParts());
 
+  // Set FormatPrecision if zero.  We want to do this before we
+  // truncate trailing zeros, as those are part of the precision.
+  if (!FormatPrecision) {
+    // It's an interesting question whether to use the nominal
+    // precision or the active precision here for denormals.
+
+    // FormatPrecision = ceil(significandBits / lg_2(10))
+    FormatPrecision = (semantics->precision * 59 + 195) / 196;
+  }
+
   // Ignore trailing binary zeros.
   int trailingZeros = significand.countTrailingZeros();
   exp += trailingZeros;
@@ -3361,9 +3371,10 @@
     // To avoid overflow, we have to operate on numbers large
     // enough to store N * 5^e:
     //   log2(N * 5^e) == log2(N) + e * log2(5)
-    //                 <= semantics->precision + e * 2.5
-    //   (log_2(5) ~ 2.321928)
-    unsigned precision = semantics->precision + 5 * texp / 2;
+    //                 <= semantics->precision + e * 137 / 59
+    //   (log_2(5) ~ 2.321928 < 2.322034 ~ 137/59)
+    
+    unsigned precision = semantics->precision + 137 * texp / 59;
 
     // Multiply significand by 5^e.
     //   N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8)
@@ -3411,30 +3422,29 @@
 
   unsigned NDigits = buffer.size();
 
-  // Check whether we should a non-scientific format.
+  // Check whether we should use scientific notation.
   bool FormatScientific;
   if (!FormatMaxPadding)
     FormatScientific = true;
   else {
-    unsigned Padding;
     if (exp >= 0) {
-      // 765e3 == 765000
-      //             ^^^
-      Padding = (unsigned) exp;
+      // 765e3 --> 765000
+      //              ^^^
+      // But we shouldn't make the number look more precise than it is.
+      FormatScientific = ((unsigned) exp > FormatMaxPadding ||
+                          NDigits + (unsigned) exp > FormatPrecision);
     } else {
-      unsigned Margin = (unsigned) -exp;
-      if (Margin < NDigits) {
+      // Power of the most significant digit.
+      int MSD = exp + (int) (NDigits - 1);
+      if (MSD >= 0) {
         // 765e-2 == 7.65
-        Padding = 0;
+        FormatScientific = false;
       } else {
         // 765e-5 == 0.00765
         //           ^ ^^
-        Padding = Margin + 1 - NDigits;
+        FormatScientific = ((unsigned) -MSD) > FormatMaxPadding;
       }
     }
-
-    FormatScientific = (Padding > FormatMaxPadding ||
-                        Padding + NDigits > FormatPrecision);
   }
 
   // Scientific formatting is pretty straightforward.

Modified: llvm/trunk/unittests/ADT/APFloatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APFloatTest.cpp?rev=92150&r1=92149&r2=92150&view=diff

==============================================================================
--- llvm/trunk/unittests/ADT/APFloatTest.cpp (original)
+++ llvm/trunk/unittests/ADT/APFloatTest.cpp Thu Dec 24 17:18:09 2009
@@ -329,8 +329,10 @@
   ASSERT_EQ("1.01E+4", convertToString(1.01E+4, 4, 2));
   ASSERT_EQ("1.01E+4", convertToString(1.01E+4, 5, 1));
   ASSERT_EQ("0.0101", convertToString(1.01E-2, 5, 2));
-  ASSERT_EQ("1.01E-2", convertToString(1.01E-2, 4, 2));
+  ASSERT_EQ("0.0101", convertToString(1.01E-2, 4, 2));
   ASSERT_EQ("1.01E-2", convertToString(1.01E-2, 5, 1));
+  ASSERT_EQ("0.7853981633974483", convertToString(0.78539816339744830961, 0, 3));
+  ASSERT_EQ("4.940656458412465E-324", convertToString(4.9406564584124654e-324, 0, 3));
 }
 
 #ifdef GTEST_HAS_DEATH_TEST





More information about the llvm-commits mailing list