diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index 4426a361c06..5f748a2c24c 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -3223,6 +3223,41 @@ namespace { append(Buffer, N, Str); } + /// Removes data from the given significand until it is no more + /// precise than is required for the desired precision. + void AdjustToPrecision(APInt &significand, + int &exp, unsigned FormatPrecision) { + unsigned bits = significand.getActiveBits(); + + // 196/59 is a very slight overestimate of lg_2(10). + unsigned bitsRequired = (FormatPrecision * 196 + 58) / 59; + + if (bits <= bitsRequired) return; + + unsigned tensRemovable = (bits - bitsRequired) * 59 / 196; + if (!tensRemovable) return; + + exp += tensRemovable; + + APInt divisor(significand.getBitWidth(), 1); + APInt powten(significand.getBitWidth(), 10); + while (true) { + if (tensRemovable & 1) + divisor *= powten; + tensRemovable >>= 1; + if (!tensRemovable) break; + powten *= powten; + } + + significand = significand.udiv(divisor); + + // Truncate the significand down to its active bit count, but + // don't try to drop below 32. + unsigned newPrecision = std::min(32U, significand.getActiveBits()); + significand.trunc(newPrecision); + } + + void AdjustToPrecision(SmallVectorImpl &buffer, int &exp, unsigned FormatPrecision) { unsigned N = buffer.size(); @@ -3343,6 +3378,8 @@ void APFloat::toString(SmallVectorImpl &Str, } } + AdjustToPrecision(significand, exp, FormatPrecision); + llvm::SmallVector buffer; // Fill the buffer.