Skip to content

[APFloat] add power #122889

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open

[APFloat] add power #122889

wants to merge 11 commits into from

Conversation

ImanHosseini
Copy link
Contributor

No description provided.

@ImanHosseini ImanHosseini changed the title [ADTadd APFloat power [ADT] add APFloat power Jan 14, 2025
@ImanHosseini ImanHosseini changed the title [ADT] add APFloat power [APFloat] add power Jan 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 14, 2025

@llvm/pr-subscribers-llvm-adt

Author: Iman Hosseini (ImanHosseini)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/122889.diff

2 Files Affected:

  • (modified) llvm/include/llvm/ADT/APFloat.h (+21)
  • (modified) llvm/unittests/ADT/APFloatTest.cpp (+15)
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index 9792749230cbf9..803949cf9abcbf 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -1536,6 +1536,27 @@ inline APFloat abs(APFloat X) {
   return X;
 }
 
+/// Returns X^N for N >= 0.
+/// Returns X^N for N >= 0.
+inline APFloat pow(const APFloat &X, const int &N) {
+  assert(N >= 0 && "negative exponents not supported.");
+  APFloat Acc = APFloat::getOne(X.getSemantics());
+  if (N == 0) {
+    return APFloat::getOne(X.getSemantics());
+  }
+  APFloat Base = X;
+  int64_t RemainingExponent = N;
+  while (RemainingExponent > 0) {
+    while (RemainingExponent % 2 == 0) {
+      Base = Base * Base;
+      RemainingExponent /= 2;
+    }
+    --RemainingExponent;
+    Acc = Acc * Base;
+  }
+  return Acc;
+};
+
 /// Returns the negated value of the argument.
 inline APFloat neg(APFloat X) {
   X.changeSign();
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp
index f291c814886d35..0e4fe151af10af 100644
--- a/llvm/unittests/ADT/APFloatTest.cpp
+++ b/llvm/unittests/ADT/APFloatTest.cpp
@@ -3793,6 +3793,21 @@ TEST(APFloatTest, abs) {
   EXPECT_TRUE(PSmallestNormalized.bitwiseIsEqual(abs(MSmallestNormalized)));
 }
 
+TEST(APFloatTest, pow) {
+  APFloat One = APFloat(APFloat::IEEEsingle(), "1.0");
+  APFloat Two = APFloat(APFloat::IEEEsingle(), "2.0");
+  APFloat Four = APFloat(APFloat::IEEEsingle(), "4.0");
+  APFloat Eight = APFloat(APFloat::IEEEsingle(), "8.0");
+  APFloat NegTwo = APFloat(APFloat::IEEEsingle(), "-2.0");
+  APFloat NegEight = APFloat(APFloat::IEEEsingle(), "-8.0");
+
+  EXPECT_TRUE(One.bitwiseIsEqual(pow(One, 0)));
+  EXPECT_TRUE(One.bitwiseIsEqual(pow(One, 3)));
+  EXPECT_TRUE(Four.bitwiseIsEqual(pow(Two, 2)));
+  EXPECT_TRUE(Eight.bitwiseIsEqual(pow(Two, 3)));
+  EXPECT_TRUE(NegEight.bitwiseIsEqual(pow(NegTwo, 3)));
+}
+
 TEST(APFloatTest, neg) {
   APFloat One = APFloat(APFloat::IEEEsingle(), "1.0");
   APFloat NegOne = APFloat(APFloat::IEEEsingle(), "-1.0");

@ImanHosseini
Copy link
Contributor Author

I am not an expert on float edge cases.
What special case should we test here? @arsenm

@ImanHosseini ImanHosseini requested a review from arsenm January 14, 2025 13:56
Copy link
Member

@kuhar kuhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What special case should we test here?

IEEE 754-2019 does list a bunch of edge cases for pown -- we could adopt those.

@nikic nikic requested a review from jcranmer-intel January 14, 2025 20:01
@@ -1536,6 +1536,26 @@ inline APFloat abs(APFloat X) {
return X;
}

/// Returns X^N for N >= 0.
inline APFloat pow(const APFloat &X, int64_t N) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pow is absolutely the wrong name for this function, since there is a standard pow function that this does not implement. powi (which is the LLVM intrinsic name) or pown would work better, though I worry that this is too numerically inaccurate to be a correct implementation of pown.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jcranmer-intel . I will rename to powi.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pown would work better, though I worry that this is too numerically inaccurate to be a correct implementation of pown

@jcranmer-intel do we have some reference implementation of pown in llvm?

Copy link
Contributor Author

@ImanHosseini ImanHosseini Jan 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we do (even in libc): https://libc.llvm.org/headers/math/index.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should add this unless it's correctly rounded

@arsenm arsenm added the floating-point Floating-point math label Jan 15, 2025
assert(N >= 0 && "negative exponents not supported.");
APFloat Acc = APFloat::getOne(X.getSemantics());
if (N == 0) {
return Acc;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should canonicalize the value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For N==0? Can you explain?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All paths through the function, but yes this one too. Signaling nans should be quieted

EXPECT_TRUE(Eight.bitwiseIsEqual(pow(Two, 3)));
EXPECT_TRUE(NegEight.bitwiseIsEqual(pow(NegTwo, 3)));
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test the zeroes, the infinities, nan (particularly that signaling nan is quieted with payload preserved in the no-op case). Also largest denormal / smallest normal, largest normal.

Copy link
Contributor Author

@ImanHosseini ImanHosseini Jan 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything left out? I've added tests covering these.

Copy link

github-actions bot commented Jan 15, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Member

@kuhar kuhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have some other usecase in mind other than #122450 ? If not, I don't think we should land this until we agree on that.
I'm going to add a blocking review to make sure we don't accidentally land this.

EXPECT_TRUE(PosQNaN.bitwiseIsEqual(powi(PosQNaN, 1)));
EXPECT_TRUE(NegQNaN.bitwiseIsEqual(powi(NegQNaN, 1)));
// Check signaling NaN is quieted for n == 1.
EXPECT_TRUE(PosQNaN.bitwiseIsEqual(powi(PosSNaN, 1)));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arsenm there are now tests for quieting SNaNs.
Now what should we test for correct rounding?

Copy link
Contributor Author

@ImanHosseini ImanHosseini Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gcc's powi builtin: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fpowi
: https://github.com/gcc-mirror/gcc/blob/26b2d9f27ca24f0705641a85f29d179fa0600869/libgcc/libgcc2.c#L2582
It is not named pown (to avoid confusion with guarantees that pown makes) but powi, and we aren't committing to any precision or rounding guarantee. Same as with gcc's powi.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
floating-point Floating-point math llvm:adt
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants