1. Overview
Dividing by zero is an operation that has no meaning in ordinary arithmetic and is, therefore, undefined. In programming, however, while it is often associated with an error, this is not always the case.
In this article, we'll go through what happens when a division by zero occurs in a Java program.
According to the Java specification of the division operation, we can identify two different cases of division by zero: integers and floating-point numbers.
2. Integers
Firstly, for integers, things are pretty straightforward. Dividing an integer by zero will result in an ArithmeticException:
assertThrows(ArithmeticException.class, () -> { int result = 12 / 0; });
assertThrows(ArithmeticException.class, () -> { int result = 0 / 0; });
3. Floating Point Types
However, when dealing with floating-point numbers, an exception won't be thrown:
assertDoesNotThrow(() -> { float result = 12f / 0; });
In order to handle cases like these, Java uses some special numeric values that can represent the results of such an operation: NaN, POSITIVE_INFINITY, and NEGATIVE_INFINITY.
3.1. NaN
Let's start by dividing floating-point zero values by zero:
assertEquals(Float.NaN, 0f / 0); assertEquals(Double.NaN, 0d / 0);
The result in these cases is NaN (not a number).
3.2. Infinity
Next, let's divide some non-zero values by zero:
assertEquals(Float.POSITIVE_INFINITY, 12f / 0); assertEquals(Double.POSITIVE_INFINITY, 12d / 0); assertEquals(Float.NEGATIVE_INFINITY, -12f / 0); assertEquals(Double.NEGATIVE_INFINITY, -12d / 0);
As we can see, the result is INFINITY, with the sign depending on the sign of the operands.
Moreover, we can also use the concept of negative zero in order to get to NEGATIVE_INFINITY:
assertEquals(Float.NEGATIVE_INFINITY, 12f / -0f); assertEquals(Double.NEGATIVE_INFINITY, 12f / -0f);
3.3. Memory Representation
So, why does integer division by zero throw an exception, while floating-point division by zero does not?
Let's look at this from a memory representation perspective. For integers, there is no bit pattern that can be used to store the result of such an operation, while floating-point numbers have values like NaN or INFINITY to be used in cases like these.
Now, let's consider the binary representation of a float as SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF with one bit (S) for the sign, 8 bits (E) for the exponent, and the rest (F) for the mantissa.
In each of the three values NaN, POSITIVE_INFINITY, and NEGATIVE_INFINITY, all bits in the exponent part are set to 1.
INFINITY has the mantissa bits all set to 0, while NaN has a non-zero mantissa:
assertEquals(Float.POSITIVE_INFINITY, Float.intBitsToFloat(0b01111111100000000000000000000000)); assertEquals(Float.NEGATIVE_INFINITY, Float.intBitsToFloat(0b11111111100000000000000000000000)); assertEquals(Float.NaN, Float.intBitsToFloat(0b11111111100000010000000000000000)); assertEquals(Float.NaN, Float.intBitsToFloat(0b11111111100000011000000000100000));
4. Summary
To sum things up, in this article we saw how division by zero works in Java.
Values like INFINITY and NaN are available for floating-point numbers but not for integers. As a result, dividing an integer by zero will result in an exception. However, for a float or double, Java allows the operation.
The complete code is available over on GitHub.