JDK-8271827 : Javadoc of floorDiv() and floorMod() families is inaccurate in some places
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.lang
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 18
  • Submitted: 2021-08-04
  • Updated: 2021-08-04
  • Resolved: 2021-08-04
Related Reports
CSR :  
Description
Summary
-------

Improve specifications of `Math.floorDiv()` and `Math.floorMod()` and their `StrictMath` siblings.

Problem
-------

Some of the specification verbiage is unclear or simply incorrect. For example there is the statement in the `floorDiv()` specification

    the / operator returns the integer closest to zero

when the integer closest to zero is zero itself.

Solution
--------

Revise the verbiage to be clear and correct.

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

    --- a/src/java.base/share/classes/java/lang/Math.java
    +++ b/src/java.base/share/classes/java/lang/Math.java
    @@ -1247,7 +1247,7 @@
         /**
          * 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}.
    @@ -1256,7 +1256,7 @@
          * (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.
    +     * when the exact quotient is not an integer and 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>
    @@ -1261,9 +1261,11 @@
          *   <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>
    +     *   <li>If the signs of the arguments are different, {@code floorDiv}
    +     *       returns the largest integer less than or equal to the quotient
    +     *       while the {@code /} operator returns the smallest integer greater
    +     *       than or equal to the quotient.
    +     *       They differ if and only if the quotient is not an integer.<br>
          *       For example, {@code floorDiv(-4, 3) == -2},
          *       whereas {@code (-4 / 3) == -1}.
          *   </li>
    @@ -1290,7 +1292,7 @@
         /**
          * 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}.
    @@ -1299,7 +1301,7 @@
          * (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.
    +     * when the exact result is not an integer and is negative.
          * <p>
          * For examples, see {@link #floorDiv(int, int)}.
          *
    @@ -1319,7 +1321,7 @@
         /**
          * 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}.
    @@ -1328,7 +1330,7 @@
          * (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.
    +     * when the exact result is not an integer and is negative.
          * <p>
          * For examples, see {@link #floorDiv(int, int)}.
          *
    @@ -1353,8 +1355,8 @@
         /**
          * Returns the floor modulus of the {@code int} arguments.
          * <p>
    -     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
    -     * has the same sign as the divisor {@code y}, and
    +     * The floor modulus is {@code r = x - (floorDiv(x, y) * y)},
    +     * has the same sign as the divisor {@code y} or is zero, and
          * is in the range of {@code -abs(y) < r < +abs(y)}.
          *
          * <p>
    @@ -1360,25 +1362,22 @@
          * <p>
          * The relationship between {@code floorDiv} and {@code floorMod} is such that:
          * <ul>
    -     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
    +     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}</li>
          * </ul>
          * <p>
    -     * The difference in values between {@code floorMod} and
    -     * the {@code %} operator is due to the difference between
    -     * {@code floorDiv} that returns the integer less than or equal to the quotient
    -     * and the {@code /} operator that returns the integer closest to zero.
    +     * The difference in values between {@code floorMod} and the {@code %} operator
    +     * is due to the difference between {@code floorDiv} and the {@code /}
    +     * operator, as detailed in {@linkplain #floorDiv(int, int)}.
          * <p>
          * Examples:
          * <ul>
    -     *   <li>If the signs of the arguments are the same, the results
    -     *       of {@code floorMod} and the {@code %} operator are the same.<br>
    +     *   <li>Regardless of the signs of the arguments, {@code floorMod}(x, y)
    +     *       is zero exactly when {@code x % y} is zero as well.</li>
    +     *   <li>If neither of {@code floorMod}(x, y) or {@code x % y} is zero,
    +     *       their results differ exactly when the signs of the arguments differ.<br>
          *       <ul>
          *       <li>{@code floorMod(+4, +3) == +1}; &nbsp; and {@code (+4 % +3) == +1}</li>
          *       <li>{@code floorMod(-4, -3) == -1}; &nbsp; and {@code (-4 % -3) == -1}</li>
    -     *       </ul>
    -     *   <li>If the signs of the arguments are different, the results
    -     *       differ from the {@code %} operator.<br>
    -     *       <ul>
          *       <li>{@code floorMod(+4, -3) == -2}; &nbsp; and {@code (+4 % -3) == +1}</li>
          *       <li>{@code floorMod(-4, +3) == +2}; &nbsp; and {@code (-4 % +3) == -1}</li>
          *       </ul>
    @@ -1385,8 +1384,6 @@
          *   </li>
          * </ul>
          * <p>
    -     * If the signs of arguments are unknown and a positive modulus
    -     * is needed it can be computed as {@code (floorMod(x, y) + abs(y)) % abs(y)}.
          *
          * @param x the dividend
          * @param y the divisor
    @@ -1407,8 +1404,8 @@
         /**
          * Returns the floor modulus of the {@code long} and {@code int} arguments.
          * <p>
    -     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
    -     * has the same sign as the divisor {@code y}, and
    +     * The floor modulus is {@code r = x - (floorDiv(x, y) * y)},
    +     * has the same sign as the divisor {@code y} or is zero, and
          * is in the range of {@code -abs(y) < r < +abs(y)}.
          *
          * <p>
    @@ -1414,7 +1411,7 @@
          * <p>
          * The relationship between {@code floorDiv} and {@code floorMod} is such that:
          * <ul>
    -     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
    +     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}</li>
          * </ul>
          * <p>
          * For examples, see {@link #floorMod(int, int)}.
    @@ -1434,8 +1431,8 @@
         /**
          * Returns the floor modulus of the {@code long} arguments.
          * <p>
    -     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
    -     * has the same sign as the divisor {@code y}, and
    +     * The floor modulus is {@code r = x - (floorDiv(x, y) * y)},
    +     * has the same sign as the divisor {@code y} or is zero, and
          * is in the range of {@code -abs(y) < r < +abs(y)}.
          *
          * <p>
    @@ -1441,7 +1438,7 @@
          * <p>
          * The relationship between {@code floorDiv} and {@code floorMod} is such that:
          * <ul>
    -     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
    +     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}</li>
          * </ul>
          * <p>
          * For examples, see {@link #floorMod(int, int)}.
    
    --- a/src/java.base/share/classes/java/lang/StrictMath.java
    +++ b/src/java.base/share/classes/java/lang/StrictMath.java
    @@ -1051,10 +1051,10 @@
         /**
          * 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}.
    +     * the result is equal to {@code Integer.MIN_VALUE}.
          * <p>
          * See {@link Math#floorDiv(int, int) Math.floorDiv} for examples and
          * a comparison to the integer division {@code /} operator.
    @@ -1075,7 +1075,7 @@
         /**
          * 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,10 +1099,10 @@
         /**
          * 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}.
    +     * the result is equal to {@code Long.MIN_VALUE}.
          * <p>
          * See {@link Math#floorDiv(int, int) Math.floorDiv} for examples and
          * a comparison to the integer division {@code /} operator.
    @@ -1123,13 +1123,14 @@
         /**
          * Returns the floor modulus of the {@code int} arguments.
          * <p>
    -     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
    -     * has the same sign as the divisor {@code y}, and
    +     * The floor modulus is {@code r = x - (floorDiv(x, y) * y)},
    +     * has the same 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 floorDiv} and {@code floorMod} is such that:
          * <ul>
    -     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
    +     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}</li>
          * </ul>
          * <p>
          * See {@link Math#floorMod(int, int) Math.floorMod} for examples and
    @@ -1150,8 +1151,8 @@
         /**
          * Returns the floor modulus of the {@code long} and {@code int} arguments.
          * <p>
    -     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
    -     * has the same sign as the divisor {@code y}, and
    +     * The floor modulus is {@code r = x - (floorDiv(x, y) * y)},
    +     * has the same sign as the divisor {@code y} or is zero, and
          * is in the range of {@code -abs(y) < r < +abs(y)}.
          *
          * <p>
    @@ -1157,7 +1158,7 @@
          * <p>
          * The relationship between {@code floorDiv} and {@code floorMod} is such that:
          * <ul>
    -     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
    +     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}</li>
          * </ul>
          * <p>
          * See {@link Math#floorMod(int, int) Math.floorMod} for examples and
    @@ -1178,13 +1179,14 @@
         /**
          * Returns the floor modulus of the {@code long} arguments.
          * <p>
    -     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
    -     * has the same sign as the divisor {@code y}, and
    +     * The floor modulus is {@code r = x - (floorDiv(x, y) * y)},
    +     * has the same 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 floorDiv} and {@code floorMod} is such that:
          * <ul>
    -     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
    +     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}</li>
          * </ul>
          * <p>
          * See {@link Math#floorMod(int, int) Math.floorMod} for examples and