Skip to content

Commit bbc6504

Browse files
authored
[NFC] [APFloat] Refactor IEEEFloat::toString (#97117)
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.
1 parent f58930f commit bbc6504

File tree

1 file changed

+195
-180
lines changed

1 file changed

+195
-180
lines changed

llvm/lib/Support/APFloat.cpp

Lines changed: 195 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -4118,6 +4118,199 @@ namespace {
41184118
exp += FirstSignificant;
41194119
buffer.erase(&buffer[0], &buffer[FirstSignificant]);
41204120
}
4121+
4122+
void toStringImpl(SmallVectorImpl<char> &Str, const bool isNeg, int exp,
4123+
APInt significand, unsigned FormatPrecision,
4124+
unsigned FormatMaxPadding, bool TruncateZero) {
4125+
const int semanticsPrecision = significand.getBitWidth();
4126+
4127+
if (isNeg)
4128+
Str.push_back('-');
4129+
4130+
// Set FormatPrecision if zero. We want to do this before we
4131+
// truncate trailing zeros, as those are part of the precision.
4132+
if (!FormatPrecision) {
4133+
// We use enough digits so the number can be round-tripped back to an
4134+
// APFloat. The formula comes from "How to Print Floating-Point Numbers
4135+
// Accurately" by Steele and White.
4136+
// FIXME: Using a formula based purely on the precision is conservative;
4137+
// we can print fewer digits depending on the actual value being printed.
4138+
4139+
// FormatPrecision = 2 + floor(significandBits / lg_2(10))
4140+
FormatPrecision = 2 + semanticsPrecision * 59 / 196;
4141+
}
4142+
4143+
// Ignore trailing binary zeros.
4144+
int trailingZeros = significand.countr_zero();
4145+
exp += trailingZeros;
4146+
significand.lshrInPlace(trailingZeros);
4147+
4148+
// Change the exponent from 2^e to 10^e.
4149+
if (exp == 0) {
4150+
// Nothing to do.
4151+
} else if (exp > 0) {
4152+
// Just shift left.
4153+
significand = significand.zext(semanticsPrecision + exp);
4154+
significand <<= exp;
4155+
exp = 0;
4156+
} else { /* exp < 0 */
4157+
int texp = -exp;
4158+
4159+
// We transform this using the identity:
4160+
// (N)(2^-e) == (N)(5^e)(10^-e)
4161+
// This means we have to multiply N (the significand) by 5^e.
4162+
// To avoid overflow, we have to operate on numbers large
4163+
// enough to store N * 5^e:
4164+
// log2(N * 5^e) == log2(N) + e * log2(5)
4165+
// <= semantics->precision + e * 137 / 59
4166+
// (log_2(5) ~ 2.321928 < 2.322034 ~ 137/59)
4167+
4168+
unsigned precision = semanticsPrecision + (137 * texp + 136) / 59;
4169+
4170+
// Multiply significand by 5^e.
4171+
// N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8)
4172+
significand = significand.zext(precision);
4173+
APInt five_to_the_i(precision, 5);
4174+
while (true) {
4175+
if (texp & 1)
4176+
significand *= five_to_the_i;
4177+
4178+
texp >>= 1;
4179+
if (!texp)
4180+
break;
4181+
five_to_the_i *= five_to_the_i;
4182+
}
4183+
}
4184+
4185+
AdjustToPrecision(significand, exp, FormatPrecision);
4186+
4187+
SmallVector<char, 256> buffer;
4188+
4189+
// Fill the buffer.
4190+
unsigned precision = significand.getBitWidth();
4191+
if (precision < 4) {
4192+
// We need enough precision to store the value 10.
4193+
precision = 4;
4194+
significand = significand.zext(precision);
4195+
}
4196+
APInt ten(precision, 10);
4197+
APInt digit(precision, 0);
4198+
4199+
bool inTrail = true;
4200+
while (significand != 0) {
4201+
// digit <- significand % 10
4202+
// significand <- significand / 10
4203+
APInt::udivrem(significand, ten, significand, digit);
4204+
4205+
unsigned d = digit.getZExtValue();
4206+
4207+
// Drop trailing zeros.
4208+
if (inTrail && !d)
4209+
exp++;
4210+
else {
4211+
buffer.push_back((char) ('0' + d));
4212+
inTrail = false;
4213+
}
4214+
}
4215+
4216+
assert(!buffer.empty() && "no characters in buffer!");
4217+
4218+
// Drop down to FormatPrecision.
4219+
// TODO: don't do more precise calculations above than are required.
4220+
AdjustToPrecision(buffer, exp, FormatPrecision);
4221+
4222+
unsigned NDigits = buffer.size();
4223+
4224+
// Check whether we should use scientific notation.
4225+
bool FormatScientific;
4226+
if (!FormatMaxPadding)
4227+
FormatScientific = true;
4228+
else {
4229+
if (exp >= 0) {
4230+
// 765e3 --> 765000
4231+
// ^^^
4232+
// But we shouldn't make the number look more precise than it is.
4233+
FormatScientific = ((unsigned) exp > FormatMaxPadding ||
4234+
NDigits + (unsigned) exp > FormatPrecision);
4235+
} else {
4236+
// Power of the most significant digit.
4237+
int MSD = exp + (int) (NDigits - 1);
4238+
if (MSD >= 0) {
4239+
// 765e-2 == 7.65
4240+
FormatScientific = false;
4241+
} else {
4242+
// 765e-5 == 0.00765
4243+
// ^ ^^
4244+
FormatScientific = ((unsigned) -MSD) > FormatMaxPadding;
4245+
}
4246+
}
4247+
}
4248+
4249+
// Scientific formatting is pretty straightforward.
4250+
if (FormatScientific) {
4251+
exp += (NDigits - 1);
4252+
4253+
Str.push_back(buffer[NDigits-1]);
4254+
Str.push_back('.');
4255+
if (NDigits == 1 && TruncateZero)
4256+
Str.push_back('0');
4257+
else
4258+
for (unsigned I = 1; I != NDigits; ++I)
4259+
Str.push_back(buffer[NDigits-1-I]);
4260+
// Fill with zeros up to FormatPrecision.
4261+
if (!TruncateZero && FormatPrecision > NDigits - 1)
4262+
Str.append(FormatPrecision - NDigits + 1, '0');
4263+
// For !TruncateZero we use lower 'e'.
4264+
Str.push_back(TruncateZero ? 'E' : 'e');
4265+
4266+
Str.push_back(exp >= 0 ? '+' : '-');
4267+
if (exp < 0)
4268+
exp = -exp;
4269+
SmallVector<char, 6> expbuf;
4270+
do {
4271+
expbuf.push_back((char) ('0' + (exp % 10)));
4272+
exp /= 10;
4273+
} while (exp);
4274+
// Exponent always at least two digits if we do not truncate zeros.
4275+
if (!TruncateZero && expbuf.size() < 2)
4276+
expbuf.push_back('0');
4277+
for (unsigned I = 0, E = expbuf.size(); I != E; ++I)
4278+
Str.push_back(expbuf[E-1-I]);
4279+
return;
4280+
}
4281+
4282+
// Non-scientific, positive exponents.
4283+
if (exp >= 0) {
4284+
for (unsigned I = 0; I != NDigits; ++I)
4285+
Str.push_back(buffer[NDigits-1-I]);
4286+
for (unsigned I = 0; I != (unsigned) exp; ++I)
4287+
Str.push_back('0');
4288+
return;
4289+
}
4290+
4291+
// Non-scientific, negative exponents.
4292+
4293+
// The number of digits to the left of the decimal point.
4294+
int NWholeDigits = exp + (int) NDigits;
4295+
4296+
unsigned I = 0;
4297+
if (NWholeDigits > 0) {
4298+
for (; I != (unsigned) NWholeDigits; ++I)
4299+
Str.push_back(buffer[NDigits-I-1]);
4300+
Str.push_back('.');
4301+
} else {
4302+
unsigned NZeros = 1 + (unsigned) -NWholeDigits;
4303+
4304+
Str.push_back('0');
4305+
Str.push_back('.');
4306+
for (unsigned Z = 1; Z != NZeros; ++Z)
4307+
Str.push_back('0');
4308+
}
4309+
4310+
for (; I != NDigits; ++I)
4311+
Str.push_back(buffer[NDigits-I-1]);
4312+
4313+
}
41214314
} // namespace
41224315

