JDK-8273090 : Add Math.ceilDiv() family parallel to Math.floorDiv() family
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.lang
  • Priority: P4
  • Status: Provisional
  • Resolution: Unresolved
  • Fix Versions: 18
  • Submitted: 2021-08-27
  • Updated: 2021-09-20
Related Reports
CSR :  
Relates :  
Relates :  
Description
Summary
-------

Add methods `ceilDiv()`, `ceilMod()` and `ceilDivExact()`, paralleling the corresponding `floorDiv()`, `floorMod()` and `floorDivExact` methods, to `java.lang.Math` and `java.lang.StrictMath`.


Problem
-------

The methods `floorDiv()` and `floorMod()` compute the integer quotient of their arguments and the corresponding remainder. They do so by applying floor rounding (rounding toward negative infinity) to the exact algebraic quotient. The are no methods to apply ceiling rounding instead (rounding toward positive infinity).

As an example, when determining how many blocks of size `n` are minimally needed to host `m` items, the computation behind the scenes is something akin to `ceilDiv(m, n)`. There are presumably many customized `ceilDiv()`-like computations in the code base, probably some of them incorrect at the extrema of the `int`/`long` ranges. An officially endorsed `ceilDiv()` family helps in minimizing errors in custom-made, ad-hoc solutions.

Solution
--------

Add methods `ceilDiv()`, `ceilMod()` and `ceilDivExact()`.


