[llvm-dev] Bug or expected behavior of APFloat class?

Dan Liew via llvm-dev llvm-dev at lists.llvm.org
Mon Aug 10 11:05:59 PDT 2015


Hi,

I've been playing around with the APFloat class lately and I came
across behavior I was not expecting based on reading the
implementation comments and I'm wondering if it's a bug or
intentional.

The behavior concerns converting an APFloat to a string and back
again. In the implementation of ``APFloat::toString(...)`` you can
specify ``FormatPrecision`` as 0. The method comments state that this
will use the "natural precision" of the number. In the actual
implementation the comments say that when FormatPrecision is 0 that

```
// We use enough digits so the number can be round-tripped back to an
// APFloat. The formula comes from "How to Print Floating-Point Numbers
// Accurately" by Steele and White.
```

Based on the above comments I expected to be able to convert an
APFloat to a string and back again when ``FormatPrecision`` is set to
zero. However this does not seem to hold. Here's some example code
that demonstrates this.

```
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/APFloat.h"
#include <string>

using namespace llvm;

std::string getString(APFloat f) {
  SmallVector<char,10> strRep;
  // FormatPrecision=0 means that the "natural precision" of the number is used
  f.toString(strRep,/*FormatPrecision=*/0, /*FormatMaxPadding=*/0);
  return std::string(strRep.begin(), strRep.end());
}

uint16_t getBits(APFloat f) {
  APInt bits = f.bitcastToAPInt();
  assert(bits.getActiveBits() <= 16);
  return (uint16_t) (bits.getZExtValue() & 0xffff);
}

int main(int argc, char** argv) {
  APFloat f(APFloat::IEEEhalf);
  APFloat newF(APFloat::IEEEhalf);
  f.convertFromString("0.3", APFloat::rmTowardZero);
  outs() << "f bits: 0x";
  outs().write_hex(getBits(f));
  outs() << "\n";
  assert(getBits(f) == 0x34cc);
  // Check that if we get the string using FormatPrecision=0
  // that this can be used to construct another APFloat of the
  // same value.
  std::string fAsString = getString(f);
  outs() << "f as string: \"" << fAsString << "\"\n";
  newF.convertFromString(fAsString, APFloat::rmTowardZero);
  outs() << "newF as string: \"" << getString(newF) << "\"\n";
  outs() << "newF bits: 0x";
  outs().write_hex(getBits(newF));
  outs() << "\n";
  // BUG?: This assert fails
  assert(getBits(newF) == 0x34cc);
  return 0;
}
```

The output I see is

```
f bits: 0x34cc
f as string: "2.998E-1"
newF as string: "2.9956E-1"
newF bits: 0x34cb
... Assertion `getBits(newF) == 0x34cc' failed.
```

As you can see when we create a new APFloat from the string we get a
slightly smaller number. I have observed that if I use
``APFloat::rmNearestTiesToEven`` when creating ``newF`` that I do get
an APFloat instance which has the same value as the original APFloat.
So I'm wondering if the comment about round tripping APFloats only
holds for certain rounding modes.

Any thoughts on this?

Thanks,
Dan


More information about the llvm-dev mailing list