## SRFI 141: Integer division

### Abstract

This SRFI provides a fairly complete set of integral division and remainder operators.

### Rationale

Most programming languages provide at least one operation for division, and sometimes related operations for computing integral quotients and remainders. (There is at least one (fortunately today defunct) programming language that provides addition, subtraction, and division, with multiplication notably absent, being expressible as division.) Everyone agrees that a pair of operators for computing integral quotients q and remainders r from the division of a numerator (dividend) n by a denominator (divisor) d, should satisfy the relations

• 1. n = dq + r,
• 2. |r| < |d|, and
• 3. q is an integer.

Such a pair of operators will be called a division operator pair. Many programming languages provide only one division operator pair. Some, such as C, leave the semantics unspecified when either or each of the numerator and the denominator is negative. If the numerator and denominator are both integers, then the remainder will also be an integer.

To describe the semantics of a division operator pair, it suffices to define the integer q, from which r can be uniquely derived by the relation

• r = n - dq,

provided that this choice of q induced an r satisfying |r| < |d|. For an extensive discussion of five of the six division operator pairs proposed here, and some broken but standardized operator pairs that fail to satisfy properties (1)-(3), see Raymond T. Boute, "The Euclidean Definition of the Functions DIV and MOD", ACM TOPLAS 14(2), April 1992, pp. 127-144.

Unfortunately, most programming languages give nondescript names such as DIV(IDE), QUOT(IENT), MOD(ULO), and REM(AINDER) to these operations. The language should make clear to programmers what division operations their programs are performing, especially when negative numerators and denominators can arise, but perhaps may not often be tested.

### Related Standards

#### R5RS

The R5RS gives the names quotient and remainder to the truncating division operator pair, and the name modulo to the remainder half of the flooring division operator pair. For all these three procedures in the R5RS, the numerator may be any integer, and the denominator may be any nonzero integer.

#### R6RS

The R6RS gives the names div, mod, and div-and-mod to the Euclidean division operator family, and the names div0, mod0, and div0-and-mod0 to the balanced operator family. For all six of these procedures, the numerator may be any real number, and the denominator may be any nonzero real number. The R5RS procedures are also available in the R5RS compatibility library.

#### R7RS

The truncate and floor families are part of R7RS-small. Three of them are also available under their R5RS names, for backward compatibility. The numerator may be any integer, and the denominator may be any nonzero integer.

#### Common Lisp

Common Lisp provides four integral division functions, floor, ceiling, truncate, and round; and two remainder functions, mod and rem. The division functions comprise both the quotient and remainder of a division operator pair, and return them as two values, of which the latter, the remainder, may be implicitly ignored in Common Lisp. The denominator argument is optional in Common Lisp's integral division functions; if omitted, it is taken to be 1. mod is the remainder half of the flooring division operator pair; rem is the remainder half of the truncating division operator pair. Common Lisp does not provide any part of the Euclidean division operator pair.

For all six of these functions in Common Lisp, the numerator may be any real number, and the denominator may be any nonzero real number. Common Lisp also provides four extra functions ffloor, fceiling, ftruncate, and fround, which differ from their f-less variants only in floating-point contagion rules.

### Specification

For each of six division operator pairs -- floor, ceiling, truncate, round, Euclidean and balanced -- there is a family of three procedures: one, named <operator>/, to compute the division and to return both quotient and remainder as multiple return values; one, named <operator>-quotient, to return only the quotient; and one, named <operator>-remainder, to return only the remainder. Each division operator pair is specified by defining the quotient q in terms of the numerator a and the denominator n. Tacitly the remainder r is as above: r = n - dq.

It is an error if any of the arguments are not integers (exact or inexact). It is also an error to supply zero as a denominator to any of these procedures. If any argument is inexact, the result is inexact, unless the implementation can prove that the inexactness cannot affect the result, as in the case of dividing an exact zero by an inexact number.

floor/ numerator denominatorprocedure
floor-quotient numerator denominatorprocedure
floor-remainder numerator denominatorprocedure
• q = floor(n/d)

Thus r is negative iff d is negative.

ceiling/ numerator denominatorprocedure
ceiling-quotient numerator denominatorprocedure
ceiling-remainder numerator denominatorprocedure
• q = ceiling(n/d)

Thus r is negative iff d is non-negative.

If denominator is the number of units in a block, and <numerator> is some number of units, then (ceiling-quotient numerator denominator) gives the number of blocks needed to cover numerator units. For example, denominator might be the number of bytes in a disk sector, and numerator the number of bytes in a file; then the quotient is the number of disk sectors needed to store the contents of the file. For another example, denominator might be the number of octets in the output of a cryptographic hash function, and numerator the number of octets desired in a key for a symmetric cipher, to be derived using the cryptographic hash function; then the quotient is the number of hash values needed to concatenate to make a key.

truncate/ numerator denominatorprocedure
truncate-quotient numerator denominatorprocedure
truncate-remainder numerator denominatorprocedure
• q = truncate(n/d)

Thus r is negative iff n is negative. However, by any non-unit denominator, the quotient of +1, 0, or -1 is 0; that is, three contiguous numerators by a common denominator share a common quotient. Of the other division operator pairs, only the round pair exhibits this property.

round/ numerator denominatorprocedure
round-quotient numerator denominatorprocedure
round-remainder numerator denominatorprocedure
• q = round(n/d)

The round function rounds to the nearest integer, breaking ties by choosing the nearest even integer. Nothing general can be said about the sign of r. Like the truncate operator pair, the quotient of +1, 0, or -1 by any non-unit denominator is 0, so that three contiguous numerators by a common denominator share a common quotient.

euclidean/ numerator denominatorprocedure
euclidean-quotient numerator denominatorprocedure
euclidean-remainder numerator denominatorprocedure
• If d > 0, q = floor(n/d); if d < 0, q = ceiling(n/d).

This division operator pair satisfies the stronger property

• 0 <= r < |d|,

used often in mathematics. Thus, for example, (euclidean-remainder numerator denominator) is always a valid index into a vector whose length is at least the absolute value of denominator. This division operator pair is so named because it is the subject of the Euclidean division algorithm.

balanced/ numerator denominatorprocedure
balanced-quotient numerator denominatorprocedure
balanced-remainder numerator denominatorprocedure

This division operator pair satisfies the property

• -|d/2| <= r < |d/2|.

When d is a power of 2, say 2^k for some k, this reduces to

• -2^(k - 1) <= r < 2^(k - 1).

Computer scientists will immediately recognize this as the interval of integers representable in two's-complement with k bits.

### Acknowledgements

Thanks to Sudarshan S. Chawathe for catching several significant errors.

### Author

• Taylor Campbell, John Cowan
• Packaged for Chicken Scheme 5 by Sergey Goldgaber

### Repository

https://github.com/diamond-lizard/srfi-141