[flang-commits] [flang] [flang][runtime] Improve confusing list-directed REAL(2) output (PR #89846)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Tue Apr 23 16:26:49 PDT 2024


https://github.com/klausler created https://github.com/llvm/llvm-project/pull/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.

>From 1d0460f4d60725cf2353e3607fdd4ff15cf4a840 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Tue, 23 Apr 2024 16:17:06 -0700
Subject: [PATCH] [flang][runtime] Improve confusing list-directed REAL(2)
 output

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.
---
 flang/runtime/edit-output.cpp                   | 14 +++++++++++---
 flang/unittests/Runtime/NumericalFormatTest.cpp | 17 +++++++++++++++++
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/flang/runtime/edit-output.cpp b/flang/runtime/edit-output.cpp
index a06ed258f0f1d2..834bc9bb358972 100644
--- a/flang/runtime/edit-output.cpp
+++ b/flang/runtime/edit-output.cpp
@@ -446,6 +446,7 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
       fracDigits = sizeof buffer_ - 2; // sign & NUL
     }
   }
+  bool emitTrailingZeroes{!(flags & decimal::Minimize)};
   // Multiple conversions may be needed to get the right number of
   // effective rounded fractional digits.
   bool canIncrease{true};
@@ -526,11 +527,18 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
     }
     int digitsBeforePoint{std::max(0, std::min(expo, convertedDigits))};
     int zeroesBeforePoint{std::max(0, expo - digitsBeforePoint)};
+    if (zeroesBeforePoint > 0 && (flags & decimal::Minimize)) {
+      // If a minimized result looks like an integer, emit all of
+      // its digits rather than clipping some to zeroes.
+      // This can happen with HUGE(0._2) == 65504._2.
+      flags &= ~decimal::Minimize;
+      continue;
+    }
     int zeroesAfterPoint{std::min(fracDigits, std::max(0, -expo))};
     int digitsAfterPoint{convertedDigits - digitsBeforePoint};
-    int trailingZeroes{flags & decimal::Minimize
-            ? 0
-            : std::max(0, fracDigits - (zeroesAfterPoint + digitsAfterPoint))};
+    int trailingZeroes{emitTrailingZeroes
+            ? std::max(0, fracDigits - (zeroesAfterPoint + digitsAfterPoint))
+            : 0};
     if (digitsBeforePoint + zeroesBeforePoint + zeroesAfterPoint +
             digitsAfterPoint + trailingZeroes ==
         0) {
diff --git a/flang/unittests/Runtime/NumericalFormatTest.cpp b/flang/unittests/Runtime/NumericalFormatTest.cpp
index dee4dda4a22869..2a9f8f8d1dc4f3 100644
--- a/flang/unittests/Runtime/NumericalFormatTest.cpp
+++ b/flang/unittests/Runtime/NumericalFormatTest.cpp
@@ -958,3 +958,20 @@ TEST(IOApiTests, EditDoubleInputValues) {
                            << "', want " << want << ", got " << u.raw;
   }
 }
+
+// regression test for confusing digit minimization
+TEST(IOApiTests, ConfusingMinimization) {
+  char buffer[8]{};
+  auto cookie{IONAME(BeginInternalListOutput)(buffer, sizeof buffer)};
+  StaticDescriptor<0> staticDescriptor;
+  Descriptor &desc{staticDescriptor.descriptor()};
+  std::uint16_t x{0x7bff}; // HUGE(0._2)
+  desc.Establish(TypeCode{CFI_type_half_float}, sizeof x, &x, 0, nullptr);
+  desc.Check();
+  EXPECT_TRUE(IONAME(OutputDescriptor)(cookie, desc));
+  auto status{IONAME(EndIoStatement)(cookie)};
+  EXPECT_EQ(status, 0);
+  std::string got{std::string{buffer, sizeof buffer}};
+  EXPECT_TRUE(CompareFormattedStrings(" 65504. ", got))
+      << "expected ' 65504. ', got '" << got << '\''; // not 65500.!
+}



More information about the flang-commits mailing list