Potential Pitfalls in Java's Modulo Operator for Parity Checking
A common approach for determining if a integer is odd or even in Java is to use the modulo operator %. While this often works, a subtle bug can occur with ngeative numbers.
Demonstrating the Issue
Consider the following test method:
@Test
public void testParityCheck() {
System.out.println("Testing parity with modulo:");
System.out.println("2 is: " + checkParityMod(2));
System.out.println("1 is: " + checkParityMod(1));
System.out.println("0 is: " + checkParityMod(0));
System.out.println("-1 is: " + checkParityMod(-1));
System.out.println("-2 is: " + checkParityMod(-2));
}
private String checkParityMod(int value) {
return value % 2 == 1 ? "Odd" : "Even";
}
Running this test yields an incrorect result: -1 is classified as "Even". This happens because the expression -1 % 2 evaluates to -1, not 1, so the condition == 1 fails.
Understanding the Modulo Result
The result of a % b in Java is defined by the identity: (a / b) * b + (a % b) == a. For negative dividensd, the remainder can also be negative. A simplified view of the calculation is:
public static int computeRemainder(int dividend, int divisor) {
return dividend - (dividend / divisor) * divisor;
}
When computeRemainder(-1, 2) is called, it calculates -1 - (-1 / 2 * 2). Since integer division -1 / 2 equals 0, the result is -1 - (0) = -1.
Reliable Solutions
1. Check for Evenness Instead
The simplest fix is to test if the remiander is zero, which correctly identifies even numbers for all integers.
private String checkParityModFixed(int value) {
// Check for even (remainder 0) instead of odd (remainder 1)
return value % 2 == 0 ? "Even" : "Odd";
}
2. Use Bitwise AND (Recommended for Performance)
A more efficient method uses the bitwise AND operator &. For integers, the least significant bit determines parity: 1 for odd, 0 for even.
@Test
public void testBitwiseParity() {
System.out.println("Testing parity with bitwise AND:");
System.out.println("2 is: " + checkParityBitwise(2));
System.out.println("1 is: " + checkParityBitwise(1));
System.out.println("0 is: " + checkParityBitwise(0));
System.out.println("-1 is: " + checkParityBitwise(-1));
System.out.println("-2 is: " + checkParityBitwise(-2));
}
private String checkParityBitwise(int value) {
// Mask the least significant bit
return (value & 1) == 1 ? "Odd" : "Even";
}
This method works correctly for all integer values because it directly inspects the bit pattern.