diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index 30d998fc3c1..d4c2f950e2d 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -191,6 +191,7 @@ namespace llvm { static APFloat getInf(const fltSemantics &Sem, bool Negative = false) { return APFloat(Sem, fcInfinity, Negative); } + /// getNaN - Factory for QNaN values. /// /// \param Negative - True iff the NaN generated should be negative. @@ -201,6 +202,26 @@ namespace llvm { return APFloat(Sem, fcNaN, Negative, type); } + /// getLargest - Returns the largest finite number in the given + /// semantics. + /// + /// \param Negative - True iff the number should be negative + static APFloat getLargest(const fltSemantics &Sem, bool Negative = false); + + /// getSmallest - Returns the smallest (by magnitude) finite number + /// in the given semantics. Might be denormalized, which implies a + /// relative loss of precision. + /// + /// \param Negative - True iff the number should be negative + static APFloat getSmallest(const fltSemantics &Sem, bool Negative = false); + + /// getSmallestNormalized - Returns the smallest (by magnitude) + /// normalized finite number in the given semantics. + /// + /// \param Negative - True iff the number should be negative + static APFloat getSmallestNormalized(const fltSemantics &Sem, + bool Negative = false); + /// Profile - Used to insert APFloat objects, or objects that contain /// APFloat objects, into FoldingSets. void Profile(FoldingSetNodeID& NID) const; @@ -277,6 +298,29 @@ namespace llvm { /* Return an arbitrary integer value usable for hashing. */ uint32_t getHashValue() const; + /// Converts this value into a decimal string. + /// + /// \param FormatPrecision The maximum number of digits of + /// 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. + /// \param FormatMaxPadding The maximum number of zeros to + /// consider inserting before falling back to scientific + /// notation. 0 means to always use scientific notation. + /// + /// Number Precision MaxPadding Result + /// ------ --------- ---------- ------ + /// 1.01E+4 5 2 10100 + /// 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 1 1.01E-2 + void toString(SmallVectorImpl &Str, + unsigned FormatPrecision = 8, + unsigned FormatMaxPadding = 3); + private: /* Trivial queries. */ diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index b9b323c4242..4426a361c06 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -3139,6 +3139,60 @@ APFloat::initFromAPInt(const APInt& api, bool isIEEE) llvm_unreachable(0); } +APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) { + APFloat Val(Sem, fcNormal, Negative); + + // We want (in interchange format): + // sign = {Negative} + // exponent = 1..10 + // significand = 1..1 + + Val.exponent = Sem.maxExponent; // unbiased + + // 1-initialize all bits.... + Val.zeroSignificand(); + integerPart *significand = Val.significandParts(); + unsigned N = partCountForBits(Sem.precision); + for (unsigned i = 0; i != N; ++i) + significand[i] = ~((integerPart) 0); + + // ...and then clear the top bits for internal consistency. + significand[N-1] + &= (((integerPart) 1) << ((Sem.precision % integerPartWidth) - 1)) - 1; + + return Val; +} + +APFloat APFloat::getSmallest(const fltSemantics &Sem, bool Negative) { + APFloat Val(Sem, fcNormal, Negative); + + // We want (in interchange format): + // sign = {Negative} + // exponent = 0..0 + // significand = 0..01 + + Val.exponent = Sem.minExponent; // unbiased + Val.zeroSignificand(); + Val.significandParts()[0] = 1; + return Val; +} + +APFloat APFloat::getSmallestNormalized(const fltSemantics &Sem, bool Negative) { + APFloat Val(Sem, fcNormal, Negative); + + // We want (in interchange format): + // sign = {Negative} + // exponent = 0..0 + // significand = 10..0 + + Val.exponent = Sem.minExponent; + Val.zeroSignificand(); + Val.significandParts()[partCountForBits(Sem.precision)-1] + |= (((integerPart) 1) << ((Sem.precision % integerPartWidth) - 1)); + + return Val; +} + APFloat::APFloat(const APInt& api, bool isIEEE) { initFromAPInt(api, isIEEE); @@ -3155,3 +3209,250 @@ APFloat::APFloat(double d) APInt api = APInt(64, 0); initFromAPInt(api.doubleToBits(d)); } + +namespace { + static void append(SmallVectorImpl &Buffer, + unsigned N, const char *Str) { + unsigned Start = Buffer.size(); + Buffer.set_size(Start + N); + memcpy(&Buffer[Start], Str, N); + } + + template + void append(SmallVectorImpl &Buffer, const char (&Str)[N]) { + append(Buffer, N, Str); + } + + void AdjustToPrecision(SmallVectorImpl &buffer, + int &exp, unsigned FormatPrecision) { + unsigned N = buffer.size(); + if (N <= FormatPrecision) return; + + // The most significant figures are the last ones in the buffer. + unsigned FirstSignificant = N - FormatPrecision; + + // Round. + // FIXME: this probably shouldn't use 'round half up'. + + // Rounding down is just a truncation, except we also want to drop + // trailing zeros from the new result. + if (buffer[FirstSignificant - 1] < '5') { + while (buffer[FirstSignificant] == '0') + FirstSignificant++; + + exp += FirstSignificant; + buffer.erase(&buffer[0], &buffer[FirstSignificant]); + return; + } + + // Rounding up requires a decimal add-with-carry. If we continue + // the carry, the newly-introduced zeros will just be truncated. + for (unsigned I = FirstSignificant; I != N; ++I) { + if (buffer[I] == '9') { + FirstSignificant++; + } else { + buffer[I]++; + break; + } + } + + // If we carried through, we have exactly one digit of precision. + if (FirstSignificant == N) { + exp += FirstSignificant; + buffer.clear(); + buffer.push_back('1'); + return; + } + + exp += FirstSignificant; + buffer.erase(&buffer[0], &buffer[FirstSignificant]); + } +} + +void APFloat::toString(SmallVectorImpl &Str, + unsigned FormatPrecision, + unsigned FormatMaxPadding) { + switch (category) { + case fcInfinity: + if (isNegative()) + return append(Str, "-Inf"); + else + return append(Str, "+Inf"); + + case fcNaN: return append(Str, "NaN"); + + case fcZero: + if (isNegative()) + Str.push_back('-'); + + if (!FormatMaxPadding) + append(Str, "0.0E+0"); + else + Str.push_back('0'); + return; + + case fcNormal: + break; + } + + if (isNegative()) + Str.push_back('-'); + + // Decompose the number into an APInt and an exponent. + int exp = exponent - ((int) semantics->precision - 1); + APInt significand(semantics->precision, + partCountForBits(semantics->precision), + significandParts()); + + // Ignore trailing binary zeros. + int trailingZeros = significand.countTrailingZeros(); + exp += trailingZeros; + significand = significand.lshr(trailingZeros); + + // Change the exponent from 2^e to 10^e. + if (exp == 0) { + // Nothing to do. + } else if (exp > 0) { + // Just shift left. + significand.zext(semantics->precision + exp); + significand <<= exp; + exp = 0; + } else { /* exp < 0 */ + int texp = -exp; + + // We transform this using the identity: + // (N)(2^-e) == (N)(5^e)(10^-e) + // This means we have to multiply N (the significand) by 5^e. + // 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; + + // Multiply significand by 5^e. + // N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8) + significand.zext(precision); + APInt five_to_the_i(precision, 5); + while (true) { + if (texp & 1) significand *= five_to_the_i; + + texp >>= 1; + if (!texp) break; + five_to_the_i *= five_to_the_i; + } + } + + llvm::SmallVector buffer; + + // Fill the buffer. + unsigned precision = significand.getBitWidth(); + APInt ten(precision, 10); + APInt digit(precision, 0); + + bool inTrail = true; + while (significand != 0) { + // digit <- significand % 10 + // significand <- significand / 10 + APInt::udivrem(significand, ten, significand, digit); + + unsigned d = digit.getZExtValue(); + + // Drop trailing zeros. + if (inTrail && !d) exp++; + else { + buffer.push_back((char) ('0' + d)); + inTrail = false; + } + } + + assert(!buffer.empty() && "no characters in buffer!"); + + // Drop down to FormatPrecision. + // TODO: don't do more precise calculations above than are required. + AdjustToPrecision(buffer, exp, FormatPrecision); + + unsigned NDigits = buffer.size(); + + // Check whether we should a non-scientific format. + bool FormatScientific; + if (!FormatMaxPadding) + FormatScientific = true; + else { + unsigned Padding; + if (exp >= 0) { + // 765e3 == 765000 + // ^^^ + Padding = (unsigned) exp; + } else { + unsigned Margin = (unsigned) -exp; + if (Margin < NDigits) { + // 765e-2 == 7.65 + Padding = 0; + } else { + // 765e-5 == 0.00765 + // ^ ^^ + Padding = Margin + 1 - NDigits; + } + } + + FormatScientific = (Padding > FormatMaxPadding || + Padding + NDigits > FormatPrecision); + } + + // Scientific formatting is pretty straightforward. + if (FormatScientific) { + exp += (NDigits - 1); + + Str.push_back(buffer[NDigits-1]); + Str.push_back('.'); + if (NDigits == 1) + Str.push_back('0'); + else + for (unsigned I = 1; I != NDigits; ++I) + Str.push_back(buffer[NDigits-1-I]); + Str.push_back('E'); + + Str.push_back(exp >= 0 ? '+' : '-'); + if (exp < 0) exp = -exp; + SmallVector expbuf; + do { + expbuf.push_back((char) ('0' + (exp % 10))); + exp /= 10; + } while (exp); + for (unsigned I = 0, E = expbuf.size(); I != E; ++I) + Str.push_back(expbuf[E-1-I]); + return; + } + + // Non-scientific, positive exponents. + if (exp >= 0) { + for (unsigned I = 0; I != NDigits; ++I) + Str.push_back(buffer[NDigits-1-I]); + for (unsigned I = 0; I != (unsigned) exp; ++I) + Str.push_back('0'); + return; + } + + // Non-scientific, negative exponents. + + // The number of digits to the left of the decimal point. + int NWholeDigits = exp + (int) NDigits; + + unsigned I = 0; + if (NWholeDigits > 0) { + for (; I != (unsigned) NWholeDigits; ++I) + Str.push_back(buffer[NDigits-I-1]); + Str.push_back('.'); + } else { + unsigned NZeros = 1 + (unsigned) -NWholeDigits; + + Str.push_back('0'); + Str.push_back('.'); + for (unsigned Z = 1; Z != NZeros; ++Z) + Str.push_back('0'); + } + + for (; I != NDigits; ++I) + Str.push_back(buffer[NDigits-I-1]); +} diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index 92f020b382d..d2a977a05cd 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -8,10 +8,12 @@ //===----------------------------------------------------------------------===// #include +#include #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" using namespace llvm; @@ -21,6 +23,13 @@ static double convertToDoubleFromString(const char *Str) { return F.convertToDouble(); } +static std::string convertToString(double d, unsigned Prec, unsigned Pad) { + llvm::SmallVector Buffer; + llvm::APFloat F(d); + F.toString(Buffer, Prec, Pad); + return std::string(Buffer.data(), Buffer.size()); +} + namespace { TEST(APFloatTest, Zero) { @@ -313,6 +322,17 @@ TEST(APFloatTest, fromHexadecimalString) { EXPECT_EQ(2.71828, convertToDoubleFromString("2.71828")); } +TEST(APFloatTest, toString) { + ASSERT_EQ("10", convertToString(10.0, 6, 3)); + ASSERT_EQ("1.0E+1", convertToString(10.0, 6, 0)); + ASSERT_EQ("10100", convertToString(1.01E+4, 5, 2)); + 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("1.01E-2", convertToString(1.01E-2, 5, 1)); +} + #ifdef GTEST_HAS_DEATH_TEST TEST(APFloatTest, SemanticsDeath) { EXPECT_DEATH(APFloat(APFloat::IEEEsingle, 0.0f).convertToDouble(), "Float semantics are not IEEEdouble");