[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