[libc-commits] [libc] bb6966a - [libc] Return correct values for hypot when overflowed.

Tue Ly via libc-commits libc-commits at lists.llvm.org
Wed Sep 7 16:23:35 PDT 2022


Author: Tue Ly
Date: 2022-09-07T19:23:11-04:00
New Revision: bb6966aa5340609dc5144b9f496f548bc53f7e60

URL: https://github.com/llvm/llvm-project/commit/bb6966aa5340609dc5144b9f496f548bc53f7e60
DIFF: https://github.com/llvm/llvm-project/commit/bb6966aa5340609dc5144b9f496f548bc53f7e60.diff

LOG: [libc] Return correct values for hypot when overflowed.

Hypot incorrectly returns +Inf when overflowed with FE_DOWNWARD and
FE_TOWARDZERO rounding modes.

Reviewed By: sivachandra, zimmermann6

Differential Revision: https://reviews.llvm.org/D133370

Added: 
    

Modified: 
    libc/src/__support/FPUtil/Hypot.h
    libc/test/src/math/HypotTest.h

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/FPUtil/Hypot.h b/libc/src/__support/FPUtil/Hypot.h
index 077e8db20b03c..de22691f7de79 100644
--- a/libc/src/__support/FPUtil/Hypot.h
+++ b/libc/src/__support/FPUtil/Hypot.h
@@ -189,7 +189,10 @@ static inline T hypot(T x, T y) {
       sum >>= 2;
       ++out_exp;
       if (out_exp >= FPBits_t::MAX_EXPONENT) {
-        return T(FPBits_t::inf());
+        if (int round_mode = get_round();
+            round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
+          return T(FPBits_t::inf());
+        return T(FPBits_t(FPBits_t::MAX_NORMAL));
       }
     } else {
       // For denormal result, we simply move the leading bit of the result to
@@ -227,7 +230,8 @@ static inline T hypot(T x, T y) {
   y_new >>= 1;
 
   // Round to the nearest, tie to even.
-  switch (get_round()) {
+  int round_mode = get_round();
+  switch (round_mode) {
   case FE_TONEAREST:
     // Round to nearest, ties to even
     if (round_bit && (lsb || sticky_bits || (r != 0)))
@@ -243,7 +247,9 @@ static inline T hypot(T x, T y) {
     y_new -= ONE >> 1;
     ++out_exp;
     if (out_exp >= FPBits_t::MAX_EXPONENT) {
-      return T(FPBits_t::inf());
+      if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
+        return T(FPBits_t::inf());
+      return T(FPBits_t(FPBits_t::MAX_NORMAL));
     }
   }
 

diff  --git a/libc/test/src/math/HypotTest.h b/libc/test/src/math/HypotTest.h
index b7a7ffdf5312a..57abef8b62342 100644
--- a/libc/test/src/math/HypotTest.h
+++ b/libc/test/src/math/HypotTest.h
@@ -24,24 +24,38 @@ class HypotTestTemplate : public __llvm_libc::testing::Test {
   using Func = T (*)(T, T);
   using FPBits = __llvm_libc::fputil::FPBits<T>;
   using UIntType = typename FPBits::UIntType;
-  const T nan = T(__llvm_libc::fputil::FPBits<T>::build_nan(1));
-  const T inf = T(__llvm_libc::fputil::FPBits<T>::inf());
-  const T neg_inf = T(__llvm_libc::fputil::FPBits<T>::neg_inf());
-  const T zero = T(__llvm_libc::fputil::FPBits<T>::zero());
-  const T neg_zero = T(__llvm_libc::fputil::FPBits<T>::neg_zero());
+  const T nan = T(FPBits::build_nan(1));
+  const T inf = T(FPBits::inf());
+  const T neg_inf = T(FPBits::neg_inf());
+  const T zero = T(FPBits::zero());
+  const T neg_zero = T(FPBits::neg_zero());
+  const T max_normal = T(FPBits(FPBits::MAX_NORMAL));
+  const T min_normal = T(FPBits(FPBits::MIN_NORMAL));
+  const T max_subnormal = T(FPBits(FPBits::MAX_SUBNORMAL));
+  const T min_subnormal = T(FPBits(FPBits::MIN_SUBNORMAL));
 
 public:
   void test_special_numbers(Func func) {
+    constexpr int N = 13;
+    const T SpecialInputs[N] = {inf,           neg_inf,        zero,
+                                neg_zero,      max_normal,     min_normal,
+                                max_subnormal, min_subnormal,  -max_normal,
+                                -min_normal,   -max_subnormal, -min_subnormal};
+
     EXPECT_FP_EQ(func(inf, nan), inf);
     EXPECT_FP_EQ(func(nan, neg_inf), inf);
-    EXPECT_FP_EQ(func(zero, inf), inf);
-    EXPECT_FP_EQ(func(neg_inf, neg_zero), inf);
-
     EXPECT_FP_EQ(func(nan, nan), nan);
     EXPECT_FP_EQ(func(nan, zero), nan);
     EXPECT_FP_EQ(func(neg_zero, nan), nan);
 
-    EXPECT_FP_EQ(func(neg_zero, zero), zero);
+    for (int i = 0; i < N; ++i) {
+      for (int j = 0; j < N; ++j) {
+        mpfr::BinaryInput<T> input{SpecialInputs[i], SpecialInputs[j]};
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Hypot, input,
+                                       func(SpecialInputs[i], SpecialInputs[j]),
+                                       0.5);
+      }
+    }
   }
 
   void test_subnormal_range(Func func) {


        


More information about the libc-commits mailing list