This site is a static rendering of the Trac instance that was used by R7RS-WG1 for its work on R7RS-small (PDF), which was ratified in 2013. For more information, see Home. For a version of this page that may be more recent, see FixnumsCowan in WG2's repo for R7RS-large.

Fixnums­Cowan

cowan
2016-08-04 22:16:57
4history
source

Fixnums are an implementation-defined subset of the exact integers. Every implementation must define its fixnum range as a closed interval [-2w-1, 2w-1-1], such that w is an integer w greater than or equal to 24. Every mathematical integer within an implementation's fixnum range must correspond to an exact integer that is representable within the implementation. A fixnum is an exact integer whose value lies within this fixnum range.

Fixnum operations perform integer arithmetic on their fixnum arguments. If any argument is not a fixnum, or if the mathematical result is not representable as a fixnum, it is an error. In particular, this means that fixnum operations may return a mathematically incorrect fixnum in these situations without raising an error.

This section uses fx, fx1, fx2, etc., as parameter names for fixnum arguments.

(fixnum? obj)

Returns #t if obj is an exact integer within the fixnum range, #f otherwise.

(fixnum-width)
(least-fixnum)
(greatest-fixnum)

These procedures return w, −2w−1 and 2w−1 − 1: the width, minimum and the maximum value of the fixnum range, respectively.

(fx=? fx1 fx2 fx3 ...)
(fx>? fx1 fx2 fx3 ...)
(fx<? fx1 fx2 fx3 ...)
(fx>=? fx1 fx2 fx3 ...)
(fx<=? fx1 fx2 fx3 ...)

These procedures return #t if their arguments are (respectively): equal, monotonically increasing, monotonically decreasing, monotonically nondecreasing, or monotonically nonincreasing, #f otherwise.

(fxzero? fx)
(fxpositive? fx)
(fxnegative? fx)
(fxodd? fx)
(fxeven? fx)

These numerical predicates test a fixnum for a particular property, returning #t or #f. The five properties tested by these procedures are: whether the number object is zero, greater than zero, less than zero, odd, or even.

(fxmax fx1 fx2 ...)
(fxmin fx1 fx2 ...)

These procedures return the maximum or minimum of their arguments.

(fx+ fx1 fx2)
(fx* fx1 fx2)

These procedures return the sum or product of their arguments.

(fx- fx1 fx2)
(fx- fx)

With two arguments, this procedure returns the difference fx1fx2.

With one argument, this procedure returns the additive inverse of its argument.

(fxfloor/ fx1 fx2)
(fxfloor-quotient fx1 fx2)
(fxfloor-remainder fx1 fx2)
(fxceiling/ fx1 fx2)
(fxceiling-quotient fx1 fx2)
(fxceiling-remainder fx1 fx2)
(fxtruncate/ fx1 fx2)
(fxtruncate-quotient fx1 fx2)
(fxtruncate-remainder fx1 fx2)
(fxround/ fx1 fx2)
(fxround-quotient fx1 fx2)
(fxround-remainder fx1 fx2)
(fxeuclidean/ fx1 fx2)
(fxeuclidean-quotient fx1 fx2)
(fxeuclidean-remainder fx1 fx2)
(fxbalanced/ fx1 fx2)
(fxbalanced-quotient fx1 fx2)
(fxbalanced-remainder fx1 fx2)

It is an error if fx2 is zero. These procedures implement integer division and return the results of the corresponding operations specified in DivisionRiastradh.

(fx+/carry fx1 fx2 fx3)

Returns the two fixnum results of the following computation:

(let* ((s (+ fx1 fx2 fx3))
       (s0 (mod0 s (expt 2 (fixnum-width))))
       (s1 (div0 s (expt 2 (fixnum-width)))))
  (values s0 s1))

(fx-/carry fx1 fx2 fx3)

Returns the two fixnum results of the following computation:

(let* ((d (- fx1 fx2 fx3))
       (d0 (mod0 d (expt 2 (fixnum-width))))
       (d1 (div0 d (expt 2 (fixnum-width)))))
  (values d0 d1))

(fx*/carry fx1 fx2 fx3)

Returns the two fixnum results of the following computation:

