[libc-commits] [libc] [libc][math] Fix spurious underflow exception in atan2f16 (PR #188047)

via libc-commits libc-commits at lists.llvm.org
Mon Mar 23 07:43:35 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: Anonmiraj (AnonMiraj)

<details>
<summary>Changes</summary>

Core-math exhaustive test passes

CC: @<!-- -->lntue 

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


2 Files Affected:

- (modified) libc/src/__support/math/atan2f16.h (+10) 
- (modified) libc/test/src/math/atan2f16_test.cpp (+26) 


``````````diff
diff --git a/libc/src/__support/math/atan2f16.h b/libc/src/__support/math/atan2f16.h
index 297167a429d9f..06b0e961c5912 100644
--- a/libc/src/__support/math/atan2f16.h
+++ b/libc/src/__support/math/atan2f16.h
@@ -96,6 +96,16 @@ LIBC_INLINE float16 atan2f16(float16 y, float16 x) {
   double p = atan_eval(q_d, static_cast<unsigned>(idx));
   double r = final_sign *
              fputil::multiply_add(q_d, p, const_term + ATAN_K_OVER_16[idx]);
+
+  double abs_r = r > 0 ? r : -r;
+  double min_normal = 0x1.0p-14;
+  double half_ulp = 0x1.0p-25;
+  if (LIBC_UNLIKELY(abs_r > (min_normal - half_ulp) && abs_r < min_normal)) {
+    if (fputil::fenv_is_round_to_nearest()) {
+      r = r > 0 ? min_normal : -min_normal;
+    }
+  }
+
   return fputil::cast<float16>(r);
 }
 
diff --git a/libc/test/src/math/atan2f16_test.cpp b/libc/test/src/math/atan2f16_test.cpp
index b4214e932f591..5a1df3af47b3f 100644
--- a/libc/test/src/math/atan2f16_test.cpp
+++ b/libc/test/src/math/atan2f16_test.cpp
@@ -56,6 +56,32 @@ TEST_F(LlvmLibcAtan2f16Test, TrickyInputs) {
   }
 }
 
+TEST_F(LlvmLibcAtan2f16Test, SpuriousUnderflow) {
+  mpfr::ForceRoundingMode r(mpfr::RoundingMode::Nearest);
+  if (!r.success)
+    return;
+
+  constexpr int N = 1;
+  mpfr::BinaryInput<float16> INPUTS[N] = {
+      {0x1.0p-24f16, 0x1.0p-10f16},
+  };
+
+  for (int i = 0; i < N; ++i) {
+    float16 y = INPUTS[i].x;
+    float16 x = INPUTS[i].y;
+
+    LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+    float16 result = LIBC_NAMESPACE::atan2f16(y, x);
+    int excepts = LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT);
+
+    EXPECT_EQ(excepts & FE_UNDERFLOW, 0);
+    EXPECT_NE(excepts & FE_INEXACT, 0);
+
+    ASSERT_MPFR_MATCH(mpfr::Operation::Atan2, INPUTS[i], result, 0.5,
+                      mpfr::RoundingMode::Nearest);
+  }
+}
+
 TEST_F(LlvmLibcAtan2f16Test, InFloat16Range) {
   constexpr uint16_t X_START = FPBits(static_cast<float16>(0.25f)).uintval();
   constexpr uint16_t X_STOP = FPBits(static_cast<float16>(4.0f)).uintval();

``````````

</details>


https://github.com/llvm/llvm-project/pull/188047


More information about the libc-commits mailing list