[llvm] [APFloat] Add APFloat::format (PR #99088)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 8 00:28:54 PDT 2024
================
@@ -5323,6 +5399,291 @@ APFloat APFloat::getAllOnesValue(const fltSemantics &Semantics) {
return APFloat(Semantics, APInt::getAllOnes(Semantics.sizeInBits));
}
+SmallVectorImpl<char> &APFloat::format(SmallVectorImpl<char> &strout,
+ llvm::FloatStyle style,
+ std::optional<size_t> precision_in) {
+ size_t precision = precision_in.value_or(getDefaultPrecision(style));
+
+ // everything that follows assumes that precision >= 0
+ assert(precision >= 0);
+
+ // deal with the special cases
+ if (isNaN()) {
+ detail::append(strout, "nan");
+ return strout;
+ } else if (isInfinity()) {
+ if (isNegative())
+ detail::append(strout, "-INF");
+ else
+ detail::append(strout, "INF");
+ return strout;
+ } else if (isZero()) {
+ if (isNegative())
+ strout.push_back('-');
+ strout.push_back('0');
+ if (precision > 0) {
+ strout.push_back('.');
+ for (size_t i = 0; i < precision; ++i)
+ strout.push_back('0');
+ }
+ if (style == FloatStyle::Exponent)
+ detail::append(strout, "e+00");
+ else if (style == FloatStyle::ExponentUpper)
+ detail::append(strout, "E+00");
+ else if (style == FloatStyle::Percent)
+ strout.push_back('%');
+ return strout;
+ }
+
+ // check we've dealt with all the special cases
+ assert(!isNaN() && !isInfinity() && !isZero());
+
+ // get as an integer and radix 2 exponent
+ APInt I;
+ int E;
+ decomposeToIntegerAndPowerOf2(I, E);
+
+ // convert from base 2 to base 10
+ if (0 == E) {
+ // then nothing to do --- s is an integer
+ } else if (E > 0) {
+ // shift left and reduce e to 0
+ int numLeadingZeros = I.countl_zero();
+ if (E > numLeadingZeros)
+ I = I.zext(I.getBitWidth() + E - numLeadingZeros);
+ I <<= E;
+ E = 0;
+ } else {
+ // we want to convert a negative base 2 exponent
+ // to a negative base 10 exponent:
+ // I * 2^-E = I * 2^-E * 5^E * 5^-E
+ // = I * 5^E * 2^-E * 5^-E
+ // = (I * 5^E) * (2*5)^-E
+ // = (I * 5^E) * 10^-E
+ // that is, we need to multiply I by 5^-exp and treat
+ // the exponent as being base 10
+
+ // 5^13 = 5^(8+4+1)
+ //
+ // Now work our how many bits we need for the product I * 5^E
+ // We need log2(I * 5^E) = log2(s) + log2(5^E)
+ // = log2(s) + e * log2(5)
+ // log2(5) ~ 2.321928096 < 2.322033898 ~ 137/59
+ // log2(I) <= I.getBitWidth()
+
+ I = I.zext(I.getBitWidth() + (137 * -E + 136) / 59);
+ APInt power5(I.getBitWidth(), 5);
+ int exp = -E;
+ assert(exp > 0);
+ for (;;) {
+ if (exp & 1)
+ I *= power5;
+ exp >>= 1;
+ if (0 == exp)
+ break;
+ power5 *= power5;
+ }
+ }
+
+ // at this point s is an intger, and exp is either 0, or is negative
+ assert(E <= 0);
+
+ // convert s to a string
+ SmallVector<char> s;
+ I.toString(s, 10, false);
+
+ // The decimal point is at position -E (recall E is <= 0)
+ // relative to the END of the string. If E == 0, the decimal
+ // point is to the right of the last position.
+ // Thus, if decimalPoint == s.size() + E, the decimal point is
+ // immediately to the left of s[decimalPoint].
+ // If decimalPoint is 0, the decimal point is immediately
+ // before the start of s. If it is negative, then there are
+ // implicit zeros to the left of s.
+ int decimalPoint = s.size() + E;
+ E = 0;
+
+ if (style == FloatStyle::Exponent || style == FloatStyle::ExponentUpper) {
+ // this corresponds to printf("%e"), or [-]d[.dd..dd]e(+|-)dd
+ // We need one digit to the left of the decimal point.
+ // In other words, we need to make decimalPoint 1,
+ // and adjust E.
+ E = decimalPoint - 1;
+ decimalPoint = 1;
+
+ // now need to deal with the precision.
+ if (precision < (s.size() - 1) && (s[precision + 1] >= '5')) {
+ // then need to round. What we do is extract the
----------------
arsenm wrote:
```suggestion
// Then need to round. What we do is extract the
```
Capitalize comments
https://github.com/llvm/llvm-project/pull/99088
More information about the llvm-commits
mailing list