(let* ((s (+ (* fx1 fx2fx3))
       (s0 (mod0 s (expt 2 (fixnum-width))))
       (s1 (div0 s (expt 2 (fixnum-width)))))
=  (values s0 s1))

(fxnot fx)

Returns the unique fixnum that is congruent mod 2w to the one's-complement of fx.

(fxand fx1 ...)
(fxior fx1 ...)
(fxxor fx1 ...)

These procedures return the fixnum that is the bit-wise “and”, “inclusive or”, or “exclusive or” of the two's complement representations of their arguments. If they are passed only one argument, they return that argument. If they are passed no arguments, they return the fixnum (either −1 or 0) that acts as identity for the operation.

(fxif fx1 fx2 fx3)

Returns the fixnum that is the bit-wise “if” of the two's complement representations of its arguments, i.e. for each bit, if it is 1 in fx1, the corresponding bit in fx2 becomes the value of the corresponding bit in the result, and if it is 0, the corresponding bit in fx3 becomes the corresponding bit in the value of the result. This is the fixnum result of the following computation:

(fxior (fxand fx1 fx2)
       (fxand (fxnot fx1fx3))

(fxbit-count fx)

If fx is non-negative, this procedure returns the number of 1 bits in the two's complement representation of fx. Otherwise it returns the result of the following computation:

(fxnot (fxbit-count (fxnot ei)))

(fxlength fx)

Returns the number of bits needed to represent fx if it is positive, and the number of bits needed to represent (fxnot fx) if it is negative, which is the fixnum result of the following computation:

(do ((result 0 (+ result 1))
     (bits (if (fxnegative? fx)
               (fxnot fx)
               fx)
           (fxarithmetic-shift-right bits 1)))
    ((fxzero? bits)
     result))

(fxfirst-bit-set fx)

Returns the index of the least significant 1 bit in the two's complement representation of fx. If fx is 0, then −1 is returned.

(fxfirst-bit-set 0)        ⇒  -1
(fxfirst-bit-set 1)        ⇒  0
(fxfirst-bit-set -4)       ⇒  2

(fxbit-set? fx1 fx2)

It is an error if fx2 is negative, or is greater than or equal to (fixnum-width). The fxbit-set? procedure returns #t if the fx2th bit is 1 in the two's complement representation of fx1, and #f otherwise. This is the fixnum result of the following computation:

(not
  (fxzero?


    (fxand fx1
           (fxarithmetic-shift-left 1 fx2))))

(fxcopy-bit fx1 fx2 fx3)

It is an error if fx2 is negative, or is greater than or equal to (fixnum-width). It is also an error if Fx3 is neither 0 nor 1. The fxcopy-bit procedure returns the result of replacing the fx2th bit of fx1 by fx3, which is the result of the following computation:

(let* ((mask (fxarithmetic-shift-left 1 fx2)))
  (fxif mask
        (fxarithmetic-shift-left fx3 fx2)
        fx1))

(fxbit-field fx1 fx2 fx3)

It is an error if either of fx2 and fx3 is negative, or if either is greater than or equal to (fixnum-width). It is also an error if fx2 is greater than fx3. The fxbit-field procedure returns the number represented by the bits at the positions from fx2 (inclusive) to fx3 (exclusive), which is the fixnum result of the following computation:

(let* ((mask (fxnot
              (fxarithmetic-shift-left -1 fx3))))
  (fxarithmetic-shift-right (fxand fx1 mask)
                            fx2))

(fxcopy-bit-field fx1 fx2 fx3 fx4)

It is an error if either fx2 or fx3 or if either is greater than or equal to (fixnum-width). It is also an error if fx2 is greater than fx3. The fxcopy-bit-field procedure returns the result of replacing in fx1 the bits at positions from fx2 (inclusive) to fx3 (exclusive) by the corresponding bits in fx4, which is the fixnum result of the following computation:

(let* ((to    fx1)
       (start fx2)
       (end   fx3)
       (from  fx4)
       (mask1 (fxarithmetic-shift-left -1 start))
       (mask2 (fxnot
               (fxarithmetic-shift-left -1 end)))
       (mask (fxand mask1 mask2)))
  (fxif mask
        (fxarithmetic-shift-left from start)
        to))

(fxarithmetic-shift fx1 fx2)

It is an error if the absolute value of fx2 is greater than or equal to (fixnum-width). If

(floor (* fx1 (expt 2 fx2)))

is a fixnum, then that fixnum is returned; otherwise it is an error.

(fxarithmetic-shift-left fx1 fx2)
(fxarithmetic-shift-right fx1 fx2)

It is an error if fx2 is negative, or is greater than or equal to (fixnum-width). The fxarithmetic-shift-left procedure behaves the same as fxarithmetic-shift, and (fxarithmetic-shift-right fx1 fx2) behaves the same as (fxarithmetic-shift fx1 (fx- fx2)).

(fxrotate-bit-field fx1 fx2 fx3 fx4)

It is an error if any of fx2, fx3, and fx4 are negative, or are greater than or equal to (fixnum-width). It is also an error if Fx2 is greater than fx3, or if Fx4 is greater than or equal to the difference between fx3 and fx2. The fxrotate-bit-field procedure returns the result of cyclically permuting in fx1 the bits at positions from fx2 (inclusive) to fx3 (exclusive) by fx4 bits towards the more significant bits, which is the result of the following computation:

(let* ((n     fx1)
       (start fx2)
       (end   fx3)
       (count fx4)
       (width (fx- end start)))
  (if (fxpositive? width)
      (let* ((count (fxmod count width))
             (field0
               (fxbit-field n start end))
             (field1
               (fxarithmetic-shift-left
                 field0 count))
             (field2
               (fxarithmetic-shift-right
                 field0 (fx- width count)))
             (field (fxior field1 field2)))
        (fxcopy-bit-field n start end field))
      n))

(fxreverse-bit-field fx1 fx2 fx3)

It is an error if either of fx2 and fx3 is negative, or if either is greater than or equal to (fixnum-width). It is also an error if fx2 is greater than fx3. The fxreverse-bit-field procedure returns the fixnum obtained from fx1 by reversing the order of the bits at positions from fx2 (inclusive) to fx3 (exclusive).

(fxreverse-bit-field #b1010010 1 4)    
⇒  88 ; #b1011000

Logical shift

"Logical" right or left shift operations are not well defined on general integers; they are only defined on integers in some finite range. Remember that, in this library, integers are interpreted as *semi-infinite* bit strings that have only a finite number of ones or a finite number of zeroes. "Logical" shifting shifts bit strings of some fixed size. If we shift left, then leftmost bits "fall off" the end (and zeroes shift in on the right). If we shift right, then zeroes shift into the string on the left (and rightmost bits fall off the end). So to define a logical shift operation, *we must specify the size of the window.* Typically this is the width of the underlying machine's register set (e.g., 32 bits). This is blatantly machine-specific & unportable, and clearly not the right thing for Scheme's more machine-independent general integers. For Scheme's integers, arithmetic shift is the right thing. Note that this situation pertains as well in Common Lisp, and Common Lisp does exactly what this SRFI does: arithmetic shift, but no logical shift.

If we were to define a "width 32" or "width 64" or "fixnum" integer datatype, then we could meaningfully define logical shift for these values.