Skip to content

Commit 79ecb81

Browse files
authored
[libc][math] Fix exceptional cases pow(-0, 1/2) and pow(-inf, 1/2). (#110566)
1 parent e96f778 commit 79ecb81

File tree

4 files changed

+24
-2
lines changed

4 files changed

+24
-2
lines changed

libc/src/math/generic/pow.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,16 @@ LLVM_LIBC_FUNCTION(double, pow, (double x, double y)) {
231231
switch (y_a) {
232232
case 0: // y = +-0.0
233233
return 1.0;
234-
case 0x3fe0'0000'0000'0000: // y = +-0.5
234+
case 0x3fe0'0000'0000'0000: { // y = +-0.5
235235
// TODO: speed up x^(-1/2) with rsqrt(x) when available.
236+
if (LIBC_UNLIKELY(!y_sign && (x_u == FPBits::zero(Sign::NEG).uintval() ||
237+
x_u == FPBits::inf(Sign::NEG).uintval()))) {
238+
// pow(-0, 1/2) = +0
239+
// pow(-inf, 1/2) = +inf
240+
return FPBits(x_abs).get_val();
241+
}
236242
return y_sign ? (1.0 / fputil::sqrt<double>(x)) : fputil::sqrt<double>(x);
243+
}
237244
case 0x3ff0'0000'0000'0000: // y = +-1.0
238245
return y_sign ? (1.0 / x) : x;
239246
case 0x4000'0000'0000'0000: // y = +-2.0;

libc/src/math/generic/powf.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,11 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
563563
switch (y_u) {
564564
case 0x3f00'0000: // y = 0.5f
565565
// pow(x, 1/2) = sqrt(x)
566+
if (LIBC_UNLIKELY(x_u == 0x8000'0000 || x_u == 0xff80'0000)) {
567+
// pow(-0, 1/2) = +0
568+
// pow(-inf, 1/2) = +inf
569+
return FloatBits(x_abs).get_val();
570+
}
566571
return fputil::sqrt<float>(x);
567572
case 0x3f80'0000: // y = 1.0f
568573
return x;

libc/test/src/math/smoke/pow_test.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
2222
constexpr double POS_ODD_INTEGER = 5.0;
2323
constexpr double POS_EVEN_INTEGER = 8.0;
2424
constexpr double POS_NON_INTEGER = 1.1;
25+
constexpr double ONE_HALF = 0.5;
2526

2627
for (int i = 0; i < N_ROUNDING_MODES; ++i) {
2728
ForceRoundingMode __r(ROUNDING_MODES[i]);
@@ -38,6 +39,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
3839
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(zero, POS_ODD_INTEGER));
3940
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(zero, POS_EVEN_INTEGER));
4041
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(zero, POS_NON_INTEGER));
42+
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(zero, ONE_HALF));
4143
EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(zero, zero));
4244
EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(zero, neg_zero));
4345
EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::pow(zero, inf));
@@ -55,6 +57,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
5557
EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::pow(neg_zero, POS_ODD_INTEGER));
5658
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(neg_zero, POS_EVEN_INTEGER));
5759
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(neg_zero, POS_NON_INTEGER));
60+
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(neg_zero, ONE_HALF));
5861
EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(neg_zero, zero));
5962
EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(neg_zero, neg_zero));
6063
EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::pow(neg_zero, inf));
@@ -105,6 +108,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
105108
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, POS_ODD_INTEGER));
106109
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, POS_EVEN_INTEGER));
107110
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, POS_NON_INTEGER));
111+
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, ONE_HALF));
108112
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(inf, inf));
109113
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(inf, neg_inf));
110114
EXPECT_FP_IS_NAN(LIBC_NAMESPACE::pow(inf, aNaN));
@@ -120,6 +124,7 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
120124
EXPECT_FP_EQ(neg_inf, LIBC_NAMESPACE::pow(neg_inf, POS_ODD_INTEGER));
121125
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(neg_inf, POS_EVEN_INTEGER));
122126
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(neg_inf, POS_NON_INTEGER));
127+
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(neg_inf, ONE_HALF));
123128
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::pow(neg_inf, inf));
124129
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::pow(neg_inf, neg_inf));
125130
EXPECT_FP_IS_NAN(LIBC_NAMESPACE::pow(neg_inf, aNaN));

libc/test/src/math/smoke/powf_test.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
2525
constexpr float neg_non_integer = -1.1f;
2626
constexpr float pos_odd_integer = 5.0f;
2727
constexpr float pos_even_integer = 8.0f;
28-
constexpr float pos_non_integer = 1.1f;
28+
constexpr float pos_non_integer = 1.3f;
29+
constexpr float one_half = 0.5f;
2930

3031
for (int i = 0; i < N_ROUNDING_MODES; ++i) {
3132
ForceRoundingMode __r(ROUNDING_MODES[i]);
@@ -42,6 +43,7 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
4243
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(zero, pos_odd_integer));
4344
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(zero, pos_even_integer));
4445
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(zero, pos_non_integer));
46+
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(zero, one_half));
4547
EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(zero, zero));
4648
EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(zero, neg_zero));
4749
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::powf(zero, inf));
@@ -59,6 +61,7 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
5961
EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::powf(neg_zero, pos_odd_integer));
6062
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(neg_zero, pos_even_integer));
6163
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(neg_zero, pos_non_integer));
64+
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(neg_zero, one_half));
6265
EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(neg_zero, zero));
6366
EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(neg_zero, neg_zero));
6467
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::powf(neg_zero, inf));
@@ -109,6 +112,7 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
109112
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, pos_odd_integer));
110113
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, pos_even_integer));
111114
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, pos_non_integer));
115+
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, one_half));
112116
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(inf, inf));
113117
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(inf, neg_inf));
114118
EXPECT_FP_IS_NAN(LIBC_NAMESPACE::powf(inf, aNaN));
@@ -124,6 +128,7 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) {
124128
EXPECT_FP_EQ(neg_inf, LIBC_NAMESPACE::powf(neg_inf, pos_odd_integer));
125129
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(neg_inf, pos_even_integer));
126130
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(neg_inf, pos_non_integer));
131+
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(neg_inf, one_half));
127132
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::powf(neg_inf, inf));
128133
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::powf(neg_inf, neg_inf));
129134
EXPECT_FP_IS_NAN(LIBC_NAMESPACE::powf(neg_inf, aNaN));

0 commit comments

Comments
 (0)