Friday, August 15, 2014

Java 8 Overview: Exact numerical methods and negative floor/mod methods

Exact Numerical Methods

One of the lesser known features added to Java 8 is the addition of exact numerical methods to deal with MAX_VALUE/MIN_VALUE situations. Normally when you do arithmetic with integers or longs (floats and doubles work the same but you don't do much addition with them right? You use BigDecimal right? right?) and you go beyond their max value they just wrap around to MIN_VALUE and increase from there or decrease from MIN_VALUE to MAX_VALUE and decrease from there due to the bit shift of the first bit in a word (which designates a positive number from a negative number). The following code example and output shows how this works for int (long, float, and double work the same).
System.out.println("Max Value: " + Integer.MAX_VALUE);
System.out.println("Max Value + 1: " + (Integer.MAX_VALUE + 1));

try {
  System.out.println("This won't print: " + Math.addExact(Integer.MAX_VALUE, 1));
} catch (ArithmeticException e) {
  System.out.println("Exception since we overflowed Integer.MAX_VALUE");
Max Value: 2147483647
Max Value + 1: -2147483648
Exception since we overflowed Integer.MAX_VALUE

Negative Floor and Mod

The other arithmetic "fix" in this release deals with negative division and negative mod values. The way java is supposed to work is when you use the '/' symbol with integers and the result isn't exact then it's supposed to give you the first number less than the exact number. So if I were to do (4/3) then I'd get 1 since the actual answer is 1.33. With negative numbers this is off slightly. Instead of the next number down it gives you the next number up (heading for 0), basically the negative version of the positive result. Look at the following example.
System.out.println("Divide with negative numerator: " + -4 / 3);
System.out.println("Math.floorDiv() with negative numerator: " + Math.floorDiv(-4, 3));
Divide with negative numerator: -1
Math.floorDiv() with negative numerator: -2
In this example the old value is -1 (the mirror value for the positive result) but that isn't quite right, it's the next integer GREATER than the correct answer, not the next integer LESS THAN the answer so now with the new method you get the correct answer of -2.
Similar to the floor the mod value with negative numbers is also incorrect with the new floorDiv() logic. Now, MOD with negative numbers is already screwy as may languages define it differently but with the new setup you'd get the following:
System.out.println("Mod with negative numerator: " + -4 % 3);
System.out.println("Math.floorMod() with negative numerator: " + Math.floorMod(-4, 3));
Mod with negative numerator: -1
Math.floorMod() with negative numerator: 2
So, what's happening with the new setup? Well, if you were to do a floorDiv of the same numbers you'd get a -2 and -2 * 3 is -6 so the difference between that result and the original numerator is 2. The floorMod result is always the same sign as the denominator (so if instead of Math.floorMod(-4, 3) we used Math.floorMod(4, -3) then the result would be -2).


While I would imagine the new mod methods will have limited usefulness, however, the exact numerical methods for int and long I would find very useful. Currently well written programs have to constantly check to see if a summation (it will also work in reverse below MIN_VALUE) exceeds the bounds of the variable type. Now, you can check for ArithmaticException (or not as it's a runtime exception so it will bubble up nicely) instead and devote your program to what it's intending to do and leave the bounds checks to the system.

No comments:

Post a Comment