17. Computing mathematical absolute value for int/long and result overflow

Mathematical absolute value is notated by placing the value between two pipe operators and is computed as follows:

|x| = x, |-x| = x

It is commonly used for computing/expressing distances. For example, imagine that 0 represents the sea level and we have a scuba diver and a climber. The scuba diver is underwater at -45 ft (notice that we use negative numbers to express how deep in the water the scuba diver is). At the same time, the climber has climbed 30 ft high. Which of them is closer to the sea level (0)? We may think that -45 < 30, so the scuba diver is closer because its value is smaller. But, we can easily find the correct answer by applying the mathematical absolute as follows:

|-45| = 45, |30| = 30
45 > 30, so the climber is closer to the sea level (0)

Now, let’s dive into the solution with the following example:

int x = -3;
int absofx = Math.abs(x); // 3

This is a very simple use case of Math.abs() which returns the mathematical absolute value of the given integer. Now, let’s apply this method to the following large numbers:

int x = Integer.MIN_VALUE; // -2,147,483,648   
int absofx = Math.abs(x);  // -2,147,483,648

This is not good! The int domain was overflowed because of |Integer.MIN_VALUE| > |Integer.MAX_VALUE|. The expected result is the positive value of 2,147,483,648 which doesn’t fit in the int domain. However, changing the type of x from int to long will solve the problem:

long x = Integer.MIN_VALUE; // -2,147,483,648   
long absofx = Math.abs(x);  // 2,147,483,648

But the problem will reappear if, instead of Integer.MIN_VALUE, there is Long.MIN_VALUE:

long y = Long.MIN_VALUE;   // -9,223,372,036,854,775,808
long absofy = Math.abs(y); // -9,223,372,036,854,775,808

Starting with JDK 15, the Math class was enriched with two absExact() methods. There is one for int and one for long. These methods are very useful if the mathematical absolute result is prone to overflowing the int or long domain (for instance, the Integer/Long.MIN_VALUE values overflows the positive int/long range). In such cases, these methods throw ArithmeticException instead of returning a misleading result, as in the following example:

int absofxExact = Math.absExact(x);  // ArithmeticException
long absofyExact = Math.absExact(y); // ArithmeticException

In a functional style context, a potential solution will rely on UnaryOperator functional interface, as follows:

UnaryOperator<Integer> operatorInt = Math::absExact;
UnaryOperator<Long> operatorLong = Math::absExact;
// both throw ArithmeticException
int absofxExactUo = operatorInt.apply(x); 
long absofyExactUo = operatorLong.apply(y); When working with large numbers, also focus on BigInteger (immutable arbitrary-precision integers) and BigDecimal (immutable arbitrary-precision signed decimal numbers).

Leave a Reply

Your email address will not be published. Required fields are marked *