Integers

Integers as an abstract data type

The values of the integer data type are simply whole numbers, zero, positive, and negative. They go on forever in both the positive and negative directions -- there is no greatest or least integer.

Since there are infinitely many integers, it is impossible to perform a separate act of naming for each one. Instead, we rely on a system of numeration -- a set of rules for constructing a name for any given number from its value. We'll use the standard decimal system of numeration, with an explicit sign for negative integers.

The following operations belong to my proposed interface for the integer data type. First, the basic arithmetic operations:

negate
Input: negand, an integer.
Output: result, an integer.
Preconditions: none.
Postcondition: The sum of negand and result is 0.

absolute-value
Input: operand, an integer.
Output: result, an integer.
Preconditions: none.
Postcondition: result is the magnitude of operand, that is, its distance (in either direction) from 0.

add
Inputs: augend and addend, both integers.
Output: sum, an integer.
Preconditions: none.
Postcondition: sum is the sum of augend and addend.

subtract
Inputs: minuend and subtrahend, both integers.
Output: difference, an integer.
Preconditions: none.
Postcondition: minuend is the sum of difference and subtrahend.

multiply
Inputs: multiplicand and multiplier, both integers.
Output: product, an integer.
Preconditions: none.
Postcondition: product is the product of multiplicand and multiplier.

divide
Inputs: dividend and divisor, both integers.
Outputs: quotient and remainder, both integers.
Precondition: divisor is not 0.
Postconditions: dividend is the sum of remainder and the product of quotient and divisor. The magnitude of remainder is less than the magnitude of divisor. If remainder is not 0, its sign is the same as the sign of dividend.

quotient
Inputs: dividend and divisor, both integers.
Output: result, an integer.
Precondition: divisor is not 0.
Postcondition: result is the quotient resulting from the division of dividend by divisor. (In other words, it is the first output when divide is applied to dividend and divisor.)

remainder
Inputs: dividend and divisor, both integers.
Output: result, an integer.
Precondition: divisor is not 0.
Postcondition: result is the remainder resulting from the division of dividend by divisor. (In other words, it is the second output when divide is applied to dividend and divisor.)

modulo
Inputs: moduland and modulus, both integers.
Output: result, an integer.
Precondition: modulus is not 0.
Postconditions: The difference between moduland and result is an exact multiple of modulus. The magnitude of result is less than the magnitude of modulus. If result is not 0, its sign is the same as the sign of modulus.

raise
Inputs: base, an integer, and exponent, a natural number.
Output: power, an integer.
Preconditions: none.
Postconditions: power is the result of raising base to the power of exponent. If both base and exponent are 0, power is 1.

The next five operations are special cases of the preceding ones that occur frequently enough to be treated separately:

successor
Input: operand, an integer.
Output: result, an integer.
Preconditions: none.
Postcondition: result is the integer immediately following operand. (In other words, result is the sum of operand and 1.)

predecessor
Input: operand, an integer.
Output: result, an integer.
Preconditions: none.
Postcondition: operand is the integer immediately following result. (In other words, oeprand is the sum of result and 1.)

twice
Input: operand, an integer.
Output: result, an integer.
Preconditions: none.
Postcondition: result is the product of operand and 2.

square
Input: operand, an integer.
Output: result, an integer.
Preconditions: none.
Postcondition: result is the result of raising operand to the power 2.

cube
Input: operand, an integer.
Output: result, an integer.
Preconditions: none.
Postcondition: result is the result of raising operand to the power 3.

Next, the comparison operations:

equal
Inputs: left-operand and right-operand, both integers.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if the operands are the same integer, false if they are different integers.

unequal
Inputs: left-operand and right-operand, both integers.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if the operands are different integers, false if they are the same integer.

less
Inputs: left-operand and right-operand, both integers.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if left-operand is less than right-operand, false if it is greater than right-operand or if both operands are the same integer.

less-or-equal
Inputs: left-operand and right-operand, both integers.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if left-operand is less than right-operand or if both operands are the same integer, false if left-operand is greater than right-operand.

greater
Inputs: left-operand and right-operand, both integers.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if left-operand is greater than right-operand, false if it is less than right-operand or if both operands are the same integer.

