Skip to content
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

8271225: Add floorDivExact() method to java.lang.[Strict]Math #4941

Closed
wants to merge 5 commits into from
Closed
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 100 additions & 3 deletions src/java.base/share/classes/java/lang/Math.java
Original file line number Diff line number Diff line change
@@ -1012,6 +1012,9 @@ public static long multiplyExact(long x, long y) {
* <p>
* If {@code y} is zero, an {@code ArithmeticException} is thrown
* (JLS {@jls 15.17.2}).
* <p>
* The built-in remainder operator "{@code %}" is a suitable counterpart
* both for this method and for the built-in division operator "{@code /}".
*
* @param x the dividend
* @param y the divisor
@@ -1039,6 +1042,9 @@ public static int divideExact(int x, int y) {
* <p>
* If {@code y} is zero, an {@code ArithmeticException} is thrown
* (JLS {@jls 15.17.2}).
* <p>
* The built-in remainder operator "{@code %}" is a suitable counterpart
* both for this method and for the built-in division operator "{@code /}".
*
* @param x the dividend
* @param y the divisor
@@ -1056,6 +1062,97 @@ public static long divideExact(long x, long y) {
throw new ArithmeticException("long overflow");
}

/**
* Returns the largest (closest to positive infinity)
* {@code int} value that is less than or equal to the algebraic quotient.
* If the dividend is {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and
* the divisor is {@code -1}, then integer overflow occurs and an
* {@code ArithmeticException} is thrown.
* <p>
* Normal integer division operates under the round to zero rounding mode
* (truncation). This operation instead acts under the round toward
* negative infinity (floor) rounding mode.
* The floor rounding mode gives different results from truncation
* when the exact result is negative.
* <ul>
* <li>If the signs of the arguments are the same, the results of
* {@code floorDiv} and the {@code /} operator are the same. <br>
* For example, {@code floorDiv(4, 3) == 1} and {@code (4 / 3) == 1}.</li>
* <li>If the signs of the arguments are different, the quotient is negative and
* {@code floorDiv} returns the integer less than or equal to the quotient
* and the {@code /} operator returns the integer closest to zero.<br>
* For example, {@code floorDiv(-4, 3) == -2},
* whereas {@code (-4 / 3) == -1}.
* </li>
* </ul>
* <p>
* The floor modulus method {@link #floorMod(int,int)} is a suitable
* counterpart both for this method and for the {@link #floorDiv(int,int)}
* method.
*
* @param x the dividend
* @param y the divisor
* @return the largest (closest to positive infinity)
* {@code int} value that is less than or equal to the algebraic quotient.
* @throws ArithmeticException if the divisor {@code y} is zero, or the
* dividend {@code x} is {@code Integer.MIN_VALUE} and the divisor {@code y}
* is {@code -1}.
* @see #floorDiv(int, int)
* @since 18
*/
public static int floorDivExact(int x, int y) {
int r = x / y;
if ((x & y & r) >= 0) {
// if the signs are different and modulo not zero, round down
if ((x ^ y) < 0 && (r * y != x)) {
r--;
}
return r;
}
throw new ArithmeticException("integer overflow");
}

/**
* Returns the largest (closest to positive infinity)
* {@code long} value that is less than or equal to the algebraic quotient.
* If the dividend is {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the
* divisor is {@code -1}, then integer overflow occurs and an
* {@code ArithmeticException} is thrown.
* <p>
* Normal integer division operates under the round to zero rounding mode
* (truncation). This operation instead acts under the round toward
* negative infinity (floor) rounding mode.
* The floor rounding mode gives different results from truncation
* when the exact result is negative.
* <p>
* For examples, see {@link #floorDiv(int, int)}.
* <p>
* The floor modulus method {@link #floorMod(long,long)} is a suitable
* counterpart both for this method and for the {@link #floorDiv(long,long)}
* method.
*
* @param x the dividend
* @param y the divisor
* @return the largest (closest to positive infinity)
* {@code long} value that is less than or equal to the algebraic quotient.
* @throws ArithmeticException if the divisor {@code y} is zero, or the
* dividend {@code x} is {@code Long.MIN_VALUE} and the divisor {@code y}
* is {@code -1}.
* @see #floorDiv(long, long)
* @since 18
*/
public static long floorDivExact(long x, long y) {
long r = x / y;
if ((x & y & r) >= 0) {
// if the signs are different and modulo not zero, round down
if ((x ^ y) < 0 && (r * y != x)) {
r--;
}
return r;
}
throw new ArithmeticException("long overflow");
}

/**
* Returns the argument incremented by one, throwing an exception if the
* result overflows an {@code int}.
@@ -1247,7 +1344,7 @@ public static long unsignedMultiplyHigh(long x, long y) {
/**
* Returns the largest (closest to positive infinity)
* {@code int} value that is less than or equal to the algebraic quotient.
* There is one special case, if the dividend is the
* There is one special case, if the dividend is
* {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and the divisor is {@code -1},
* then integer overflow occurs and
* the result is equal to {@code Integer.MIN_VALUE}.
@@ -1290,7 +1387,7 @@ public static int floorDiv(int x, int y) {
/**
* Returns the largest (closest to positive infinity)
* {@code long} value that is less than or equal to the algebraic quotient.
* There is one special case, if the dividend is the
* There is one special case, if the dividend is
* {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is {@code -1},
* then integer overflow occurs and
* the result is equal to {@code Long.MIN_VALUE}.
@@ -1319,7 +1416,7 @@ public static long floorDiv(long x, int y) {
/**
* Returns the largest (closest to positive infinity)
* {@code long} value that is less than or equal to the algebraic quotient.
* There is one special case, if the dividend is the
* There is one special case, if the dividend is
* {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is {@code -1},
* then integer overflow occurs and
* the result is equal to {@code Long.MIN_VALUE}.
89 changes: 86 additions & 3 deletions src/java.base/share/classes/java/lang/StrictMath.java
Original file line number Diff line number Diff line change
@@ -863,6 +863,9 @@ public static long multiplyExact(long x, long y) {
* <p>
* If {@code y} is zero, an {@code ArithmeticException} is thrown
* (JLS {@jls 15.17.2}).
* <p>
* The built-in remainder operator "{@code %}" is a suitable counterpart
* both for this method and for the built-in division operator "{@code /}".
*
* @param x the dividend
* @param y the divisor
@@ -887,6 +890,9 @@ public static int divideExact(int x, int y) {
* <p>
* If {@code y} is zero, an {@code ArithmeticException} is thrown
* (JLS {@jls 15.17.2}).
* <p>
* The built-in remainder operator "{@code %}" is a suitable counterpart
* both for this method and for the built-in division operator "{@code /}".
*
* @param x the dividend
* @param y the divisor
@@ -901,6 +907,83 @@ public static long divideExact(long x, long y) {
return Math.divideExact(x, y);
}

/**
* Returns the largest (closest to positive infinity)
* {@code int} value that is less than or equal to the algebraic quotient.
* If the dividend is {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and
* the divisor is {@code -1}, then integer overflow occurs and an
* {@code ArithmeticException} is thrown.
* <p>
* Normal integer division operates under the round to zero rounding mode
* (truncation). This operation instead acts under the round toward
* negative infinity (floor) rounding mode.
* The floor rounding mode gives different results from truncation
* when the exact result is negative.
* <ul>
* <li>If the signs of the arguments are the same, the results of
* {@code floorDiv} and the {@code /} operator are the same. <br>
* For example, {@code floorDiv(4, 3) == 1} and {@code (4 / 3) == 1}.</li>
* <li>If the signs of the arguments are different, the quotient is negative and
* {@code floorDiv} returns the integer less than or equal to the quotient
* and the {@code /} operator returns the integer closest to zero.<br>
* For example, {@code floorDiv(-4, 3) == -2},
* whereas {@code (-4 / 3) == -1}.
* </li>
* </ul>
* <p>
* The floor modulus method {@link #floorMod(int,int)} is a suitable
* counterpart both for this method and for the {@link #floorDiv(int,int)}
* method.
*
* @param x the dividend
* @param y the divisor
* @return the largest (closest to positive infinity)
* {@code int} value that is less than or equal to the algebraic quotient.
* @throws ArithmeticException if the divisor {@code y} is zero, or the
* dividend {@code x} is {@code Integer.MIN_VALUE} and the divisor {@code y}
* is {@code -1}.
* @see #floorDiv(int, int)
* @see Math#floorDiv(int, int)
* @since 18
*/
public static int floorDivExact(int x, int y) {
return Math.floorDivExact(x, y);
}

/**
* Returns the largest (closest to positive infinity)
* {@code long} value that is less than or equal to the algebraic quotient.
* If the dividend is {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the
* divisor is {@code -1}, then integer overflow occurs and an
* {@code ArithmeticException} is thrown.
* <p>
* Normal integer division operates under the round to zero rounding mode
* (truncation). This operation instead acts under the round toward
* negative infinity (floor) rounding mode.
* The floor rounding mode gives different results from truncation
* when the exact result is negative.
* <p>
* For examples, see {@link #floorDiv(int, int)}.
* <p>
* The floor modulus method {@link #floorMod(long,long)} is a suitable
* counterpart both for this method and for the {@link #floorDiv(long,long)}
* method.
*
* @param x the dividend
* @param y the divisor
* @return the largest (closest to positive infinity)
* {@code long} value that is less than or equal to the algebraic quotient.
* @throws ArithmeticException if the divisor {@code y} is zero, or the
* dividend {@code x} is {@code Long.MIN_VALUE} and the divisor {@code y}
* is {@code -1}.
* @see #floorDiv(long, long)
* @see Math#floorDiv(long, long)
* @since 18
*/
public static long floorDivExact(long x, long y) {
return Math.floorDivExact(x, y);
}

/**
* Returns the argument incremented by one,
* throwing an exception if the result overflows an {@code int}.
@@ -1051,7 +1134,7 @@ public static long unsignedMultiplyHigh(long x, long y) {
/**
* Returns the largest (closest to positive infinity)
* {@code int} value that is less than or equal to the algebraic quotient.
* There is one special case, if the dividend is the
* There is one special case, if the dividend is
* {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and the divisor is {@code -1},
* then integer overflow occurs and
* the result is equal to the {@code Integer.MIN_VALUE}.
@@ -1075,7 +1158,7 @@ public static int floorDiv(int x, int y) {
/**
* Returns the largest (closest to positive infinity)
* {@code long} value that is less than or equal to the algebraic quotient.
* There is one special case, if the dividend is the
* There is one special case, if the dividend is
* {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is {@code -1},
* then integer overflow occurs and
* the result is equal to {@code Long.MIN_VALUE}.
@@ -1099,7 +1182,7 @@ public static long floorDiv(long x, int y) {
/**
* Returns the largest (closest to positive infinity)
* {@code long} value that is less than or equal to the algebraic quotient.
* There is one special case, if the dividend is the
* There is one special case, if the dividend is
* {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is {@code -1},
* then integer overflow occurs and
* the result is equal to the {@code Long.MIN_VALUE}.
62 changes: 59 additions & 3 deletions test/jdk/java/lang/Math/ExactArithTests.java
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ static void fail(String message) {

/**
* Test Math.addExact, multiplyExact, divideExact, subtractExact,
* incrementExact, decrementExact, negateExact methods with
* floorDivExact, incrementExact, decrementExact, negateExact methods with
* {@code int} arguments.
*/
static void testIntegerExact() {
@@ -166,6 +166,34 @@ static void testIntegerExact(int x, int y) {
}
}

exceptionExpected = false;
try {
// Test floorDivExact
int q = 0;
try {
q = Math.floorDiv(x, y);
} catch (ArithmeticException e) {
exceptionExpected = true;
}
if (!exceptionExpected && x == Integer.MIN_VALUE && y == -1) {
exceptionExpected = true;
}
int z = Math.floorDivExact(x, y);
if (exceptionExpected) {
fail("FAIL: int Math.floorDivExact(" + x + " / " + y + ")" +
"; expected ArithmeticException not thrown");
}
if (z != q) {
fail("FAIL: int Math.floorDivExact(" + x + " / " + y + ") = " +
z + "; expected: " + q);
}
} catch (ArithmeticException ex) {
if (!exceptionExpected) {
fail("FAIL: int Math.floorDivExact(" + x + " / " + y + ")" +
"; Unexpected exception: " + ex);
}
}

try {
// Test incrementExact
int inc = Math.incrementExact(x);
@@ -217,8 +245,8 @@ static void testIntegerExact(int x, int y) {

/**
* Test Math.addExact, multiplyExact, divideExact, subtractExact,
* incrementExact, decrementExact, negateExact, toIntExact methods
* with {@code long} arguments.
* floorDivExact, incrementExact, decrementExact, negateExact, toIntExact
* methods with {@code long} arguments.
*/
static void testLongExact() {
testLongExactTwice(0, 0);
@@ -324,6 +352,34 @@ static void testLongExact(long x, long y) {
}
}

boolean exceptionExpected = false;
try {
// Test floorDivExact
long q = 0;
try {
q = Math.floorDiv(x, y);
} catch (ArithmeticException e) {
exceptionExpected = true;
}
if (!exceptionExpected && x == Long.MIN_VALUE && y == -1) {
exceptionExpected = true;
}
long z = Math.floorDivExact(x, y);
if (exceptionExpected) {
fail("FAIL: long Math.floorDivExact(" + x + " / " + y + ")" +
"; expected ArithmeticException not thrown");
}
if (z != q) {
fail("FAIL: long Math.floorDivExact(" + x + " / " + y + ") = " +
z + "; expected: " + q);
}
} catch (ArithmeticException ex) {
if (!exceptionExpected) {
fail("FAIL: long Math.floorDivExact(" + x + " / " + y + ")" +
"; Unexpected exception: " + ex);
}
}

try {
// Test incrementExact
resultBig = xBig.add(BigInteger.ONE);