According to the standard, overflow in java is handled using a special value called infinity, but here the sum is 3.4028235E38. Why is this the case?
public class FloatingPointTest {
public static void main(String[] args) {
float a = Float.MAX_VALUE;
float b = 1_000_000_000f; // Note the 'f' to ensure it's a float literal
float sum = a + b;
System.out.println("Float.MAX_VALUE: " + a);
System.out.println("Large number: " + b);
System.out.println("Sum: " + sum);
System.out.println("Is sum equal to Float.POSITIVE_INFINITY? " + (sum == Float.POSITIVE_INFINITY));
}
}
An arithmetic result is rounded before it is tested for overflow. If the rounded result is representable, there is no overflow.
For rounding, Java uses IEEE 754’s round-to-nearest, ties-to-even method (per The Java Virtual Machine Specification, JAVA SE 18 Edition 2022-02-23, clause 2.8 Floating-Point Arithmetic, page 20).
Rounding in IEEE-754 behaves as if the range were unbounded (per IEEE 754-2019 draft D2.47, clause 4.3, first paragraph, page 18). That is, the rounding is performed as if there were no bound on the exponent, and then a check for overflow is performed. For illustration, suppose we had a two-digit decimal format that had finite numbers up to, but not including, 100. So 99 is representable but 100 is out of bounds. Consider adding 99 and .23. The exact result would be 99.23. This is above 99, but we do not declare overflow yet. First, we round 99.23 to two digits. The result is 99. This is within the finite range, so it does not overflow.
In the binary32 format that Java uses for Float, Float.MAX_VALUE is 2128−2104. If the exponent were not bounded, the next greater representable value would be 2128. When we add 109 to Float.MAX_VALUE, the exact result would be 2128−2104+109. When we round, this is nearer to 2128−2104 than it is to 2128. So it is rounded to 2128−2104, and there is no overflow.
The rule that we round before we test for overflow makes sense: There is no reason for rounding to change at the edge of the finite range or to produce an infinity when the ordinary result of rounding would be finite. If we changed the rules to make any result outside the finite range an overflow, then floating-point arithmetic would behave differently near the edge of the range than it does inside the finite range.
If you added 2103 to Float.MAX_VALUE, the exact result, 2128−2104+2103 would be exactly halfway between 2128−2104 and 2128. The rule for tied results is to round to the choice with the even low digit in its significand. The low digit of 2128−2104 is 1, and the low digit of 2128 is 0, so the result would be 2128. That is out of the finite range, so an overflow would be declared.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With