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

Hal Finkel via llvm-dev llvm-dev at lists.llvm.org
Sat Aug 15 20:19:14 PDT 2015


----- Original Message -----
> From: "Dan Liew via llvm-dev" <llvm-dev at lists.llvm.org>
> To: llvm-dev at lists.llvm.org
> Sent: Monday, August 10, 2015 1:05:59 PM
> Subject: [llvm-dev] Bug or expected behavior of APFloat class?
> 
> 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?

It is certainly possible that APFloat::rmNearestTiesToEven is required for the current code to work (that's the default mode that most of LLVM assumes). That certainly seems like a bug, and I'm not surprised if you find bugs when using other rounding modes.

 -Hal

> 
> Thanks,
> Dan
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org         http://llvm.cs.uiuc.edu
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
> 

-- 
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory


More information about the llvm-dev mailing list