Specification
-------------

        --- a/src/java.base/share/classes/java/lang/Math.java
        +++ b/src/java.base/share/classes/java/lang/Math.java
        @@ -1088,13 +1088,13 @@ public final class Math {
        +    /**
        +     * Returns the smallest (closest to negative infinity)
        +     * {@code int} value that is greater than or equal to the algebraic quotient.
        +     * This method is identical to {@link #ceilDiv(int,int)} except that it
        +     * throws an {@code ArithmeticException} when the dividend is
        +     * {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and the divisor is
        +     * {@code -1} instead of ignoring the integer overflow and returning
        +     * {@code Integer.MIN_VALUE}.
        +     * <p>
        +     * The ceil modulus method {@link #ceilMod(int,int)} is a suitable
        +     * counterpart both for this method and for the {@link #ceilDiv(int,int)}
        +     * method.
        +     * <p>
        +     * For examples, see {@link #ceilDiv(int, int)}.
        +     *
        +     * @param x the dividend
        +     * @param y the divisor
        +     * @return the smallest (closest to negative infinity)
        +     * {@code int} value that is greater 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 #ceilDiv(int, int)
        +     * @since 18
        +     */
        +    public static int ceilDivExact(int x, int y) {
        +
        +    /**
        +     * Returns the smallest (closest to negative infinity)
        +     * {@code long} value that is greater than or equal to the algebraic quotient.
        +     * This method is identical to {@link #ceilDiv(long,long)} except that it
        +     * throws an {@code ArithmeticException} when the dividend is
        +     * {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is
        +     * {@code -1} instead of ignoring the integer overflow and returning
        +     * {@code Long.MIN_VALUE}.
        +     * <p>
        +     * The ceil modulus method {@link #ceilMod(long,long)} is a suitable
        +     * counterpart both for this method and for the {@link #ceilDiv(long,long)}
        +     * method.
        +     * <p>
        +     * For examples, see {@link #ceilDiv(int, int)}.
        +     *
        +     * @param x the dividend
        +     * @param y the divisor
        +     * @return the smallest (closest to negative infinity)
        +     * {@code long} value that is greater 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 #ceilDiv(long,long)
        +     * @since 18
        +     */
        +    public static long ceilDivExact(long x, long y) {
        
        @@ -1361,12 +1435,12 @@ public final class Math {
        @@ -1530,12 +1604,226 @@ public final class Math {
        +    /**
        +     * Returns the smallest (closest to negative infinity)
        +     * {@code int} value that is greater than or equal to the algebraic quotient.
        +     * 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}.
        +     * <p>
        +     * Normal integer division operates under the round to zero rounding mode
        +     * (truncation).  This operation instead acts under the round toward
        +     * positive infinity (ceiling) rounding mode.
        +     * The ceiling rounding mode gives different results from truncation
        +     * when the exact quotient is not an integer and is positive.
        +     * <ul>
        +     *   <li>If the signs of the arguments are different, the results of
        +     *       {@code ceilDiv} and the {@code /} operator are the same.  <br>
        +     *       For example, {@code ceilDiv(-4, 3) == -1} and {@code (-4 / 3) == -1}.</li>
        +     *   <li>If the signs of the arguments are the same, {@code ceilDiv}
        +     *       returns the smallest integer greater than or equal to the quotient
        +     *       while the {@code /} operator returns the largest integer less
        +     *       than or equal to the quotient.
        +     *       They differ if and only if the quotient is not an integer.<br>
        +     *       For example, {@code ceilDiv(4, 3) == 2},
        +     *       whereas {@code (4 / 3) == 1}.
        +     *   </li>
        +     * </ul>
        +     *
        +     * @param x the dividend
        +     * @param y the divisor
        +     * @return the smallest (closest to negative infinity)
        +     * {@code int} value that is greater than or equal to the algebraic quotient.
        +     * @throws ArithmeticException if the divisor {@code y} is zero
        +     * @see #ceilMod(int, int)
        +     * @see #ceil(double)
        +     * @since 18
        +     */
        +    public static int ceilDiv(int x, int y) {
        +
        +    /**
        +     * Returns the smallest (closest to negative infinity)
        +     * {@code long} value that is greater than or equal to the algebraic quotient.
        +     * 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}.
        +     * <p>
        +     * Normal integer division operates under the round to zero rounding mode
        +     * (truncation).  This operation instead acts under the round toward
        +     * positive infinity (ceiling) rounding mode.
        +     * The ceiling rounding mode gives different results from truncation
        +     * when the exact result is not an integer and is positive.
        +     * <p>
        +     * For examples, see {@link #ceilDiv(int, int)}.
        +     *
        +     * @param x the dividend
        +     * @param y the divisor
        +     * @return the smallest (closest to negative infinity)
        +     * {@code long} value that is greater than or equal to the algebraic quotient.
        +     * @throws ArithmeticException if the divisor {@code y} is zero
        +     * @see #ceilMod(int, int)
        +     * @see #ceil(double)
        +     * @since 18
        +     */
        +    public static long ceilDiv(long x, int y) {
        +
        +    /**
        +     * Returns the smallest (closest to negative infinity)
        +     * {@code long} value that is greater than or equal to the algebraic quotient.
        +     * 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}.
        +     * <p>
        +     * Normal integer division operates under the round to zero rounding mode
        +     * (truncation).  This operation instead acts under the round toward
        +     * positive infinity (ceiling) rounding mode.
        +     * The ceiling rounding mode gives different results from truncation
        +     * when the exact result is not an integer and is positive.
        +     * <p>
        +     * For examples, see {@link #ceilDiv(int, int)}.
        +     *
        +     * @param x the dividend
        +     * @param y the divisor
        +     * @return the smallest (closest to negative infinity)
        +     * {@code long} value that is greater than or equal to the algebraic quotient.
        +     * @throws ArithmeticException if the divisor {@code y} is zero
        +     * @see #ceilMod(int, int)
        +     * @see #ceil(double)
        +     * @since 18
        +     */
        +    public static long ceilDiv(long x, long y) {
        +
        +    /**
        +     * Returns the ceiling modulus of the {@code int} arguments.
        +     * <p>
        +     * The ceiling modulus is {@code r = x - (ceilDiv(x, y) * y)},
        +     * has the opposite sign as the divisor {@code y} or is zero, and
        +     * is in the range of {@code -abs(y) < r < +abs(y)}.
        +     *
        +     * <p>
        +     * The relationship between {@code ceilDiv} and {@code ceilMod} is such that:
        +     * <ul>
        +     *   <li>{@code ceilDiv(x, y) * y + ceilMod(x, y) == x}</li>
        +     * </ul>
        +     * <p>
        +     * The difference in values between {@code ceilMod} and the {@code %} operator
        +     * is due to the difference between {@code ceilDiv} and the {@code /}
        +     * operator, as detailed in {@linkplain #ceilDiv(int, int)}.
        +     * <p>
        +     * Examples:
        +     * <ul>
        +     *   <li>Regardless of the signs of the arguments, {@code ceilMod}(x, y)
        +     *       is zero exactly when {@code x % y} is zero as well.</li>
        +     *   <li>If neither {@code ceilMod}(x, y) nor {@code x % y} is zero,
        +     *       they differ exactly when the signs of the arguments are the same.<br>
        +     *       <ul>
        +     *       <li>{@code ceilMod(+4, +3) == -2}; &nbsp; and {@code (+4 % +3) == +1}</li>
        +     *       <li>{@code ceilMod(-4, -3) == +2}; &nbsp; and {@code (-4 % -3) == -1}</li>
        +     *       <li>{@code ceilMod(+4, -3) == +1}; &nbsp; and {@code (+4 % -3) == +1}</li>
        +     *       <li>{@code ceilMod(-4, +3) == -1}; &nbsp; and {@code (-4 % +3) == -1}</li>
        +     *       </ul>
        +     *   </li>
        +     * </ul>
        +     *
        +     * @param x the dividend
        +     * @param y the divisor
        +     * @return the ceiling modulus {@code x - (ceilDiv(x, y) * y)}
        +     * @throws ArithmeticException if the divisor {@code y} is zero
        +     * @see #ceilDiv(int, int)
        +     * @since 18
        +     */
        +    public static int ceilMod(int x, int y) {
        +
        +    /**
        +     * Returns the ceiling modulus of the {@code long} and {@code int} arguments.
        +     * <p>
        +     * The ceiling modulus is {@code r = x - (ceilDiv(x, y) * y)},
        +     * has the opposite sign as the divisor {@code y} or is zero, and
        +     * is in the range of {@code -abs(y) < r < +abs(y)}.
        +     *
        +     * <p>
        +     * The relationship between {@code ceilDiv} and {@code ceilMod} is such that:
        +     * <ul>
        +     *   <li>{@code ceilDiv(x, y) * y + ceilMod(x, y) == x}</li>
        +     * </ul>
        +     * <p>
        +     * For examples, see {@link #ceilMod(int, int)}.
        +     *
        +     * @param x the dividend
        +     * @param y the divisor
        +     * @return the ceiling modulus {@code x - (ceilDiv(x, y) * y)}
        +     * @throws ArithmeticException if the divisor {@code y} is zero
        +     * @see #ceilDiv(long, int)
        +     * @since 18
        +     */
        +    public static int ceilMod(long x, int y) {
        +
        +    /**
        +     * Returns the ceiling modulus of the {@code long} arguments.
        +     * <p>
        +     * The ceiling modulus is {@code r = x - (ceilDiv(x, y) * y)},
        +     * has the opposite sign as the divisor {@code y} or is zero, and
        +     * is in the range of {@code -abs(y) < r < +abs(y)}.
        +     *
        +     * <p>
        +     * The relationship between {@code ceilDiv} and {@code ceilMod} is such that:
        +     * <ul>
        +     *   <li>{@code ceilDiv(x, y) * y + ceilMod(x, y) == x}</li>
        +     * </ul>
        +     * <p>
        +     * For examples, see {@link #ceilMod(int, int)}.
        +     *
        +     * @param x the dividend
        +     * @param y the divisor
        +     * @return the ceiling modulus {@code x - (ceilDiv(x, y) * y)}
        +     * @throws ArithmeticException if the divisor {@code y} is zero
        +     * @see #ceilDiv(long, long)
        +     * @since 18
        +     */
        +    public static long ceilMod(long x, long y) {
    
    --- a/src/java.base/share/classes/java/lang/StrictMath.java
    +++ b/src/java.base/share/classes/java/lang/StrictMath.java
    @@ -967,6 +967,66 @@ public final class StrictMath {
    +    /**
    +     * Returns the smallest (closest to negative infinity)
    +     * {@code int} value that is greater than or equal to the algebraic quotient.
    +     * This method is identical to {@link #ceilDiv(int,int)} except that it
    +     * throws an {@code ArithmeticException} when the dividend is
    +     * {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and the divisor is
    +     * {@code -1} instead of ignoring the integer overflow and returning
    +     * {@code Integer.MIN_VALUE}.
    +     * <p>
    +     * The ceil modulus method {@link #ceilMod(int,int)} is a suitable
    +     * counterpart both for this method and for the {@link #ceilDiv(int,int)}
    +     * method.
    +     * <p>
    +     * See {@link Math#ceilDiv(int, int) Math.ceilDiv} for examples and
    +     * a comparison to the integer division {@code /} operator.
    +     *
    +     * @param x the dividend
    +     * @param y the divisor
    +     * @return the smallest (closest to negative infinity)
    +     * {@code int} value that is greater 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 Math#ceilDiv(int, int)
    +     * @since 18
    +     */
    +    public static int ceilDivExact(int x, int y) {
    +
    +    /**
    +     * Returns the smallest (closest to negative infinity)
    +     * {@code long} value that is greater than or equal to the algebraic quotient.
    +     * This method is identical to {@link #ceilDiv(long,long)} except that it
    +     * throws an {@code ArithmeticException} when the dividend is
    +     * {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is
    +     * {@code -1} instead of ignoring the integer overflow and returning
    +     * {@code Long.MIN_VALUE}.
    +     * <p>
    +     * The ceil modulus method {@link #ceilMod(long,long)} is a suitable
    +     * counterpart both for this method and for the {@link #ceilDiv(long,long)}
    +     * method.
    +     * <p>
    +     * For examples, see {@link Math#ceilDiv(int, int) Math.ceilDiv}.
    +     *
    +     * @param x the dividend
    +     * @param y the divisor
    +     * @return the smallest (closest to negative infinity)
    +     * {@code long} value that is greater 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 Math#ceilDiv(int, int)
    +     * @see Math#ceilDiv(long,long)
    +     * @since 18
    +     */
    +    public static long ceilDivExact(long x, long y) {
    +
    +    /**
    +     * Returns the smallest (closest to negative infinity)
    +     * {@code int} value that is greater than or equal to the algebraic quotient.
    +     * 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}.
    +     * <p>
    +     * See {@link Math#ceilDiv(int, int) Math.ceilDiv} for examples and
    +     * a comparison to the integer division {@code /} operator.
    +     *
    +     * @param x the dividend
    +     * @param y the divisor
    +     * @return the smallest (closest to negative infinity)
    +     * {@code int} value that is greater than or equal to the algebraic quotient.
    +     * @throws ArithmeticException if the divisor {@code y} is zero
    +     * @see Math#ceilDiv(int, int)
    +     * @see Math#ceil(double)
    +     * @since 18
    +     */
    +    public static int ceilDiv(int x, int y) {
    +
    +    /**
    +     * Returns the smallest (closest to negative infinity)
    +     * {@code long} value that is greater than or equal to the algebraic quotient.
    +     * 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}.
    +     * <p>
    +     * See {@link Math#ceilDiv(int, int) Math.ceilDiv} for examples and
    +     * a comparison to the integer division {@code /} operator.
    +     *
    +     * @param x the dividend
    +     * @param y the divisor
    +     * @return the smallest (closest to negative infinity)
    +     * {@code long} value that is greater than or equal to the algebraic quotient.
    +     * @throws ArithmeticException if the divisor {@code y} is zero
    +     * @see Math#ceilDiv(long, int)
    +     * @see Math#ceil(double)
    +     * @since 18
    +     */
    +    public static long ceilDiv(long x, int y) {
    +
    +    /**
    +     * Returns the smallest (closest to negative infinity)
    +     * {@code long} value that is greater than or equal to the algebraic quotient.
    +     * 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}.
    +     * <p>
    +     * See {@link Math#ceilDiv(int, int) Math.ceilDiv} for examples and
    +     * a comparison to the integer division {@code /} operator.
    +     *
    +     * @param x the dividend
    +     * @param y the divisor
    +     * @return the smallest (closest to negative infinity)
    +     * {@code long} value that is greater than or equal to the algebraic quotient.
    +     * @throws ArithmeticException if the divisor {@code y} is zero
    +     * @see Math#ceilDiv(long, long)
    +     * @see Math#ceil(double)
    +     * @since 18
    +     */
    +    public static long ceilDiv(long x, long y) {
    +
    +    /**
    +     * Returns the ceiling modulus of the {@code int} arguments.
    +     * <p>
    +     * The ceiling modulus is {@code r = x - (ceilDiv(x, y) * y)},
    +     * has the opposite sign as the divisor {@code y} or is zero, and
    +     * is in the range of {@code -abs(y) < r < +abs(y)}.
    +     *
    +     * <p>
    +     * The relationship between {@code ceilDiv} and {@code ceilMod} is such that:
    +     * <ul>
    +     *   <li>{@code ceilDiv(x, y) * y + ceilMod(x, y) == x}</li>
    +     * </ul>
    +     * <p>
    +     * See {@link Math#ceilMod(int, int) Math.ceilMod} for examples and
    +     * a comparison to the {@code %} operator.
    +     *
    +     * @param x the dividend
    +     * @param y the divisor
    +     * @return the ceiling modulus {@code x - (ceilDiv(x, y) * y)}
    +     * @throws ArithmeticException if the divisor {@code y} is zero
    +     * @see Math#ceilMod(int, int)
    +     * @see StrictMath#ceilDiv(int, int)
    +     * @since 18
    +     */
    +    public static int ceilMod(int x, int y) {
    +
    +    /**
    +     * Returns the ceiling modulus of the {@code long} and {@code int} arguments.
    +     * <p>
    +     * The ceiling modulus is {@code r = x - (ceilDiv(x, y) * y)},
    +     * has the opposite sign as the divisor {@code y} or is zero, and
    +     * is in the range of {@code -abs(y) < r < +abs(y)}.
    +     *
    +     * <p>
    +     * The relationship between {@code ceilDiv} and {@code ceilMod} is such that:
    +     * <ul>
    +     *   <li>{@code ceilDiv(x, y) * y + ceilMod(x, y) == x}</li>
    +     * </ul>
    +     * <p>
    +     * See {@link Math#ceilMod(int, int) Math.ceilMod} for examples and
    +     * a comparison to the {@code %} operator.
    +     *
    +     * @param x the dividend
    +     * @param y the divisor
    +     * @return the ceiling modulus {@code x - (ceilDiv(x, y) * y)}
    +     * @throws ArithmeticException if the divisor {@code y} is zero
    +     * @see Math#ceilMod(long, int)
    +     * @see StrictMath#ceilDiv(long, int)
    +     * @since 18
    +     */
    +    public static int ceilMod(long x, int y) {
    +
    +    /**
    +     * Returns the ceiling modulus of the {@code long} arguments.
    +     * <p>
    +     * The ceiling modulus is {@code r = x - (ceilDiv(x, y) * y)},
    +     * has the opposite sign as the divisor {@code y} or is zero, and
    +     * is in the range of {@code -abs(y) < r < +abs(y)}.
    +     *
    +     * <p>
    +     * The relationship between {@code ceilDiv} and {@code ceilMod} is such that:
    +     * <ul>
    +     *   <li>{@code ceilDiv(x, y) * y + ceilMod(x, y) == x}</li>
    +     * </ul>
    +     * <p>
    +     * See {@link Math#ceilMod(int, int) Math.ceilMod} for examples and
    +     * a comparison to the {@code %} operator.
    +     *
    +     * @param x the dividend
    +     * @param y the divisor
    +     * @return the ceiling modulus {@code x - (ceilDiv(x, y) * y)}
    +     * @throws ArithmeticException if the divisor {@code y} is zero
    +     * @see Math#ceilMod(long, long)
    +     * @see StrictMath#ceilDiv(long, long)
    +     * @since 18
    +     */
    +    public static long ceilMod(long x, long y) {


Comments
Joe, if there are no more comments I would like to switch the issue status back to Finalized. Anything I can otherwise correct or ameliorate?
20-09-2021

Mmmh, yours looks like the definition of *floor(x)*: the greatest integer value `n` less than or equals to x `n <= x < n + 1` Or am I missing something?
14-09-2021

Moving to Provisional, not Approved. I have a wording suggestion to offer before the request is re-Finalized. As phrased, the specifications are correct: + * Returns the smallest (closest to negative infinity) + * {@code int} value that is greater than or equal to the algebraic quotient. ... + public static int ceilDivExact(int x, int y) { However, I think most readers would expect a *ceil* method to return "the greatest value less or equals to the algebraic quotient", or rather most readers would would have the expectations met sooner if phrased this way. If this rewording to done, the existing floor{Div, Mod}Foo methods should get the corresponding updates for consistency. What do you think?
14-09-2021