[LLVMdev] APFloat storage complications

Neil Booth neil at daikokuya.co.uk
Fri Sep 21 19:39:55 PDT 2007


APFloat is derived from C code using fixed width storage for
the matntissa.  When converting to C++ I changed it to variable-
width storage for space efficiency and generality reasons.

Unfortunately this leads to a complication during float->float
conversions that I missed that isn't present when using fixed
width storage.

Dale - I think this solves the issue correctly whilst preserving
correct rounding.  Does it fix the problem case you had?

Neil.
-------------- next part --------------
Index: lib/Support/APFloat.cpp
===================================================================
--- lib/Support/APFloat.cpp	(revision 42219)
+++ lib/Support/APFloat.cpp	(working copy)
@@ -1318,39 +1318,44 @@
 APFloat::convert(const fltSemantics &toSemantics,
 		 roundingMode rounding_mode)
 {
-  unsigned int newPartCount;
+  lostFraction lostFraction;
+  unsigned int newPartCount, oldPartCount;
   opStatus fs;
-
+  
+  lostFraction = lfExactlyZero;
   newPartCount = partCountForBits(toSemantics.precision + 1);
+  oldPartCount = partCount();
 
-  /* If our new form is wider, re-allocate our bit pattern into wider
-     storage.
-     If we're narrowing from multiple words to 1 words, copy to the single
-     word.  If we are losing information by doing this, we would have to
-     worry about rounding; right now the only case is f80 -> shorter
-     conversion, and we are keeping all 64 significant bits, so it's OK. */
-  if(newPartCount > partCount()) {
+  /* Handle storage complications.  If our new form is wider,
+     re-allocate our bit pattern into wider storage.  If it is
+     narrower, we ignore the excess parts, but if narrowing to a
+     single part we need to free the old storage.  */
+  if (newPartCount > oldPartCount) {
     integerPart *newParts;
 
     newParts = new integerPart[newPartCount];
     APInt::tcSet(newParts, 0, newPartCount);
-    APInt::tcAssign(newParts, significandParts(), partCount());
+    APInt::tcAssign(newParts, significandParts(), oldPartCount);
     freeSignificand();
     significand.parts = newParts;
-  } else if (newPartCount==1 && newPartCount < partCount()) {
-    integerPart newPart;
-
-    APInt::tcSet(&newPart, 0, newPartCount);
-    APInt::tcAssign(&newPart, significandParts(), partCount());
-    freeSignificand();
-    significand.part = newPart;
+  } else if (newPartCount < oldPartCount) {
+    /* Capture any lost fraction through truncation of parts so we get
+       correct rounding whilst normalizing.  */
+    lostFraction = lostFractionThroughTruncation
+      (significandParts(), oldPartCount, newPartCount * integerPartWidth);
+    if (newPartCount == 1)
+      {
+	integerPart newPart = significandParts()[0];
+	freeSignificand();
+	significand.part = newPart;
+      }
   }
 
   if(category == fcNormal) {
     /* Re-interpret our bit-pattern.  */
     exponent += toSemantics.precision - semantics->precision;
     semantics = &toSemantics;
-    fs = normalize(rounding_mode, lfExactlyZero);
+    fs = normalize(rounding_mode, lostFraction);
   } else {
     semantics = &toSemantics;
     fs = opOK;


More information about the llvm-dev mailing list