Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#FFcccc
public int multAccum(int oldAcc, int newVal, int scale) {
  // May result in overflow 
  return oldAcc + (newVal * scale);
}

Compliant Solution (Pre-condition the

...

inputs)

The code example below shows the necessary pre-conditioning checks required for each arithmetic operation on arguments of type int. The checks for the other integral types are analogous.

...

Note that although these pre-conditioning checks are correct, more efficient code may well be possible. Further, the checks can be simplified when the original type was char. Because the range of type char includes only positive values, all comparisons with negative values may be omitted.

Compliant Solution (Pre-condition the inputs)

Code Block
bgColor#ccccff
public int multAccum(int oldAcc, int newVal, int scale) throws ArithmeticException {
  preMultiply(newVal, Scale);
  final int temp = newVal * scale;
  preAdd(oldAcc, temp);
  return oldAcc + temp;
}

Compliant Solution (Use a Larger Type and Downcast)

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. Therefore, we can perform an operation using the larger type and range-check before down casting to the original type. Note, however, that this guarantee holds only for a one arithmetic operation; larger expressions without per-operation bounds checks may overflow the larger type.

This approach cannot be applied for type long because long is the largest primitive integral type. Use the "Use 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 they int. The implementations of range checks for the smaller primitive integer types are exactly analogous.

Code Block
bgColor#ccccff

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

public 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 (Use BigInteger)

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. This property provides conceptual simplicity. An unfortunate consequence of this technique is that compliant code must be written using method calls in place of primitive arithmetic operators; this may obscure the intent of the code.

Note that operations on objects of type BigInteger may be significantly less efficient than operations on the original primitive integer type. Whether this loss of efficiency is important will depend on the context in which the code is used.

...

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

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

public 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
}

...