Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: eliminated redundant descriptions

...

  • Upcasting. Cast the inputs to the next larger primitive integer type and perform the arithmetic in the larger size. Check each intermediate result for overflow of the original smaller type, and throw an ArithmeticException if the range check fails. Note that the range check must be performed after each arithmetic operation; larger expressions without per-operation bounds checking may overflow the larger type. Downcast the final result to the original smaller type before assigning to the result variable. This approach cannot be used for type long because long is already the largest primitive integer type.
  • BigInteger. Convert the inputs into objects of type BigInteger and perform all arithmetic using BigInteger methods. Throw an ArithmeticException if the final result is outside the range of the original smaller type; otherwise, convert back to the intended result type.Type BigInteger is the standard arbitrary-precision integer type provided by the Java standard libraries. The arithmetic operations implemented as methods of this type cannot themselves overflow; instead, they produce the numerically correct result. As a consequence, compliant code performs only a single range check—just before converting the final result to the original smaller type and throw an ArithmeticException if the final result is outside the range of the original smaller type.

The The pre-condition testing technique requires different pre-condition tests for each arithmetic operation. This can be somewhat more difficult to understand than either of the other two approaches.

...

The BigInteger technique is conceptually the simplest of the three techniques. However, it requires the use of method calls for each operation in place of primitive arithmetic operators; this may obscure the intended meaning of the code. This technique consumes more time and memory than the other techniquesOperations on objects of type BigInteger can also be significantly less efficient than operations on the original primitive integer type.

Pre-condition Testing

The following code example shows the necessary pre-condition checks required for each arithmetic operation on arguments of type int. The checks for the other integral types are analogous. In this example, we choose to throw an exception when integer overflow would occur; any other error handling is also acceptable.

...

This compliant solution uses the preAdd() and preMultiply() methods defined above to indicate errors if the corresponding operations might in the Pre-condition testing section to perform secure integral operations or throw ArithmeticException on overflow.

Code Block
bgColor#ccccff
public static int multAccum(int oldAcc, int newVal, int scale) throws ArithmeticException {
  return preAdd(oldAcc, preMultiply(newVal, scale));
}

Compliant Solution (Upcasting)

For all integral types other than long, the next larger integral type can represent the result of any single integral operation. For example, operations on values of type int can be safely performed using type long. As a result, we can perform an operation using the larger type and range-check before downcasting to the original type. Note, however, that this guarantee holds only for a single arithmetic operation; larger expressions without per-operation bounds checking may overflow the larger type.

This approach cannot be applied for type long because long is the largest primitive integral type. Use the BigInteger technique when the original variables are of type long.

This compliant solution shows the implementation of a method for checking whether a long value falls within the representable range of an int. The implementations of range checks for the smaller primitive integer types are similar.

This compliant solution shows the implementation of a method for checking whether a long value falls within the representable range of an int using the upcasting technique. The implementations of range checks for the smaller primitive integer types are similar.

Code Block
bgColor#ccccff


public static long intRangeCheck(long value) throws ArithmeticOverflow {
  if ((value < Integer.MIN
Code Block
bgColor#ccccff


public static long intRangeCheck(long value) throws ArithmeticOverflow {
  if ((value < Integer.MIN_VALUE) || (value > Integer.MAX_VALUE)) {
    throw new ArithmeticException("Integer overflow");
  }
  return value;
}

public static int multAccum(int oldAcc, int newVal, int scale) throws ArithmeticException {
  final long res = 
    intRangeCheck(((long) oldAcc) + intRangeCheck((long) newVal * (long) scale));
  return (int) res; // safe down-cast
}

Compliant Solution (BigInteger)

-cast
}

This approach cannot be applied for type long because long is the largest primitive integral type. Use the BigInteger technique when the original variables are of type long.

Compliant Solution (BigInteger)

This compliant solution uses the BigInteger technique to detect overflowType BigInteger is the standard arbitrary-precision integer type provided by the Java standard libraries. The arithmetic operations implemented as methods of this type cannot themselves overflow; instead, they produce the numerically correct result. As a consequence, compliant code performs only a single range check—just before converting the final result to the original smaller type. This property provides conceptual simplicity. An unfortunate consequence of this technique is that compliant code must be written using method calls instead of primitive arithmetic operators; this can obscure the intent of the code. Operations on objects of type BigInteger can also be significantly less efficient than operations on the original primitive integer type.

Code Block
bgColor#ccccff
private static final BigInteger bigMaxInt = BigInteger.valueOf(Int.MAX_VALUE);
private static final BigInteger bigMinInt = BigInteger.valueOf(Int.MIN_VALUE);

public static BigInteger intRangeCheck(BigInteger val) throws ArithmeticException {
  if (val.compareTo(bigMaxInt) == 1 ||
      val.compareTo(bigMinInt) == -1) {
    throw new ArithmeticException("Integer overflow");
  }
  return val;
}

public static int multAccum(int oldAcc, int newVal, int scale) throws ArithmeticException { 
  BigInteger product =
    BigInteger.valueOf(newVal).multiply(BigInteger.valueOf(scale));
  BigInteger res = intRangeCheck(BigInteger.valueOf(oldAcc).add(product));
  return res.intValue(); // safe conversion
}

...