#### Range of Numeric Values

As we have seen, all numeric types have a range of valid values (p. 41). This range is given by the constants named MAX_VALUE and MIN_VALUE, which are defined in each numeric wrapper type.

The arithmetic operators are overloaded, meaning that the operation of an operator varies depending on the type of its operands. Floating-point arithmetic is performed if any operand of an operator is of floating-point type; otherwise, integer arithmetic is performed.

Values that are out of range or are the results of invalid expressions are handled differently depending on whether integer or floating-point arithmetic is performed.

##### Integer Arithmetic

Integer arithmetic always returns a value that is in range, except in the case of integer division by zero and remainder by zero, which cause an ArithmeticException (see the later discussion of the division operator / and the remainder operator %). A valid value does not necessarily mean that the result is correct, as demonstrated by the following examples:

int tooBig = Integer.MAX_VALUE + 1; // -2147483648 which is Integer.MIN_VALUE.

int tooSmall = Integer.MIN_VALUE – 1; // 2147483647 which is Integer.MAX_VALUE.

These results should be values that are out of range. However, integer arithmetic wraps around the result if it is out of range; that is, the result is reduced modulo in the range of the result type. To avoid wrapping around out-of-range values, programs should use either explicit checks or a wider type. If the type long were used in the earlier examples, the results would be correct in the long range:

long notTooBig = Integer.MAX_VALUE + 1L; // 2147483648L in range.

long notTooSmall = Integer.MIN_VALUE – 1L; // -2147483649L in range

##### Floating-Point Arithmetic

Certain floating-point operations result in values that are out of range. Typically, adding or multiplying two very large floating-point numbers can result in an out-of-range value that is represented by infinity (Figure 2.3). Attempting floating-point division by zero also returns infinity. The following examples show how this value is printed as signed infinity:

System.out.println( 4.0 / 0.0); // Prints: Infinity

System.out.println(-4.0 / 0.0); // Prints: -Infinity

Both positive and negative infinity represent overflow to infinity; that is, the value is too large to be represented as a double or float (Figure 2.3). Signed infinity is represented by the named constants POSITIVE_INFINITY and NEGATIVE_INFINITY in the wrapper classes java.lang.Float and java.lang.Double. A value can be compared with these constants to detect overflow.

Figure 2.3 Overflow and Underflow in Floating-Point Arithmetic

Floating-point arithmetic can also result in underflow to zero, when the value is too small to be represented as a double or float (Figure 2.3). Underflow occurs in the following situations:

- The result is between Double.MIN_VALUE (or Float.MIN_VALUE) and zero, as with the result of (5.1E-324 – 4.9E-324). Underflow then returns positive zero 0.0 (or 0.0F).
- The result is between -Double.MIN_VALUE (or -Float.MIN_VALUE) and zero, as with the result of (-Double.MIN_VALUE * 1E-1). Underflow then returns negative zero -0.0 (or -0.0F).

Negative zero compares equal to positive zero; in other words, (-0.0 == 0.0) is true.

Certain operations have no mathematical result, and are represented by NaN (Not-a-Number). For example, calculating the square root of –1 results in a NaN. Another example is (floating-point) dividing zero by zero:

System.out.println(0.0 / 0.0); // Prints: NaN

NaN is represented by the constant named NaN in the wrapper classes java.lang.Float and java.lang.Double. Any operation involving NaN produces NaN. Any comparison (except inequality, !=) involving NaN and any other value (including NaN) returns false. An inequality comparison of NaN with another value (including NaN) always returns true. However, the recommended way of checking a value for NaN is to use the static method isNaN() defined in both wrapper classes, java.lang.Float and java.lang.Double.