Computing the average

exercise No. 212

Q:

We consider:

/**
 * Compute the average of a list of int values.
 *
 * Example: For <code>values = {1, 2}</code> the average is 1.5.
 *
 * @param values An array containing at least one value.
 * @return The average of all values.
 */
public static double average(int[] values) {
  int sum = 0;
  for (final int v: values) {
    sum += v;
  }
  return sum / values.length;
}

This method contains two serious flaws with respect to its Javadoc promise.

  1. Explain both issues

  2. Improve the implementation accordingly.

  3. Explain why your corrected code will solve the issues.

Tip

Do not forget considering overflow issues.

A:

  • The method's implementation contains two flaws:

    1. Due to integer arithmetic the return statement's expression sum / values.length will in most cases truncate the intended result. In the given example (1 + 2) / 2 will be truncated to integer 1 rather than returning the intended double value of 1.5.

    2. Calculating the sum may lead to overflow errors. Due to an arithmetic overflow e.g, the sum corresponding to an input array {1, Integer.MAX_VALUE} will result in Integer.MIN_VALUE .

  • We address the first issue by casting our divisor to double. The second issue is being resolved by choosing a long rather than int variable for calculating the sum of values:

    public static double average(int[] values) {
      long sum = 0;
      for (final int v: values) {
        sum += v;
      }
      return sum / (double) values.length;
    }
  • Declaring sum of type long rather than int does indeed avoids the overflow issue: An int's value is bounded by [ - 2 31 , 2 31 - 1 ] . An int[] array on the other hand may contain a maximum of 2 31 - 1 entries. The sum variable's value is thus bounded by [ - ( 2 62 - 2 31 ) , 2 62 - 2 32 + 1 ] . This is well within a long variable's range [ - 2 63 , 2 63 - 1 ] avoiding overflows altogether.