The %
operator is the reminder operator in Java.
In other languages, it may be called modulo operator.
”%”, which divides one operand by another and returns the remainder as its result.
It seems a simple operator, by looking at example code like this, 10 % 7 = 3
.
However, the %
operator may return a negative value.
assertEquals(-1, -9 % 2, "return negative value here");
assertEquals(1, 9 % -2, "return positive value here");
It’s because Java’s reminder implementation uses “truncated division”. See details in this Wiki page.
The “truncation (integer part)” of -9 / 2
, i.e. -4.5
, is -4
. So,
-9 % 2 = -9 - 2 * (-4) = -9 - (-8) = -1
For the 9 % -2
case, the “truncation” is also -4
. However,
9 % -2 = 9 - (-2) * (-4) = 9 - 8 = 1
A Problem
Sometime, this %
returning negative behavior may cause problems.
var batches = 10;
// ... some RxJava code
.groupBy(input -> Objects.hash(input) % batches)
//...
For example, in above code you may want to split your work into 10 batches.
However, because the Objects.hash()
may return negative hash code,
Objects.hash(input) % 10
has 19 possible values (integers), from -9 to 9.
So unexpectedly, your work is split int 19 batches.
A Rescue
Java 8 provides a Math.floorMod() method, which can be used in situations like above. According to its Javadoc,
If the signs of the arguments are the same, the results of floorMod and the % operator are the same.
If the signs of the arguments are different, the results differ from the % operator.
floorMod(+4, -3) == -2; and (+4 % -3) == +1
floorMod(-4, +3) == +2; and (-4 % +3) == -1
floorMod(-4, -3) == -1; and (-4 % -3) == -1
The floorMod(x, y)
is calculated using below relationship.
floorDiv(x, y) * y + floorMod(x, y) == x
And for the Math.floorDiv() method, its Javadoc says
Returns the largest (closest to positive infinity) int value that is less than or equal to the algebraic quotient.
For example, floorDiv(-4, 3) == -2, whereas (-4 / 3) == -1.
Given dividend is -4 and divisor is 3, its algebraic quotient is -1.333333.
“The largest (closest to positive infinity) int value that is less than or equal to” -1.333333
is -2, not -1 which is larger than the quotient.
Therefore, floorDiv(-4, 3) == -2
.
floorMod(-4, 3) = -4 - floorDiv(-4, 3) * 3 = -4 - (-2)*3 = 2