Skip to content

Commit

Permalink
[libc][math] Fix exceptional cases pow(-0, 1/2) and pow(-inf, 1/2). (l…
Browse files Browse the repository at this point in the history
  • Loading branch information
lntue authored Oct 1, 2024
1 parent e96f778 commit 79ecb81
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 2 deletions.
9 changes: 8 additions & 1 deletion libc/src/math/generic/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions libc/src/math/generic/powf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions libc/test/src/math/smoke/pow_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand All @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -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));
Expand All @@ -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));
Expand Down
7 changes: 6 additions & 1 deletion libc/test/src/math/smoke/powf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand All @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -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));
Expand All @@ -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));
Expand Down

0 comments on commit 79ecb81

Please sign in to comment.