[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:00 PDT 2026


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

Core-math exhaustive test passes

CC: @lntue 

>From 890dcf189d430c2e7d5de63b1d0a04631946bbb7 Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Mon, 23 Mar 2026 16:41:26 +0200
Subject: [PATCH] [libc][math] Fix spurious underflow exception in atan2f16

---
 libc/src/__support/math/atan2f16.h   | 10 ++++++++++
 libc/test/src/math/atan2f16_test.cpp | 26 ++++++++++++++++++++++++++
 2 files changed, 36 insertions(+)

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();



More information about the libc-commits mailing list