[libc-commits] [libc] 79ecb81 - [libc][math] Fix exceptional cases pow(-0, 1/2) and pow(-inf, 1/2). (#110566)

via libc-commits libc-commits at lists.llvm.org
Tue Oct 1 03:37:50 PDT 2024


Author: lntue
Date: 2024-10-01T06:37:47-04:00
New Revision: 79ecb814d0c929a66ad92c7b3e91191f01247ac1

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

LOG: [libc][math] Fix exceptional cases pow(-0, 1/2) and pow(-inf, 1/2). (#110566)

Added: 
    

Modified: 
    libc/src/math/generic/pow.cpp
    libc/src/math/generic/powf.cpp
    libc/test/src/math/smoke/pow_test.cpp
    libc/test/src/math/smoke/powf_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/src/math/generic/pow.cpp b/libc/src/math/generic/pow.cpp
index 20f914430261c1..3a50e220154e51 100644
--- a/libc/src/math/generic/pow.cpp
+++ b/libc/src/math/generic/pow.cpp
@@ -231,9 +231,16 @@ LLVM_LIBC_FUNCTION(double, pow, (double x, double y)) {
     switch (y_a) {
     case 0: // y = +-0.0
       return 1.0;
-    case 0x3fe0'0000'0000'0000: // y = +-0.5
+    case 0x3fe0'0000'0000'0000: { // y = +-0.5
       // TODO: speed up x^(-1/2) with rsqrt(x) when available.
+      if (LIBC_UNLIKELY(!y_sign && (x_u == FPBits::zero(Sign::NEG).uintval() ||
+                                    x_u == FPBits::inf(Sign::NEG).uintval()))) {
+        // pow(-0, 1/2) = +0
+        // pow(-inf, 1/2) = +inf
+        return FPBits(x_abs).get_val();
+      }
       return y_sign ? (1.0 / fputil::sqrt<double>(x)) : fputil::sqrt<double>(x);
+    }
     case 0x3ff0'0000'0000'0000: // y = +-1.0
       return y_sign ? (1.0 / x) : x;
     case 0x4000'0000'0000'0000: // y = +-2.0;

diff  --git a/libc/src/math/generic/powf.cpp b/libc/src/math/generic/powf.cpp
index 845ac2521e0905..e3dee678a1a70a 100644
--- a/libc/src/math/generic/powf.cpp
+++ b/libc/src/math/generic/powf.cpp
@@ -563,6 +563,11 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
       switch (y_u) {
       case 0x3f00'0000: // y = 0.5f
         // pow(x, 1/2) = sqrt(x)
+        if (LIBC_UNLIKELY(x_u == 0x8000'0000 || x_u == 0xff80'0000)) {
+          // pow(-0, 1/2) = +0
+          // pow(-inf, 1/2) = +inf
+          return FloatBits(x_abs).get_val();
+        }
         return fputil::sqrt<float>(x);
       case 0x3f80'0000: // y = 1.0f
         return x;

diff  --git a/libc/test/src/math/smoke/pow_test.cpp b/libc/test/src/math/smoke/pow_test.cpp
index 4f2a3a28c0dcbe..7f0136d783c6ba 100644
--- a/libc/test/src/math/smoke/pow_test.cpp
+++ b/libc/test/src/math/smoke/pow_test.cpp
@@ -22,6 +22,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
   constexpr double POS_ODD_INTEGER = 5.0;
   constexpr double POS_EVEN_INTEGER = 8.0;
   constexpr double POS_NON_INTEGER = 1.1;
+  constexpr double ONE_HALF = 0.5;
 
   for (int i = 0; i < N_ROUNDING_MODES; ++i) {
     ForceRoundingMode __r(ROUNDING_MODES[i]);
@@ -38,6 +39,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(zero, POS_ODD_INTEGER));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(zero, POS_EVEN_INTEGER));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(zero, POS_NON_INTEGER));
+    EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(zero, ONE_HALF));
     EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(zero, zero));
     EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(zero, neg_zero));
     EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::pow(zero, inf));
@@ -55,6 +57,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
     EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::pow(neg_zero, POS_ODD_INTEGER));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(neg_zero, POS_EVEN_INTEGER));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(neg_zero, POS_NON_INTEGER));
+    EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(neg_zero, ONE_HALF));
     EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(neg_zero, zero));
     EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(neg_zero, neg_zero));
     EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::pow(neg_zero, inf));
@@ -105,6 +108,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, POS_ODD_INTEGER));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, POS_EVEN_INTEGER));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, POS_NON_INTEGER));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, ONE_HALF));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, inf));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(inf, neg_inf));
     EXPECT_FP_IS_NAN(LIBC_NAMESPACE::pow(inf, aNaN));
@@ -120,6 +124,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
     EXPECT_FP_EQ(neg_inf, LIBC_NAMESPACE::pow(neg_inf, POS_ODD_INTEGER));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(neg_inf, POS_EVEN_INTEGER));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(neg_inf, POS_NON_INTEGER));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(neg_inf, ONE_HALF));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(neg_inf, inf));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(neg_inf, neg_inf));
     EXPECT_FP_IS_NAN(LIBC_NAMESPACE::pow(neg_inf, aNaN));

diff  --git a/libc/test/src/math/smoke/powf_test.cpp b/libc/test/src/math/smoke/powf_test.cpp
index 98a532f3468c73..6aa1ac2b661be2 100644
--- a/libc/test/src/math/smoke/powf_test.cpp
+++ b/libc/test/src/math/smoke/powf_test.cpp
@@ -25,7 +25,8 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
   constexpr float neg_non_integer = -1.1f;
   constexpr float pos_odd_integer = 5.0f;
   constexpr float pos_even_integer = 8.0f;
-  constexpr float pos_non_integer = 1.1f;
+  constexpr float pos_non_integer = 1.3f;
+  constexpr float one_half = 0.5f;
 
   for (int i = 0; i < N_ROUNDING_MODES; ++i) {
     ForceRoundingMode __r(ROUNDING_MODES[i]);
@@ -42,6 +43,7 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(zero, pos_odd_integer));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(zero, pos_even_integer));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(zero, pos_non_integer));
+    EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(zero, one_half));
     EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(zero, zero));
     EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(zero, neg_zero));
     EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::powf(zero, inf));
@@ -59,6 +61,7 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
     EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::powf(neg_zero, pos_odd_integer));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(neg_zero, pos_even_integer));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(neg_zero, pos_non_integer));
+    EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(neg_zero, one_half));
     EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(neg_zero, zero));
     EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(neg_zero, neg_zero));
     EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::powf(neg_zero, inf));
@@ -109,6 +112,7 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, pos_odd_integer));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, pos_even_integer));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, pos_non_integer));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, one_half));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, inf));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(inf, neg_inf));
     EXPECT_FP_IS_NAN(LIBC_NAMESPACE::powf(inf, aNaN));
@@ -124,6 +128,7 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
     EXPECT_FP_EQ(neg_inf, LIBC_NAMESPACE::powf(neg_inf, pos_odd_integer));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(neg_inf, pos_even_integer));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(neg_inf, pos_non_integer));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(neg_inf, one_half));
     EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(neg_inf, inf));
     EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(neg_inf, neg_inf));
     EXPECT_FP_IS_NAN(LIBC_NAMESPACE::powf(neg_inf, aNaN));


        


More information about the libc-commits mailing list