Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 24, 2024

Conversation

klausler
Copy link
Contributor

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.

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.
@klausler klausler requested a review from psteinfeld April 23, 2024 23:26
@llvmbot llvmbot added flang:runtime flang Flang issues not falling into any other category labels Apr 23, 2024
@llvmbot
Copy link
Member

llvmbot commented Apr 23, 2024

@llvm/pr-subscribers-flang-runtime

Author: Peter Klausler (klausler)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/89846.diff

2 Files Affected:

  • (modified) flang/runtime/edit-output.cpp (+11-3)
  • (modified) flang/unittests/Runtime/NumericalFormatTest.cpp (+17)
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.!
+}

Copy link
Contributor

@psteinfeld psteinfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick fix!

You're the best.

@klausler klausler merged commit fa465b4 into llvm:main Apr 24, 2024
@klausler klausler deleted the digits branch April 24, 2024 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:runtime flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants