Skip to content

Commit fa465b4

Browse files
authored
[flang][runtime] Improve confusing list-directed REAL(2) output (#89846)
List-directed output editing of REAL values will minimize the number of digits that are emitted by calculating a decimal value that, if read back in to a REAL variable of the same kind, would compare equal. This behavior is causing some confusion when applied to list-directed output of large REAL(2) values. Specifically, the value HUGE(0._2) (which is 0x7bff in hex) is exactly 65504, but is edited to 65500. by list-directed output, which selects F0 editing, minimizes the value to 6.55e4, and then formats it without the exponent. This small patch changes that behavior for cases where the output of digit-minimized F editing has no digits after the decimal point and zeroes need to be emitted before it due to the decimal exponent. Digit minimization is disabled in this case and the exact digits are emitted instead.
1 parent 6fd475f commit fa465b4

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

flang/runtime/edit-output.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
446446
fracDigits = sizeof buffer_ - 2; // sign & NUL
447447
}
448448
}
449+
bool emitTrailingZeroes{!(flags & decimal::Minimize)};
449450
// Multiple conversions may be needed to get the right number of
450451
// effective rounded fractional digits.
451452
bool canIncrease{true};
@@ -526,11 +527,18 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
526527
}
527528
int digitsBeforePoint{std::max(0, std::min(expo, convertedDigits))};
528529
int zeroesBeforePoint{std::max(0, expo - digitsBeforePoint)};
530+
if (zeroesBeforePoint > 0 && (flags & decimal::Minimize)) {
531+
// If a minimized result looks like an integer, emit all of
532+
// its digits rather than clipping some to zeroes.
533+
// This can happen with HUGE(0._2) == 65504._2.
534+
flags &= ~decimal::Minimize;
535+
continue;
536+
}
529537
int zeroesAfterPoint{std::min(fracDigits, std::max(0, -expo))};
530538
int digitsAfterPoint{convertedDigits - digitsBeforePoint};
531-
int trailingZeroes{flags & decimal::Minimize
532-
? 0
533-
: std::max(0, fracDigits - (zeroesAfterPoint + digitsAfterPoint))};
539+
int trailingZeroes{emitTrailingZeroes
540+
? std::max(0, fracDigits - (zeroesAfterPoint + digitsAfterPoint))
541+
: 0};
534542
if (digitsBeforePoint + zeroesBeforePoint + zeroesAfterPoint +
535543
digitsAfterPoint + trailingZeroes ==
536544
0) {

flang/unittests/Runtime/NumericalFormatTest.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,3 +958,20 @@ TEST(IOApiTests, EditDoubleInputValues) {
958958
<< "', want " << want << ", got " << u.raw;
959959
}
960960
}
961+
962+
// regression test for confusing digit minimization
963+
TEST(IOApiTests, ConfusingMinimization) {
964+
char buffer[8]{};
965+
auto cookie{IONAME(BeginInternalListOutput)(buffer, sizeof buffer)};
966+
StaticDescriptor<0> staticDescriptor;
967+
Descriptor &desc{staticDescriptor.descriptor()};
968+
std::uint16_t x{0x7bff}; // HUGE(0._2)
969+
desc.Establish(TypeCode{CFI_type_half_float}, sizeof x, &x, 0, nullptr);
970+
desc.Check();
971+
EXPECT_TRUE(IONAME(OutputDescriptor)(cookie, desc));
972+
auto status{IONAME(EndIoStatement)(cookie)};
973+
EXPECT_EQ(status, 0);
974+
std::string got{std::string{buffer, sizeof buffer}};
975+
EXPECT_TRUE(CompareFormattedStrings(" 65504. ", got))
976+
<< "expected ' 65504. ', got '" << got << '\''; // not 65500.!
977+
}

0 commit comments

Comments
 (0)