[flang] runtime: For Fw.d formatting, don't oscillate forever

The algorithm for Fw.d output will drive binary to decimal conversion for
an initial fixed number of digits, then adjust that number based on the
result's exposent.  For value close to a power of ten, this adjustment
process wouldn't terminate; e.g., formatting 9.999 as F10.2 would start
with 1e2, boost the digits to 2, get 9.99e1, decrease the digits, and loop.
Solve by refusing to boost the digits a second time.

Differential Revision: https://reviews.llvm.org/D107490
This commit is contained in:
peter klausler 2021-08-02 14:37:40 -07:00
parent 617be2756f
commit 4876520eef
3 changed files with 17 additions and 2 deletions

View File

@ -310,7 +310,6 @@ ConversionToDecimalResult ConvertToDecimal(char *buffer, std::size_t size,
more.Next();
}
number.Minimize(Big{less, rounding}, Big{more, rounding});
} else {
}
return number.ConvertToDecimal(buffer, size, flags, digits);
}

View File

@ -268,6 +268,7 @@ bool RealOutputEditing<binaryPrecision>::EditFOutput(const DataEdit &edit) {
// Multiple conversions may be needed to get the right number of
// effective rounded fractional digits.
int extraDigits{0};
bool canIncrease{true};
while (true) {
decimal::ConversionToDecimalResult converted{
Convert(extraDigits + fracDigits, edit, flags)};
@ -277,11 +278,12 @@ bool RealOutputEditing<binaryPrecision>::EditFOutput(const DataEdit &edit) {
}
int scale{IsZero() ? 1 : edit.modes.scale}; // kP
int expo{converted.decimalExponent + scale};
if (expo > extraDigits && extraDigits >= 0) {
if (expo > extraDigits && extraDigits >= 0 && canIncrease) {
extraDigits = expo;
if (!edit.digits.has_value()) { // F0
fracDigits = sizeof buffer_ - extraDigits - 2; // sign & NUL
}
canIncrease = false; // only once
continue;
} else if (expo < extraDigits && extraDigits > -fracDigits) {
extraDigits = std::max(expo, -fracDigits);

View File

@ -627,6 +627,20 @@ TEST(IOApiTests, FormatDoubleValues) {
{"(F5.3,';')", -0.0025, "-.003;"},
{"(F5.3,';')", -0.00025, "-.000;"},
{"(F5.3,';')", -0.000025, "-.000;"},
{"(F5.3,';')", 99.999, "*****;"},
{"(F5.3,';')", 9.9999, "*****;"},
{"(F5.3,';')", 0.99999, "1.000;"},
{"(F5.3,';')", 0.099999, "0.100;"},
{"(F5.3,';')", 0.0099999, "0.010;"},
{"(F5.3,';')", 0.00099999, "0.001;"},
{"(F5.3,';')", 0.000099999, "0.000;"},
{"(F5.3,';')", -99.999, "*****;"},
{"(F5.3,';')", -9.9999, "*****;"},
{"(F5.3,';')", -0.99999, "*****;"},
{"(F5.3,';')", -0.099999, "-.100;"},
{"(F5.3,';')", -0.0099999, "-.010;"},
{"(F5.3,';')", -0.00099999, "-.001;"},
{"(F5.3,';')", -0.000099999, "-.000;"},
};
for (auto const &[format, value, expect] : individualTestCases) {