41234316
void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
@@ -4152,193 +4345,15 @@ void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
41524345
break;
41534346
}
41544347

4155-
if (isNegative())
4156-
Str.push_back('-');
4157-
41584348
// Decompose the number into an APInt and an exponent.
41594349
int exp = exponent - ((int) semantics->precision - 1);
41604350
APInt significand(
41614351
semantics->precision,
41624352
ArrayRef(significandParts(), partCountForBits(semantics->precision)));
41634353

4164-
// Set FormatPrecision if zero. We want to do this before we
4165-
// truncate trailing zeros, as those are part of the precision.
4166-
if (!FormatPrecision) {
4167-
// We use enough digits so the number can be round-tripped back to an
4168-
// APFloat. The formula comes from "How to Print Floating-Point Numbers
4169-
// Accurately" by Steele and White.
4170-
// FIXME: Using a formula based purely on the precision is conservative;
4171-
// we can print fewer digits depending on the actual value being printed.
4172-
4173-
// FormatPrecision = 2 + floor(significandBits / lg_2(10))
4174-
FormatPrecision = 2 + semantics->precision * 59 / 196;
4175-
}
4176-
4177-
// Ignore trailing binary zeros.
4178-
int trailingZeros = significand.countr_zero();
4179-
exp += trailingZeros;
4180-
significand.lshrInPlace(trailingZeros);
4181-
4182-
// Change the exponent from 2^e to 10^e.
4183-
if (exp == 0) {
4184-
// Nothing to do.
4185-
} else if (exp > 0) {
4186-
// Just shift left.
4187-
significand = significand.zext(semantics->precision + exp);
4188-
significand <<= exp;
4189-
exp = 0;
4190-
} else { /* exp < 0 */
4191-
int texp = -exp;
4192-
4193-
// We transform this using the identity:
4194-
// (N)(2^-e) == (N)(5^e)(10^-e)
4195-
// This means we have to multiply N (the significand) by 5^e.
4196-
// To avoid overflow, we have to operate on numbers large
4197-
// enough to store N * 5^e:
4198-
// log2(N * 5^e) == log2(N) + e * log2(5)
4199-
// <= semantics->precision + e * 137 / 59
4200-
// (log_2(5) ~ 2.321928 < 2.322034 ~ 137/59)
4201-
4202-
unsigned precision = semantics->precision + (137 * texp + 136) / 59;
4203-
4204-
// Multiply significand by 5^e.
4205-
// N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8)
4206-
significand = significand.zext(precision);
4207-
APInt five_to_the_i(precision, 5);
4208-
while (true) {
4209-
if (texp & 1) significand *= five_to_the_i;
4210-
4211-
texp >>= 1;
4212-
if (!texp) break;
4213-
five_to_the_i *= five_to_the_i;
4214-
}
4215-
}
4216-
4217-
AdjustToPrecision(significand, exp, FormatPrecision);
4218-
4219-
SmallVector<char, 256> buffer;
4220-
4221-
// Fill the buffer.
4222-
unsigned precision = significand.getBitWidth();
4223-
if (precision < 4) {
4224-
// We need enough precision to store the value 10.
4225-
precision = 4;
4226-
significand = significand.zext(precision);
4227-
}
4228-
APInt ten(precision, 10);
4229-
APInt digit(precision, 0);
4230-
4231-
bool inTrail = true;
4232-
while (significand != 0) {
4233-
// digit <- significand % 10
4234-
// significand <- significand / 10
4235-
APInt::udivrem(significand, ten, significand, digit);
4236-
4237-
unsigned d = digit.getZExtValue();
4238-
4239-
// Drop trailing zeros.
4240-
if (inTrail && !d) exp++;
4241-
else {
4242-
buffer.push_back((char) ('0' + d));
4243-
inTrail = false;
4244-
}
4245-
}
4246-
4247-
assert(!buffer.empty() && "no characters in buffer!");
4248-
4249-
// Drop down to FormatPrecision.
4250-
// TODO: don't do more precise calculations above than are required.
4251-
AdjustToPrecision(buffer, exp, FormatPrecision);
4252-
4253-
unsigned NDigits = buffer.size();
4254-
4255-
// Check whether we should use scientific notation.
4256-
bool FormatScientific;
4257-
if (!FormatMaxPadding)
4258-
FormatScientific = true;
4259-
else {
4260-
if (exp >= 0) {
4261-
// 765e3 --> 765000
4262-
// ^^^
4263-
// But we shouldn't make the number look more precise than it is.
4264-
FormatScientific = ((unsigned) exp > FormatMaxPadding ||
4265-
NDigits + (unsigned) exp > FormatPrecision);
4266-
} else {
4267-
// Power of the most significant digit.
4268-
int MSD = exp + (int) (NDigits - 1);
4269-
if (MSD >= 0) {
4270-
// 765e-2 == 7.65
4271-
FormatScientific = false;
4272-
} else {
4273-
// 765e-5 == 0.00765
4274-
// ^ ^^
4275-
FormatScientific = ((unsigned) -MSD) > FormatMaxPadding;
4276-
}
4277-
}
4278-
}
4279-
4280-
// Scientific formatting is pretty straightforward.
4281-
if (FormatScientific) {
4282-
exp += (NDigits - 1);
4283-
4284-
Str.push_back(buffer[NDigits-1]);
4285-
Str.push_back('.');
4286-
if (NDigits == 1 && TruncateZero)
4287-
Str.push_back('0');
4288-
else
4289-
for (unsigned I = 1; I != NDigits; ++I)
4290-
Str.push_back(buffer[NDigits-1-I]);
4291-
// Fill with zeros up to FormatPrecision.
4292-
if (!TruncateZero && FormatPrecision > NDigits - 1)
4293-
Str.append(FormatPrecision - NDigits + 1, '0');
4294-
// For !TruncateZero we use lower 'e'.
4295-
Str.push_back(TruncateZero ? 'E' : 'e');
4296-
4297-
Str.push_back(exp >= 0 ? '+' : '-');
4298-
if (exp < 0) exp = -exp;
4299-
SmallVector<char, 6> expbuf;
4300-
do {
4301-
expbuf.push_back((char) ('0' + (exp % 10)));
4302-
exp /= 10;
4303-
} while (exp);
4304-
// Exponent always at least two digits if we do not truncate zeros.
4305-
if (!TruncateZero && expbuf.size() < 2)
4306-
expbuf.push_back('0');
4307-
for (unsigned I = 0, E = expbuf.size(); I != E; ++I)
4308-
Str.push_back(expbuf[E-1-I]);
4309-
return;
4310-
}
4311-
4312-
// Non-scientific, positive exponents.
4313-
if (exp >= 0) {
4314-
for (unsigned I = 0; I != NDigits; ++I)
4315-
Str.push_back(buffer[NDigits-1-I]);
4316-
for (unsigned I = 0; I != (unsigned) exp; ++I)
4317-
Str.push_back('0');
4318-
return;
4319-
}
4320-
4321-
// Non-scientific, negative exponents.
4322-
4323-
// The number of digits to the left of the decimal point.
4324-
int NWholeDigits = exp + (int) NDigits;
4325-
4326-
unsigned I = 0;
4327-
if (NWholeDigits > 0) {
4328-
for (; I != (unsigned) NWholeDigits; ++I)
4329-
Str.push_back(buffer[NDigits-I-1]);
4330-
Str.push_back('.');
4331-
} else {
4332-
unsigned NZeros = 1 + (unsigned) -NWholeDigits;
4333-
4334-
Str.push_back('0');
4335-
Str.push_back('.');
4336-
for (unsigned Z = 1; Z != NZeros; ++Z)
4337-
Str.push_back('0');
4338-
}
4354+
toStringImpl(Str, isNegative(), exp, significand, FormatPrecision,
4355+
FormatMaxPadding, TruncateZero);
43394356

4340-
for (; I != NDigits; ++I)
4341-
Str.push_back(buffer[NDigits-I-1]);
43424357
}
43434358

43444359
bool IEEEFloat::getExactInverse(APFloat *inv) const {

0 commit comments

Comments
 (0)