RFR: 8355992: Add unsignedMultiplyExact and *powExact methods to Math and StrictMath [v2]

fabioromano1 duke at openjdk.org
Fri May 2 16:10:51 UTC 2025


On Fri, 2 May 2025 15:12:01 GMT, Raffaello Giulietti <rgiulietti at openjdk.org> wrote:

>> Add `powExact()` and `unsignedPowExact()` methods that operate on integer values arguments.
>> Further, add `unsignedMultiplyExact` methods as well.
>
> Raffaello Giulietti has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Clearer and more complete spec of the *pow* methods.

Some easy optimizations for special cases.

src/java.base/share/classes/java/lang/Math.java line 3494:

> 3492:             return 1;
> 3493:         }
> 3494:         if (x == 0 || x == 1) {

Suggestion:

        if (x == 0 || x == 1 || n == 1) {

src/java.base/share/classes/java/lang/Math.java line 3500:

> 3498:             return (n & 0b1) == 0 ? 1 : -1;
> 3499:         }
> 3500: 

Suggestion:


        if (x == 2) {
            if (n >= Integer.SIZE - 1)
                throw new ArithmeticException("integer overflow");
            return 1 << n;
        }
        if (x == -2) {
            if (n >= Integer.SIZE)
                throw new ArithmeticException("integer overflow");
            // if n == Integer.SIZE - 1, result is correct
            return (n & 0b1) == 0 ? 1 << n : -(1 << n);
        }

       if ((java.math.BigInteger.bitLengthForInt(Math.abs(x)) - 1L) * n + 1L > Integer.SIZE) {
           throw new ArithmeticException("integer overflow");
       }

With also a check for the condition `java.math.BigInteger.bitLengthForInt(Math.abs(x)) * n < Integer.SIZE`, when it is true the path could be led to a loop that skips the checks.

src/java.base/share/classes/java/lang/Math.java line 3532:

> 3530:             return 1;
> 3531:         }
> 3532:         if (x == 0 || x == 1) {

Suggestion:

        if (x == 0 || x == 1 || n == 1) {

src/java.base/share/classes/java/lang/Math.java line 3535:

> 3533:             return x;
> 3534:         }
> 3535: 

Suggestion:


        if (x == 2) {
            if (n >= Integer.SIZE)
                throw new ArithmeticException("unsigned integer overflow");
            return 1 << n;
        }

       if ((java.math.BigInteger.bitLengthForInt(x) - 1L) * n + 1L > Integer.SIZE) {
           throw new ArithmeticException("unsigned integer overflow");
       }

With also a check for the condition `java.math.BigInteger.bitLengthForInt(x) * n <= Integer.SIZE`, when it is true the path could be led to a loop that skips the checks.

src/java.base/share/classes/java/lang/Math.java line 3567:

> 3565:             return 1;
> 3566:         }
> 3567:         if (x == 0 || x == 1) {

Suggestion:

        if (x == 0 || x == 1 || n == 1) {

src/java.base/share/classes/java/lang/Math.java line 3573:

> 3571:             return (n & 0b1) != 0 ? -1 : 1;
> 3572:         }
> 3573: 

Suggestion:


        if (x == 2) {
            if (n >= Long.SIZE - 1)
                throw new ArithmeticException("long overflow");
            return 1L << n;
        }
        if (x == -2) {
            if (n >= Long.SIZE)
                throw new ArithmeticException("long overflow");
            // if n == Long.SIZE - 1, result is correct
            return (n & 0b1) == 0 ? 1L << n : -(1L << n);
        }

       if ((java.math.BigInteger.bitLengthForLong(Math.abs(x)) - 1L) * n + 1L > Long.SIZE) {
           throw new ArithmeticException("long overflow");
       }

With also a check for the condition `java.math.BigInteger.bitLengthForLong(Math.abs(x)) * n < Long.SIZE`, when it is true the path could be led to a loop that skips the checks.

src/java.base/share/classes/java/lang/Math.java line 3610:

> 3608:          * very small when |x| > 1, but not necessarily when |x| <= 1.
> 3609:          */
> 3610:         if (x == 0 || x == 1) {

Suggestion:

        if (x == 0 || x == 1 || n == 1) {

src/java.base/share/classes/java/lang/Math.java line 3613:

> 3611:             return x;
> 3612:         }
> 3613: 

Suggestion:


        if (x == 2) {
            if (n >= Long.SIZE)
                throw new ArithmeticException("unsigned long overflow");
            return 1L << n;
        }

       if ((java.math.BigInteger.bitLengthForLong(x) - 1L) * n + 1L > Long.SIZE) {
           throw new ArithmeticException("unsigned long overflow");
       }

With also a check for the condition `java.math.BigInteger.bitLengthForLong(x) * n <= Long.SIZE`, when it is true the path could be led to a loop that skips the checks.

-------------

PR Review: https://git.openjdk.org/jdk/pull/25003#pullrequestreview-2812357251
PR Review Comment: https://git.openjdk.org/jdk/pull/25003#discussion_r2071832231
PR Review Comment: https://git.openjdk.org/jdk/pull/25003#discussion_r2071832373
PR Review Comment: https://git.openjdk.org/jdk/pull/25003#discussion_r2071833435
PR Review Comment: https://git.openjdk.org/jdk/pull/25003#discussion_r2071833501
PR Review Comment: https://git.openjdk.org/jdk/pull/25003#discussion_r2071838381
PR Review Comment: https://git.openjdk.org/jdk/pull/25003#discussion_r2071833854
PR Review Comment: https://git.openjdk.org/jdk/pull/25003#discussion_r2071816617
PR Review Comment: https://git.openjdk.org/jdk/pull/25003#discussion_r2071837334


More information about the core-libs-dev mailing list