-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[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
base: main
Are you sure you want to change the base?
[APFloat] add power #122889
Conversation
@llvm/pr-subscribers-llvm-adt Author: Iman Hosseini (ImanHosseini) ChangesFull diff: https://github.com/llvm/llvm-project/pull/122889.diff 2 Files Affected:
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");
|
I am not an expert on float edge cases. |
There was a problem hiding this 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.
llvm/include/llvm/ADT/APFloat.h
Outdated
@@ -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) { |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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 ofpown
@jcranmer-intel do we have some reference implementation of pown
in llvm?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
assert(N >= 0 && "negative exponents not supported."); | ||
APFloat Acc = APFloat::getOne(X.getSemantics()); | ||
if (N == 0) { | ||
return Acc; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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))); | ||
} | ||
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this 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))); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
.
No description provided.