[llvm] [NFC] [APFloat] Refactor IEEEFloat::toString (PR #97117)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 28 15:04:46 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-support
Author: None (Ariel-Burton)
<details>
<summary>Changes</summary>
This PR lifts the body of IEEEFloat::toString out to a standalone function. We do this to facilitate code sharing with other floating point types, e.g., the forthcoming support for HexFloat.
There is no change in functionality.
---
Full diff: https://github.com/llvm/llvm-project/pull/97117.diff
1 Files Affected:
- (modified) llvm/lib/Support/APFloat.cpp (+195-180)
``````````diff
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 47618bc325951..8b0029583def3 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -4118,6 +4118,199 @@ namespace {
exp += FirstSignificant;
buffer.erase(&buffer[0], &buffer[FirstSignificant]);
}
+
+ void toStringImpl(SmallVectorImpl<char> &Str, const bool isNeg, int exp,
+ APInt significand, unsigned FormatPrecision,
+ unsigned FormatMaxPadding, bool TruncateZero) {
+ const int semanticsPrecision = significand.getBitWidth();
+
+ if (isNeg)
+ Str.push_back('-');
+
+ // Set FormatPrecision if zero. We want to do this before we
+ // truncate trailing zeros, as those are part of the precision.
+ if (!FormatPrecision) {
+ // 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.
+ // FIXME: Using a formula based purely on the precision is conservative;
+ // we can print fewer digits depending on the actual value being printed.
+
+ // FormatPrecision = 2 + floor(significandBits / lg_2(10))
+ FormatPrecision = 2 + semanticsPrecision * 59 / 196;
+ }
+
+ // Ignore trailing binary zeros.
+ int trailingZeros = significand.countr_zero();
+ exp += trailingZeros;
+ significand.lshrInPlace(trailingZeros);
+
+ // Change the exponent from 2^e to 10^e.
+ if (exp == 0) {
+ // Nothing to do.
+ } else if (exp > 0) {
+ // Just shift left.
+ significand = significand.zext(semanticsPrecision + 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 * 137 / 59
+ // (log_2(5) ~ 2.321928 < 2.322034 ~ 137/59)
+
+ unsigned precision = semanticsPrecision + (137 * texp + 136) / 59;
+
+ // Multiply significand by 5^e.
+ // N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8)
+ significand = 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;
+ }
+ }
+
+ AdjustToPrecision(significand, exp, FormatPrecision);
+
+ SmallVector<char, 256> buffer;
+
+ // Fill the buffer.
+ unsigned precision = significand.getBitWidth();
+ if (precision < 4) {
+ // We need enough precision to store the value 10.
+ precision = 4;
+ significand = significand.zext(precision);
+ }
+ 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 use scientific notation.
+ bool FormatScientific;
+ if (!FormatMaxPadding)
+ FormatScientific = true;
+ else {
+ if (exp >= 0) {
+ // 765e3 --> 765000
+ // ^^^
+ // But we shouldn't make the number look more precise than it is.
+ FormatScientific = ((unsigned) exp > FormatMaxPadding ||
+ NDigits + (unsigned) exp > FormatPrecision);
+ } else {
+ // Power of the most significant digit.
+ int MSD = exp + (int) (NDigits - 1);
+ if (MSD >= 0) {
+ // 765e-2 == 7.65
+ FormatScientific = false;
+ } else {
+ // 765e-5 == 0.00765
+ // ^ ^^
+ FormatScientific = ((unsigned) -MSD) > FormatMaxPadding;
+ }
+ }
+ }
+
+ // Scientific formatting is pretty straightforward.
+ if (FormatScientific) {
+ exp += (NDigits - 1);
+
+ Str.push_back(buffer[NDigits-1]);
+ Str.push_back('.');
+ if (NDigits == 1 && TruncateZero)
+ Str.push_back('0');
+ else
+ for (unsigned I = 1; I != NDigits; ++I)
+ Str.push_back(buffer[NDigits-1-I]);
+ // Fill with zeros up to FormatPrecision.
+ if (!TruncateZero && FormatPrecision > NDigits - 1)
+ Str.append(FormatPrecision - NDigits + 1, '0');
+ // For !TruncateZero we use lower 'e'.
+ Str.push_back(TruncateZero ? 'E' : 'e');
+
+ Str.push_back(exp >= 0 ? '+' : '-');
+ if (exp < 0)
+ exp = -exp;
+ SmallVector<char, 6> expbuf;
+ do {
+ expbuf.push_back((char) ('0' + (exp % 10)));
+ exp /= 10;
+ } while (exp);
+ // Exponent always at least two digits if we do not truncate zeros.
+ if (!TruncateZero && expbuf.size() < 2)
+ expbuf.push_back('0');
+ 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]);
+
+ }
} // namespace
void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
@@ -4152,193 +4345,15 @@ void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
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,
ArrayRef(significandParts(), partCountForBits(semantics->precision)));
- // Set FormatPrecision if zero. We want to do this before we
- // truncate trailing zeros, as those are part of the precision.
- if (!FormatPrecision) {
- // 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.
- // FIXME: Using a formula based purely on the precision is conservative;
- // we can print fewer digits depending on the actual value being printed.
-
- // FormatPrecision = 2 + floor(significandBits / lg_2(10))
- FormatPrecision = 2 + semantics->precision * 59 / 196;
- }
-
- // Ignore trailing binary zeros.
- int trailingZeros = significand.countr_zero();
- exp += trailingZeros;
- significand.lshrInPlace(trailingZeros);
-
- // Change the exponent from 2^e to 10^e.
- if (exp == 0) {
- // Nothing to do.
- } else if (exp > 0) {
- // Just shift left.
- significand = 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 * 137 / 59
- // (log_2(5) ~ 2.321928 < 2.322034 ~ 137/59)
-
- unsigned precision = semantics->precision + (137 * texp + 136) / 59;
-
- // Multiply significand by 5^e.
- // N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8)
- significand = 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;
- }
- }
-
- AdjustToPrecision(significand, exp, FormatPrecision);
-
- SmallVector<char, 256> buffer;
-
- // Fill the buffer.
- unsigned precision = significand.getBitWidth();
- if (precision < 4) {
- // We need enough precision to store the value 10.
- precision = 4;
- significand = significand.zext(precision);
- }
- 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 use scientific notation.
- bool FormatScientific;
- if (!FormatMaxPadding)
- FormatScientific = true;
- else {
- if (exp >= 0) {
- // 765e3 --> 765000
- // ^^^
- // But we shouldn't make the number look more precise than it is.
- FormatScientific = ((unsigned) exp > FormatMaxPadding ||
- NDigits + (unsigned) exp > FormatPrecision);
- } else {
- // Power of the most significant digit.
- int MSD = exp + (int) (NDigits - 1);
- if (MSD >= 0) {
- // 765e-2 == 7.65
- FormatScientific = false;
- } else {
- // 765e-5 == 0.00765
- // ^ ^^
- FormatScientific = ((unsigned) -MSD) > FormatMaxPadding;
- }
- }
- }
-
- // Scientific formatting is pretty straightforward.
- if (FormatScientific) {
- exp += (NDigits - 1);
-
- Str.push_back(buffer[NDigits-1]);
- Str.push_back('.');
- if (NDigits == 1 && TruncateZero)
- Str.push_back('0');
- else
- for (unsigned I = 1; I != NDigits; ++I)
- Str.push_back(buffer[NDigits-1-I]);
- // Fill with zeros up to FormatPrecision.
- if (!TruncateZero && FormatPrecision > NDigits - 1)
- Str.append(FormatPrecision - NDigits + 1, '0');
- // For !TruncateZero we use lower 'e'.
- Str.push_back(TruncateZero ? 'E' : 'e');
-
- Str.push_back(exp >= 0 ? '+' : '-');
- if (exp < 0) exp = -exp;
- SmallVector<char, 6> expbuf;
- do {
- expbuf.push_back((char) ('0' + (exp % 10)));
- exp /= 10;
- } while (exp);
- // Exponent always at least two digits if we do not truncate zeros.
- if (!TruncateZero && expbuf.size() < 2)
- expbuf.push_back('0');
- 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');
- }
+ toStringImpl(Str, isNegative(), exp, significand, FormatPrecision,
+ FormatMaxPadding, TruncateZero);
- for (; I != NDigits; ++I)
- Str.push_back(buffer[NDigits-I-1]);
}
bool IEEEFloat::getExactInverse(APFloat *inv) const {
``````````
</details>
https://github.com/llvm/llvm-project/pull/97117
More information about the llvm-commits
mailing list