greater-or-equal
Inputs: left-operand and right-operand, both integers.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if left-operand is greater than right-operand or if both operands are the same integer, false if left-operand is less than right-operand.

major
Inputs: left-operand and right-operand, both integers.
Output: result, an integer.
Preconditions: none.
Postcondition: result is the greater of the operands.

minor
Inputs: left-operand and right-operand, both integers.
Output: result, an integer.
Preconditions: none.
Postcondition: result is the lesser of the operands.

Again, some special cases of the preceding predicates are worth defining:

zero
Input: operand, an integer.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if operand is 0, false if it is any other integer.

negative
Input: operand, an integer.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if operand is less than 0, false if it is greater or if it is 0.

positive
Input: operand, an integer.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if operand is greater than 0, false if it is less or if it is 0.

Various tests for attributes of integers:

multiple
Inputs: candidate and unit, both integers.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if candidate is an exact multiple of unit, false otherwise. (Note that 0 is an exact multiple of every integer, including itself.)

even
Input: operand, an integer.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is true if operand is an exact multiple of 2, false if it is not.

odd
Input: operand, an integer.
Output: result, a Boolean.
Preconditions: none.
Postcondition: result is false if operand is an exact multiple of 2, true if it is not.

Finally, the input and output operations:

read
Input: source, a data source (e.g., a file, the keyboard, a device).
Outputs: legend, an integer, and success, a Boolean.
Preconditions: none.
Postcondition: Either some representation of an integer value has been extracted from source and legend is that integer value, or an input error of some kind has occurred and success is false.

write
Inputs: target, a data sink (e.g., a file, a window, a device), and scribend, an integer.
Outputs: none.
Preconditions: none.
Postcondition: A representation of scribend has been appended to target.

Integers in standard Pascal

Values of the standard Pascal Integer type are essentially always represented as word-length data, and therefore constitute a finite, fixed range of integers; integers outside of this range are not representable. In effect, preconditions are added to all of the operations, asserting that the inputs and outputs of the operation all lie within the specified range. Since it is often difficult or impossible to ascertain the truth of these preconditions before performing the operations, this feature of standard Pascal is a common source of programming errors.

In a subsequent handout, we'll develop a way of avoiding this limitation, defining a different integer type that includes arbitrarily large values. In the meantime, we'll try to live within the confines of the standard Integer type, remembering to stay within the permitted range.

In Standard Pascal, decimal numerals are used as names for values of the Integer type. It also provides an alternative name, MaxInt, for the largest value of the Integer data type. It guarantees that all integers in the range from -MaxInt to MaxInt, inclusive, are representable. (In many implementations, such as HP Pascal, the integer -MaxInt - 1 is also representable, but the standard does not guarantee this.)

Of the operations listed above, standard Pascal provides about half:

It comes close to providing modulo (as the mod operator), but adds the precondition that modulus be positive; and it provides a version of read that crashes when the input is not to its liking, rather than setting a success flag.

Standard Pascal also provides an identity operation on integers -- that is, a function (Ord) that takes any integer as argument and returns the same integer.

Supplying the missing operations

