18. Computing the quotient of the arguments and result overflow

Let’s start with two simple computations as follows:

-4/-1 = 4, 4/-1 = -4

This is a very simple use case that works as expected. Now, let’s keep the divisor as -1, and let’s change the dividend to Integer.MIN_VALUE (-2,147,483,648):

int x = Integer.MIN_VALUE;       
int quotient = x/-1; // -2,147,483,648

This time the result is not correct. The int domain was overflowed because of |Integer.MIN_VALUE| > |Integer.MAX_VALUE|. It should be the positive 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;       
long quotient = x/-1; // 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 quotient = y/-1;    // -9,223,372,036,854,775,808

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

// throw ArithmeticException
int quotientExact = Math.divideExact(x, -1);

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

// throw ArithmeticException
BinaryOperator<Integer> operator = Math::divideExact;
int quotientExactBo = operator.apply(x, -1);

As we said in the previous problem as well, when working with large numbers, also focus on BigInteger (immutable arbitrary-precision integers) and BigDecimal (immutable arbitrary-precision signed decimal numbers).

19. Computing the largest/smallest value that is less/greater than or equal to the algebraic quotient

By the largest value, we understand the value closest to positive infinity, while by the smallest value, we understand the value closest to negative infinity.Computing the largest value that is less than or equal to the algebraic quotient can be done starting with JDK 8 via floorDiv(int x, int y) and floorDiv(long x, long y). Starting with JDK 9, we also have floorDiv(long x, int y).Computing the smallest value that is greater than or equal to the algebraic quotient can be done starting with JDK 18 via ceilDiv(int x, int y), ceilDiv(long x, int y), and ceilDiv(long x, long y).But, none of these functions are capable to manage the corner case divisions presented in the previous problem, Integer.MIN_VALUE/-1 and Long.MIN_VALUE/-1:

int x = Integer.MIN_VALUE; // or, x = Long.MIN_VALUE
Math.floorDiv(x, -1); // -2,147,483,648
Math.ceilDiv(x, -1);  // -2,147,483,648

Starting with JDK 18, whenever the result returned by floorDiv()/ceilDiv() is prone to overflowing the int or long domains, we can use floorDivExact() and ceilDivExact(). These methods come with flavors for int and long arguments. As you probably intuit already, these methods throw ArithmeticException instead of returning a misleading result, as in the following example:

// throw ArtihmeticException
int resultFloorExact = Math.floorDivExact(x, -1);
// throw ArtihmeticException
int resultCeilExact = Math.ceilDivExact(x, -1);

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

// throw ArithmeticException
BinaryOperator<Integer> operatorf = Math::floorDivExact;
int floorExactBo = operatorf.apply(x, -1);
// throw ArithmeticException
BinaryOperator<Integer> operatorc = Math::ceilDivExact;
int ceilExactBo = operatorc.apply(x, -1);

Done! As you already know, when working with large numbers, also focus on BigInteger (immutable arbitrary-precision integers) and BigDecimal (immutable arbitrary-precision signed decimal numbers). These may save your day 🙂

Leave a Reply

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