Bitwise Manipulation and Precision Control for Java Numeric Types
Bit-Level Operations
Integer values store data as binary sequences. Several operators manipulate these bits directly.
Shift Operators
Left shift (<<) multiplies by powers of two, while right shift (>>) performs division by powers of two.
int base = 16; // 0b10000
int leftShifted = base << 2; // 16 * 4 = 64 (0b1000000)
int rightShifted = base >> 2; // 16 / 4 = 4 (0b100)
// Overflow with excessive left shift
int overflow = base << 28; // Becomes negative due to sign bit
AND, OR, and XOR
The bitwise AND (&) yields 1 only where both operands have 1. OR (|) yields 1 where either operand has 1. XOR (^) yields 1 where bits differ.
int m = 0b1100; // 12
int n = 0b1010; // 10
int andResult = m & n; // 0b1000 (8)
int orResult = m | n; // 0b1110 (14)
int xorResult = m ^ n; // 0b0110 (6)
Complement
The unary NOT operator (~) inverts every bit, including the sign bit.
int original = 0b00000000000000000000000000000101; // 5
int inverted = ~original; // -6 (0b11111111111111111111111111111010)
Managing Integer Overflow
Arithmetic on primitive types wraps around silently when exceeding storage limits. For 32-bit int, adding beyond Integer.MAX_VALUE (2,147,483,647) produces negative values.
int large = 2_000_000_000;
int larger = 1_500_000_000;
int sum = large + larger; // Overflow occurs, results in negative value
Mitigation Strategies
For calculations potentially exceeding int ranges, promote to long:
long safeSum = (long) large + (long) larger; // Correct positive result
For arbitrary-precision arithmetic, utilize java.math.BigInteger:
BigInteger bi1 = new BigInteger("2000000000");
BigInteger bi2 = new BigInteger("1500000000");
BigInteger addition = bi1.add(bi2);
BigInteger subtraction = bi1.subtract(bi2);
BigInteger multiplication = bi1.multiply(bi2);
BigInteger division = bi1.divide(bi2); // Throws exception if not divisible
Floating-Point Accuracy
Binary floating-point representation cannot precisely encode many decimal fractions, leading to rounding artifacts.
double calc = 0.1 + 0.2;
System.out.println(calc); // Outputs 0.30000000000000004, not 0.3
Exact Decimal Arithmetic
BigDecimal provides precise control over decimal calculations. Always initialize with String arguments to avoid imprecise double literals.
BigDecimal precise1 = new BigDecimal("0.1");
BigDecimal precise2 = new BigDecimal("0.2");
BigDecimal exactSum = precise1.add(precise2); // Exactly 0.3
Division requires explicit rounding modes when the result has infinite decimal expansion:
BigDecimal dividend = new BigDecimal("10");
BigDecimal divisor = new BigDecimal("3");
BigDecimal quotient = dividend.divide(divisor, 4, RoundingMode.HALF_UP); // 3.3333