Once again, it is straightforward to supplement the built-in operations in Pascal with programmer-defined functions and procedures to complete the implementation of the abstract data type:
{ Even in implementations, such as HP Pascal, where -MaxInt - 1 is a
  representable integer, it usually has to receive exceptional treatment in
  arithmetic operations, since its negative is not representable.  (This
  implies, for instance, that one cannot take its absolute value, divide it
  by -1, etc.)  In these procedures, I've dealt with the problem by writing
  assertions that filter out this value whenever it would interfere with
  the usual algorithm.

  The identifier MinInt is predefined (as a non-standard extension to the
  language) in HP Pascal. }

  procedure Divide (Dividend: Integer; Divisor: Integer;
                    var Quotient: Integer; var Remainder: Integer);
  begin
    { Assert (Divisor <> 0); }
    { Assert ((Dividend <> MinInt) and (Divisor <> MinInt); }
    Quotient := Dividend div Divisor;
    Remainder := Dividend - (Quotient * Divisor)
  end;

  function Remainder (Dividend: Integer; Divisor: Integer): Integer;
  var
    UnsignedResult: Integer;
  begin
    { Assert (Divisor <> 0); }
    { Assert ((Dividend <> MinInt) and (Divisor <> MinInt)); }
    UnsignedResult := Abs (Dividend) mod Abs (Divisor);
    if Dividend < 0 then
      Remainder := -UnsignedResult
    else
      Remainder := UnsignedResult
  end;

  function Modulo (Moduland: Integer; Modulus: Integer): Integer;
  var
    UnsignedResult: Integer;
  begin
    { Assert (Modulus <> 0); }
    { Assert ((Moduland <> MinInt) and (Modulus <> MinInt)); }
    UnsignedResult := Moduland mod Abs (Modulus);
    if (Modulus < 0) and (UnsignedResult <> 0) then
      Modulo := UnsignedResult + Modulus
    else
      Modulo := UnsignedResult
  end;

  { The Raise function presupposes that the result of the exponentiation
    operation is representable as an integer, but does not confirm this
    presupposition.

    The algorithm used in this function begins with three arithmetic facts:

      k^0 = 1

      k^(2n) = (k^n)^2

      k^(2n + 1) = k * (k^n)^2

    Thus, if Exponent is 0, the function can immediately return 1; if it is
    greater than 0 and even, the function can raise the same base to a
    power half as large, then square the result; if it is greater than 0
    and odd, the function can perform the same squaring operation, then
    multiply the result by the base.

    The recursion must terminate, since Exponent is initially non-negative
    and is strictly smaller on each recursive call, while never becoming
    negative.  It must therefore eventually reach 0, at which point the
    recursion stops. }

  function Raise (Base: Integer; Exponent: Integer): Integer;
  var
    Square: Integer;
  begin
    { Assert (0 <= Exponent); }
    if Exponent = 0 then
      Raise := 1
    else begin
      Square := Sqr (Raise (Base, Exponent div 2));
      if Odd (Exponent) then
        Raise := Square * Base
      else
        Raise := Square
    end
  end;

  { The Twice function presupposes that the result of the doubling
    operation is representable as an integer. }

  function Twice (Operand: Integer): Integer;
  begin
    { Assert ((MinInt div 2 <= Operand) and (Operand <= MaxInt div 2)); }
    Twice := 2 * Operand
  end;

  { The Cube function presupposes that its result is representable as an
    integer. }

  function Cube (Operand: Integer): Integer;
  const
    IntegerCubeRootOfMinInt = -1290;
    IntegerCubeRootOfMaxInt = 1290;
  begin
    { Assert ((IntegerCubeRootOfMinInt <= Operand) and
              (Operand <= IntegerCubeRootOfMaxInt)); }
    Cube := Operand * Operand * Operand
  end;

  function Major (LeftOperand, RightOperand: Integer): Integer;
  begin
    if LeftOperand < RightOperand then
      Major := RightOperand
    else
      Major := LeftOperand
  end;

  function Minor (LeftOperand, RightOperand: Integer): Integer;
  begin
    if LeftOperand < RightOperand then
      Minor := LeftOperand
    else
      Minor := RightOperand
  end;

  function Zero (Operand: Integer): Boolean;
  begin
    Zero := (Operand = 0)
  end;

  function Negative (Operand: Integer): Boolean;
  begin
    Negative := (Operand < 0)
  end;

  function Positive (Operand: Integer): Boolean;
  begin
    Positive := (0 < Operand)
  end;

  function Multiple (Candidate: Integer; Unit: Integer): Boolean;
  begin
    { Assert (Unit <> MinInt); }
    if Unit = 0 then
      Multiple := (Candidate = 0)
    else
      Multiple := (Candidate mod Abs (Unit) = 0)
  end;

  function Even (Operand: Integer): Boolean;
  begin
    Even := not Odd (Operand)
  end;

This document is available on the World Wide Web as

http://www.math.grin.edu/~stone/courses/fundamentals/integers.html

created July 24, 1996
last revised August 21, 1996

John David Stone (stone@math.grin.edu)