Under exact integer arithmetic, the intended result is , using the ceiling function. A sufficient loop invariant is
Initially , and the final disjunction is true. If the guard holds, the old value is below . Incrementing i and doubling y therefore preserves and makes the new lower bound true. At exit . If , positivity of forces ; otherwise . Both cases establish the claimed postcondition. Doubling eventually reaches or exceeds any fixed positive , proving algorithm termination in this arithmetic model. This is the doubling-loop ceiling logarithm argument.
The printed Scala implementation is not correct for its entire stated Int domain. Its y is an Int. For , it reaches , wraps to on the next doubling, then becomes zero and stays zero. The guard remains true forever. The loop invariant above is valid for the printed code only when . Scala documents Int as a signed 32-bit value equivalent to Java's primitive int.[ref]
A corrected implementation for every positive Int input widens the doubling variable before any multiplication:
def ceilingLog2(x: Int): Int = {
  require(x > 0)
  var i = 0
  var y = 1L
  while (y < x.toLong) {
    i += 1
    y *= 2L
  }
  i
}
Now at most 31 iterations are needed and , safely within Long. The same loop invariant proves total correctness without the overflow gap.

Articles by others on the same topic (0)

There are currently no matching articles.