diff --git a/flang/runtime/edit-output.h b/flang/runtime/edit-output.h --- a/flang/runtime/edit-output.h +++ b/flang/runtime/edit-output.h @@ -37,14 +37,18 @@ protected: explicit RealOutputEditingBase(IoStatementState &io) : io_{io} {} - static bool IsDecimalNumber(const char *p) { - if (!p) { + static bool IsInfOrNaN(const decimal::ConversionToDecimalResult &res) { + const char *p{res.str}; + if (!p || res.length < 1) { return false; } if (*p == '-' || *p == '+') { + if (res.length == 1) { + return false; + } ++p; } - return *p >= '0' && *p <= '9'; + return *p < '0' || *p > '9'; } const char *FormatExponent(int, const DataEdit &edit, int &length); diff --git a/flang/runtime/edit-output.cpp b/flang/runtime/edit-output.cpp --- a/flang/runtime/edit-output.cpp +++ b/flang/runtime/edit-output.cpp @@ -205,7 +205,7 @@ while (true) { decimal::ConversionToDecimalResult converted{ Convert(significantDigits, edit, flags)}; - if (converted.length > 0 && !IsDecimalNumber(converted.str)) { // Inf, NaN + if (IsInfOrNaN(converted)) { return EmitPrefix(edit, converted.length, editWidth) && io_.Emit(converted.str, converted.length) && EmitSuffix(edit); } @@ -260,8 +260,7 @@ template bool RealOutputEditing::EditFOutput(const DataEdit &edit) { int fracDigits{edit.digits.value_or(0)}; // 'd' field - int extraDigits{0}; - int editWidth{edit.width.value_or(0)}; // 'w' field + const int editWidth{edit.width.value_or(0)}; // 'w' field int flags{0}; if (editWidth == 0) { // "the processor selects the field width" if (!edit.digits.has_value()) { // F0 @@ -271,27 +270,31 @@ } // Multiple conversions may be needed to get the right number of // effective rounded fractional digits. + int extraDigits{0}; while (true) { decimal::ConversionToDecimalResult converted{ Convert(extraDigits + fracDigits, edit, flags)}; - if (converted.length > 0 && !IsDecimalNumber(converted.str)) { // Inf, NaN + if (IsInfOrNaN(converted)) { return EmitPrefix(edit, converted.length, editWidth) && io_.Emit(converted.str, converted.length) && EmitSuffix(edit); } int scale{IsZero() ? -1 : edit.modes.scale}; int expo{converted.decimalExponent - scale}; - if (expo > extraDigits) { + if (expo > extraDigits && extraDigits >= 0) { extraDigits = expo; - if (flags & decimal::Minimize) { + if (!edit.digits.has_value()) { // F0 fracDigits = sizeof buffer_ - extraDigits - 2; // sign & NUL } - continue; // try again + continue; + } else if (expo < extraDigits && extraDigits > -fracDigits) { + extraDigits = std::max(expo, -fracDigits); + continue; } int signLength{*converted.str == '-' || *converted.str == '+' ? 1 : 0}; int convertedDigits{static_cast(converted.length) - signLength}; int digitsBeforePoint{std::max(0, std::min(expo, convertedDigits))}; int zeroesBeforePoint{std::max(0, expo - digitsBeforePoint)}; - int zeroesAfterPoint{std::max(0, -expo)}; + int zeroesAfterPoint{std::min(fracDigits, std::max(0, -expo))}; int digitsAfterPoint{convertedDigits - digitsBeforePoint}; int trailingZeroes{flags & decimal::Minimize ? 0 @@ -299,7 +302,7 @@ if (digitsBeforePoint + zeroesBeforePoint + zeroesAfterPoint + digitsAfterPoint + trailingZeroes == 0) { - ++zeroesBeforePoint; // "." -> "0." + zeroesBeforePoint = 1; // "." -> "0." } int totalLength{signLength + digitsBeforePoint + zeroesBeforePoint + 1 /*'.'*/ + zeroesAfterPoint + digitsAfterPoint + trailingZeroes}; @@ -332,7 +335,7 @@ return edit; // Gw.0 -> Ew.0 for w > 0 } decimal::ConversionToDecimalResult converted{Convert(1, edit)}; - if (!IsDecimalNumber(converted.str)) { // Inf, NaN + if (IsInfOrNaN(converted)) { return edit; } int expo{IsZero() ? 1 : converted.decimalExponent}; // 's' @@ -361,7 +364,7 @@ bool RealOutputEditing::EditListDirectedOutput( const DataEdit &edit) { decimal::ConversionToDecimalResult converted{Convert(1, edit)}; - if (!IsDecimalNumber(converted.str)) { // Inf, NaN + if (IsInfOrNaN(converted)) { return EditEorDOutput(edit); } int expo{converted.decimalExponent}; diff --git a/flang/unittests/Runtime/hello.cpp b/flang/unittests/Runtime/hello.cpp --- a/flang/unittests/Runtime/hello.cpp +++ b/flang/unittests/Runtime/hello.cpp @@ -402,6 +402,21 @@ "4040261841248583680000+306;"); realTest("(G0,';')", u.d, ".17976931348623157+309;"); + realTest("(F5.3,';')", 25., "*****;"); + realTest("(F5.3,';')", 2.5, "2.500;"); + realTest("(F5.3,';')", 0.25, "0.250;"); + realTest("(F5.3,';')", 0.025, "0.025;"); + realTest("(F5.3,';')", 0.0025, "0.003;"); + realTest("(F5.3,';')", 0.00025, "0.000;"); + realTest("(F5.3,';')", 0.000025, "0.000;"); + realTest("(F5.3,';')", -25., "*****;"); + realTest("(F5.3,';')", -2.5, "*****;"); + realTest("(F5.3,';')", -0.25, "-.250;"); + realTest("(F5.3,';')", -0.025, "-.025;"); + realTest("(F5.3,';')", -0.0025, "-.003;"); + realTest("(F5.3,';')", -0.00025, "-.000;"); + realTest("(F5.3,';')", -0.000025, "-.000;"); + realInTest("(F18.0)", " 0", 0x0); realInTest("(F18.0)", " ", 0x0); realInTest("(F18.0)", " -0", 0x8000000000000000);