Weird behaviour

exercise No. 229

Q:

We consider a method computing a given int's square value:

static public int getSquare (int value) {
  return value * value;
}

A larger piece of software using this method produces erroneous results. Tracing for possible errors the developing team adds a logging statement:

static public int getSquare (int value) {
  final int result = value * value;
  log.info(result);
  return result;
}

The team is baffled: Albeit squares of integer values are expected to be strictly positive occasionally negative results show up:

INFO  [main] sd1.SupportMethods (SupportMethods.java:15) - -1757895751
  1. Explain the underlying reason.

  2. You are allowed to modify the method's return type. Provide a solution.

A:

  1. The problem is caused by arithmetic overflow errors. The largest possible int is 2 31 - 1 or 2147483647. Its square root is 46340.95... .Thus up to the value of 46340 all squares are being calculated correctly e.g.:

    Code Result
    System.out.println(46340 * 46340);
    2147395600

    The product 46341 * 46341 of type int for example exceeds 2 31 - 1 for the very first time. Due to an int's four-byte two complement representation we have:

    Code Result
    System.out.println(46341 * 46341);
    -2147479015

    Starting from 46341 all computed squares are simply wrong due to arithmetic overflow regardless of their result's sign.

  2. Solving the issue requires a data type to accommodate squares of arbitrary int values. The smallest int value (having maximum amount) is - 2 31 . Its square is thus 2 62 representing the method's largest possible result. Choosing return type long allows for a maximum value of 2 63 - 1 being ways larger than required. Turning the int into a long expression is easy:

    static public long getSquare (int value) {
      final long result = (long) value * value; // Cast: long * int expression
      log.info(result);
      return result;
    }