1. Overview
In Java programming, understanding how to manipulate integers is fundamental to writing robust and efficient code. One common operation is negating an integer.
In this tutorial, we’ll explore different approaches to negating an integer.
2. Introduction to the Problem
Negating an integer involves changing its sign from positive to negative or vice versa. For example, given an int 42, after negating it, we expect to get -42 as the result.
We shouldn’t forget the number 0 is neither positive nor negative. Therefore, the result of negating 0 should be 0, too.
In Java, this operation is straightforward, and we’ll see three different ways to achieve it. Additionally, we’ll discuss a corner case: integer overflow.
For simplicity, we’ll use unit test assertions to verify the result of each approach.
3. Using the Unary Minus Operator
The most straightforward approach to negate an integer is using the unary minus operator (–). It simply changes the sign of the given integer:
int x = 42;
assertEquals(-42, -x);
int z = 0;
assertEquals(0, -z);
int n = -42;
assertEquals(42, -n);
As the test shows, we get the expected results by applying ‘–‘ to the input integers.
4. Using the Bitwise Complement Operator
Another unconventional yet effective way to negate an integer is using the bitwise complement operator (~). This operator inverts the bits of the given integer, effectively creating the two’s complement:
int number = 12;
int negative13 = ~number; // ~00001100 = 11110011 = -13
Therefore, given an integer x, ~x + 1 is the negation of x.
Next, let’s write a test to verify that:
int x = 42;
assertEquals(-42, ~x + 1);
int z = 0;
assertEquals(0, ~z + 1);
int n = -42;
assertEquals(42, ~n + 1);
As we can see, ~x + 1 solves the problem.
5. Overflow Concerns With Integer.MIN_VALUE
We know Java’s integer type is a signed 32-bit type with a range from -2147483648 to 2147483647. If we negate Integer.MAX_VALUE, the result –2147483647 is still in the range. But, if we negate Integer.MIN_VALUE, we should get 2147483648, which is greater than Integer.MAX_VALUE. Therefore, in this edge case, an overflow error occurs.
Although the ‘-x‘ and ‘~x + 1‘ approaches are straightforward, we can only use them in our applications if we ensure overflow won’t happen. A few example scenarios where using them might be appropriate include:
- Calculating a soccer team’s goal difference in a tournament
- Calculating an employee’s working hours in a month
However, if overflow might happen in our program, using these approaches is discouraged.
Next, let’s explore why these two approaches result in an overflow error when using Integer.MIN_VALUE as the input.
5.1. -x With Integer.MIN_VALUE
First, let’s negate Integer.MIN_VALUE using the ‘–‘ operator:
int min = Integer.MIN_VALUE;
LOG.info("The value of '-min' is: " + -min);
assertTrue((-min) < 0);
This test passes, meaning we still have a negative result after negating an Integer.MIN_VALUE. We can further verify this from the output:
The value of '-min' is: -2147483648
Therefore, the ‘-x’ approach returns the wrong result when an overflow occurs.
5.2. ~x + 1 With Integer.MIN_VALUE
Let’s run the same test using the ‘~x + 1′ approach:
int min = Integer.MIN_VALUE;
int result = ~min + 1;
LOG.info("The value of '~min + 1' is: " + result);
assertFalse(result > 0);
We can see that this approach won’t give the expected result either when an overflow occurs. Let’s verify this further by checking the log output in the console:
The value of '~min + 1' is: -2147483648
6. Using the Math.negateExact() Method
For scenarios where dealing with Integer.MIN_VALUE is required, the Math.negateExact() method provides a safe and precise way to negate an integer.
First, Math.negateExact() works as expected in normal cases:
int x = 42;
assertEquals(-42, Math.negateExact(x));
int z = 0;
assertEquals(0, Math.negateExact(z));
int n = -42;
assertEquals(42, Math.negateExact(n));
Next, let’s see what comes out if the input is Integer.MIN_VALUE:
int min = Integer.MIN_VALUE;
assertThrowsExactly(ArithmeticException.class, () -> Math.negateExact(min));
As the test shows, the Math.negateExact() method raises an ArithmeticException if an overflow occurs during the negation, allowing the developer to handle the error when it occurs.
7. Conclusion
In this article, we’ve explored three ways to negate an integer in Java.
‘-x‘ and ‘~x + 1‘ are straightforward solutions. However, if our program might try to negate Integer.MIN_VALUE, then using Math.negateExact() is the right choice.
As always, the complete source code for the examples is available over on GitHub.