-
Notifications
You must be signed in to change notification settings - Fork 5.8k
8355992: Add unsignedMultiplyExact and *powExact methods to Math and StrictMath #25003
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3419,4 +3419,229 @@ static float powerOfTwoF(int n) { | |||||||||||||||||||||||||||||||||||
(FloatConsts.SIGNIFICAND_WIDTH-1)) | ||||||||||||||||||||||||||||||||||||
& FloatConsts.EXP_BIT_MASK); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* Returns the product of the unsigned arguments, | ||||||||||||||||||||||||||||||||||||
* throwing an exception if the result overflows an unsigned {@code int}. | ||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||
* @param x the first unsigned value | ||||||||||||||||||||||||||||||||||||
* @param y the second unsigned value | ||||||||||||||||||||||||||||||||||||
* @return the result | ||||||||||||||||||||||||||||||||||||
* @throws ArithmeticException if the result overflows an unsigned int | ||||||||||||||||||||||||||||||||||||
* @since 25 | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
public static int unsignedMultiplyExact(int x, int y) { | ||||||||||||||||||||||||||||||||||||
long r = (x & 0xFFFF_FFFFL) * (y & 0xFFFF_FFFFL); | ||||||||||||||||||||||||||||||||||||
if (r >>> 32 != 0) { | ||||||||||||||||||||||||||||||||||||
throw new ArithmeticException("unsigned integer overflow"); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
return (int)r; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* Returns the product of the unsigned arguments, | ||||||||||||||||||||||||||||||||||||
* throwing an exception if the result overflows an unsigned {@code long}. | ||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||
* @param x the first unsigned value | ||||||||||||||||||||||||||||||||||||
* @param y the second unsigned value | ||||||||||||||||||||||||||||||||||||
* @return the result | ||||||||||||||||||||||||||||||||||||
* @throws ArithmeticException if the result overflows an unsigned long | ||||||||||||||||||||||||||||||||||||
* @since 25 | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
public static long unsignedMultiplyExact(long x, int y) { | ||||||||||||||||||||||||||||||||||||
return unsignedMultiplyExact(x, y & 0xFFFF_FFFFL); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* Returns the product of the unsigned arguments, | ||||||||||||||||||||||||||||||||||||
* throwing an exception if the result overflows an unsigned {@code long}. | ||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||
* @param x the first unsigned value | ||||||||||||||||||||||||||||||||||||
* @param y the second unsigned value | ||||||||||||||||||||||||||||||||||||
* @return the result | ||||||||||||||||||||||||||||||||||||
* @throws ArithmeticException if the result overflows an unsigned long | ||||||||||||||||||||||||||||||||||||
* @since 25 | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
public static long unsignedMultiplyExact(long x, long y) { | ||||||||||||||||||||||||||||||||||||
long l = x * y; | ||||||||||||||||||||||||||||||||||||
long h = unsignedMultiplyHigh(x, y); | ||||||||||||||||||||||||||||||||||||
if (h == 0) { | ||||||||||||||||||||||||||||||||||||
return l; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
throw new ArithmeticException("unsigned long overflow"); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* Returns {@code x} raised to the power of {@code n}, | ||||||||||||||||||||||||||||||||||||
* throwing an exception if the result overflows an {@code int}. | ||||||||||||||||||||||||||||||||||||
* When {@code n} is 0, the returned value is 1. | ||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||
* @param x the base. | ||||||||||||||||||||||||||||||||||||
* @param n the exponent. | ||||||||||||||||||||||||||||||||||||
* @return {@code x} raised to the power of {@code n}. | ||||||||||||||||||||||||||||||||||||
* @throws ArithmeticException when {@code n} is negative, | ||||||||||||||||||||||||||||||||||||
* or when the result overflows an int. | ||||||||||||||||||||||||||||||||||||
* @since 25 | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
public static int powExact(int x, int n) { | ||||||||||||||||||||||||||||||||||||
/* See the comment in unsignedPowExact(long,int) for the details. */ | ||||||||||||||||||||||||||||||||||||
if (n < 0) { | ||||||||||||||||||||||||||||||||||||
throw new ArithmeticException("negative exponent"); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (n == 0) { | ||||||||||||||||||||||||||||||||||||
return 1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (x == 0 || x == 1) { | ||||||||||||||||||||||||||||||||||||
return x; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (x == -1) { | ||||||||||||||||||||||||||||||||||||
return (n & 0b1) == 0 ? 1 : -1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
With also a check for the condition There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return (n & 0b1) == 0 ? 1 << n : -(1 << n); Equivalent to return ((1 << n) ^ -(n & 1)) + (n & 1); Without branches it should be faster There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It should have a comment that explains that this does the two's complement if |
||||||||||||||||||||||||||||||||||||
int p = 1; | ||||||||||||||||||||||||||||||||||||
while (n > 1) { | ||||||||||||||||||||||||||||||||||||
if ((n & 0b1) != 0) { | ||||||||||||||||||||||||||||||||||||
p *= x; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
x = multiplyExact(x, x); | ||||||||||||||||||||||||||||||||||||
n >>>= 1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
return multiplyExact(p, x); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* Returns unsigned {@code x} raised to the power of {@code n}, | ||||||||||||||||||||||||||||||||||||
* throwing an exception if the result overflows an unsigned {@code int}. | ||||||||||||||||||||||||||||||||||||
* When {@code n} is 0, the returned value is 1. | ||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||
* @param x the unsigned base. | ||||||||||||||||||||||||||||||||||||
* @param n the exponent. | ||||||||||||||||||||||||||||||||||||
* @return {@code x} raised to the power of {@code n}. | ||||||||||||||||||||||||||||||||||||
* @throws ArithmeticException when {@code n} is negative, | ||||||||||||||||||||||||||||||||||||
* or when the result overflows an unsigned int. | ||||||||||||||||||||||||||||||||||||
* @since 25 | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
public static int unsignedPowExact(int x, int n) { | ||||||||||||||||||||||||||||||||||||
/* See the comment in unsignedPowExact(long,int) for the details. */ | ||||||||||||||||||||||||||||||||||||
if (n < 0) { | ||||||||||||||||||||||||||||||||||||
throw new ArithmeticException("negative exponent"); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (n == 0) { | ||||||||||||||||||||||||||||||||||||
return 1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (x == 0 || x == 1) { | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||
return x; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
With also a check for the condition |
||||||||||||||||||||||||||||||||||||
int p = 1; | ||||||||||||||||||||||||||||||||||||
while (n > 1) { | ||||||||||||||||||||||||||||||||||||
if ((n & 0b1) != 0) { | ||||||||||||||||||||||||||||||||||||
p *= x; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
x = unsignedMultiplyExact(x, x); | ||||||||||||||||||||||||||||||||||||
n >>>= 1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
return unsignedMultiplyExact(p, x); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* Returns {@code x} raised to the power of {@code n}, | ||||||||||||||||||||||||||||||||||||
* throwing an exception if the result overflows a {@code long}. | ||||||||||||||||||||||||||||||||||||
* When {@code n} is 0, the returned value is 1. | ||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||
* @param x the base. | ||||||||||||||||||||||||||||||||||||
* @param n the exponent. | ||||||||||||||||||||||||||||||||||||
* @return {@code x} raised to the power of {@code n}. | ||||||||||||||||||||||||||||||||||||
* @throws ArithmeticException when {@code n} is negative, | ||||||||||||||||||||||||||||||||||||
* or when the result overflows a long. | ||||||||||||||||||||||||||||||||||||
* @since 25 | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
public static long powExact(long x, int n) { | ||||||||||||||||||||||||||||||||||||
/* See the comment in unsignedPowExact(long,int) for the details. */ | ||||||||||||||||||||||||||||||||||||
if (n < 0) { | ||||||||||||||||||||||||||||||||||||
throw new ArithmeticException("negative exponent"); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (n == 0) { | ||||||||||||||||||||||||||||||||||||
return 1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (x == 0 || x == 1) { | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @fabioromano1 Unless there's evidence that these cases are very very common, there's no point in adding fast paths.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rgiulietti I would keep at least There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, I don't think that As for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The current implementations of public static int numberOfLeadingZeros(long i) {
int x = (int)(i >>> 32);
return x == 0 ? 32 + Integer.numberOfLeadingZeros((int)i)
: Integer.numberOfLeadingZeros(x);
}
public static int numberOfLeadingZeros(int i) {
// HD, Count leading 0's
if (i <= 0)
return i == 0 ? 32 : 0;
int n = 31;
if (i >= 1 << 16) { n -= 16; i >>>= 16; }
if (i >= 1 << 8) { n -= 8; i >>>= 8; }
if (i >= 1 << 4) { n -= 4; i >>>= 4; }
if (i >= 1 << 2) { n -= 2; i >>>= 2; }
return n - (i >>> 1);
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I'm familiar with both this Java code and the intrinsic code. Compare this with the much simpler proposed code. As a general rule, the simpler the code, the better the outcome of the optimizing compiler. Again, to me there's no point in failing fast at the expense of the successful case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes; we can always try to make simpler code faster if the need or interest arises. |
||||||||||||||||||||||||||||||||||||
return x; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (x == -1) { | ||||||||||||||||||||||||||||||||||||
return (n & 0b1) != 0 ? -1 : 1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
With also a check for the condition |
||||||||||||||||||||||||||||||||||||
long p = 1; | ||||||||||||||||||||||||||||||||||||
while (n > 1) { | ||||||||||||||||||||||||||||||||||||
if ((n & 0b1) != 0) { | ||||||||||||||||||||||||||||||||||||
p *= x; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
x = multiplyExact(x, x); | ||||||||||||||||||||||||||||||||||||
n >>>= 1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
return multiplyExact(p, x); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* Returns unsigned {@code x} raised to the power of {@code n}, | ||||||||||||||||||||||||||||||||||||
* throwing an exception if the result overflows an unsigned {@code long}. | ||||||||||||||||||||||||||||||||||||
* When {@code n} is 0, the returned value is 1. | ||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||
* @param x the unsigned base. | ||||||||||||||||||||||||||||||||||||
* @param n the exponent. | ||||||||||||||||||||||||||||||||||||
* @return {@code x} raised to the power of {@code n}. | ||||||||||||||||||||||||||||||||||||
* @throws ArithmeticException when {@code n} is negative, | ||||||||||||||||||||||||||||||||||||
* or when the result overflows an unsigned long. | ||||||||||||||||||||||||||||||||||||
* @since 25 | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
public static long unsignedPowExact(long x, int n) { | ||||||||||||||||||||||||||||||||||||
if (n < 0) { | ||||||||||||||||||||||||||||||||||||
throw new ArithmeticException("negative exponent"); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (n == 0) { | ||||||||||||||||||||||||||||||||||||
return 1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||||||||
* To keep the code as simple as possible, there are intentionally | ||||||||||||||||||||||||||||||||||||
* no fast paths, except for |x| <= 1. | ||||||||||||||||||||||||||||||||||||
* The reason is that the number of loop iterations below can be kept | ||||||||||||||||||||||||||||||||||||
* very small when |x| > 1, but not necessarily when |x| <= 1. | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
if (x == 0 || x == 1) { | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||
return x; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
With also a check for the condition There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think there's a quick, precise pre-check that would ensure that the loop can just use simple, unchecked Consider IMO, you still need checked multiplications in the loop. (Besides, the product in your checks can overflow, so you would have to add a guard.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Thus, there remain only the cases when Moreover, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @fabioromano1 Well, there are two checks. In one the product can overflow, you'd need to convert one of the operands to Anyway, since the pre-checks are not precise, that would lead to an implementation with a loop with checked, and another one with unchecked multiplications. I don't think this buys you anything. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It serves to skip the checks in the loop if in the common cases the length of the results are way more little with respect to
If the condition at point 1 is evaluated only if the condition at point 2 is false, then it can never overflow. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If that check would be a couple of instructions or so, then I could agree. True, there are no overflows in the checks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rgiulietti If you think that these checks might be useful, the choice is yours. |
||||||||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||||||||
* Let x0 and n0 > 0 be the entry values of x and n, resp. | ||||||||||||||||||||||||||||||||||||
* The useful loop invariants are: | ||||||||||||||||||||||||||||||||||||
* p * x^n = x0^n0 | ||||||||||||||||||||||||||||||||||||
* |p| < |x| | ||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||
* Since |x0| >= 2 here, and since |x0|^(2^6) >= 2^Long.SIZE, the squaring | ||||||||||||||||||||||||||||||||||||
* of x in the loop overflows at latest during the 6th iteration, | ||||||||||||||||||||||||||||||||||||
* so by then the method throws. | ||||||||||||||||||||||||||||||||||||
* Thus, the loop executes at most 5 successful iterations, and fails | ||||||||||||||||||||||||||||||||||||
* not later than at the 6th. | ||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||
* But n is right-shifted at each iteration. | ||||||||||||||||||||||||||||||||||||
* If the method returns, there are thus floor(log2(n0)) iterations. | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
long p = 1; | ||||||||||||||||||||||||||||||||||||
while (n > 1) { | ||||||||||||||||||||||||||||||||||||
if ((n & 0b1) != 0) { | ||||||||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||||||||
* The invariant |p| < |x| holds, so we have |p*x| < |x*x|. | ||||||||||||||||||||||||||||||||||||
* That is, if p*x overflows, so does x*x below, which is | ||||||||||||||||||||||||||||||||||||
* always executed. | ||||||||||||||||||||||||||||||||||||
* In other words, a plain * can be used here, since we are | ||||||||||||||||||||||||||||||||||||
* piggybacking on the squaring of x to throw. | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
p *= x; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
x = unsignedMultiplyExact(x, x); | ||||||||||||||||||||||||||||||||||||
n >>>= 1; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
return unsignedMultiplyExact(p, x); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
} |
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.