Slide 9 of 74

Arithmetic at the edges

proc main(): void {
	echo 1 / 0          // 0 — division by zero is a value, not a crash
	echo 1.0 / 0.0      // 0
	echo 5 % 0          // 0
	echo -7 % 3         // -1 — the remainder takes the sign of what is divided
	echo 7.5 % 2.0      // 1.5

	top := 9223372036854775807
	echo top + 1        // 9223372036854775807 — an Int stays at its edge
	echo -top - 10      // -9223372036854775808 — at either edge
	echo 2 ** 100       // 9223372036854775807
	echo 2 ** -1        // 0 — a negative Int exponent has no whole answer
	echo 10.0 ** 400.0  // +Inf — Float arithmetic does reach infinity
}

Most of arithmetic is unsurprising. These are the cases worth knowing exactly, and what they have in common is that each one is a value rather than a crash:

  • Dividing by zero, or taking a remainder by zero, answers with 0 — for an Int and for a Float alike.
  • An Int never wraps round. A sum, difference, product or power that would pass the largest Int, 9223372036854775807, stays at it, and one that would pass the smallest, -9223372036854775808, stays at that: a counter that reaches the top sits there however much more is added. Negating the smallest Int gives the largest, which is the nearest it has.
  • ** on Ints is repeated multiplication, so 2 ** 100 reaches the top too. A negative exponent has no whole answer, so it gives 0, and n ** 0 is 1.
  • A remainder takes the sign of the number divided, so -7 % 3 is -1, and % works on Floats.
  • Float arithmetic does reach infinity: 10.0 ** 400.0 is +Inf. For the real answer to a power, work in Float, where ** is true exponentiation.

One case in the whole language is left unspecified: turning a Float that is infinite, not a number, or too large for an Int into one with hive.conv.ceil, floor or round. Check the range first if it matters.