Computing an array's average

exercise No. 222

Q:

We consider a method double averageRoundedOneDecimal(final int[] values):

/**
 * <p>Rounding the sum of values to one decimal place.</p>
 *
 * <p>Example: averageRoundedOneDecimal(new int[]{0, 1, 1}) yields 0.7 rather than 0.66666... .</p>
 *
 * @param values Input values
 * @return The average of all input values rounded to one decimal place.
 */
static double averageRoundedOneDecimal(final int[] values) {
    int sum = 0;
    for (final int value: values) {
        sum += value;
    }
    return Math.round(10 * sum / values.length) / 10;
}

The intention is rounding e.g. 3.173 to 3.2. Unfortunately the Javadoc promise does not hold: Executing averageRoundedOneDecimal(new int[]{0, 1, 1}) effectively yields zero rather than 0.7.

  1. Name the culprit.

  2. Provide a fix.

Hint: Read the Math.round(...) method's Javadoc.

A:

There are two issues here:

  • 10 * sum is an int expression. Dividing by values.length simply cuts of and thus yields zero for the example in question

  • The Math.round(...) method has got return type long. A Java compiler already provides a warning clue:

    'Math.round(10 * sum / values.length) / 10': integer division in floating-point context

We end up with cutting off again. Enforcing double division solves both issues:

return Math.round(10.0 * sum / values.length) / 10.0;

Overflow errors are possible as well: Using long sum avoids this problem.