Title

Preliminary Proposal for R6RS Arithmetic

Authors

William D Clinger and Michael Sperber

Status

This SRFI is currently in ``withdrawn'' status. For an explanation of each status that a SRFI can hold, see here. You can access the discussion via the archive of the mailing list.

This SRFI is being submitted by members of the Scheme Language Editor's Committee as part of the R6RS Scheme standardization process. The purpose of such ``R6RS SRFIs'' is to inform the Scheme community of features and design ideas under consideration by the editors and to allow the community to give the editors some direct feedback that will be considered during the design process.

At the end of the discussion period, this SRFI will be withdrawn. When the R6RS specification is finalized, the SRFI may be revised to conform to the R6RS specification and then resubmitted with the intent to finalize it. This procedure aims to avoid the situation where this SRFI is inconsistent with R6RS. An inconsistency between R6RS and this SRFI could confuse some users. Moreover it could pose implementation problems for R6RS compliant Scheme systems that aim to support this SRFI. Note that departures from the SRFI specification by the Scheme Language Editor's Committee may occur due to other design constraints, such as design consistency with other features that are not under discussion as SRFIs.

Table of contents

Abstract

Scheme's arithmetic system was designed to allow a wide variety of implementations. After many years of implementation experience, however, most implementations now fall into a small number of categories, and the benefits of continued experimentation no longer justify the confusion and portability problems that have resulted from giving implementations so much freedom in this area. Moreover, the R5RS generic arithmetic is difficult to implement as efficiently as purely fixnum or purely flonum arithmetic. (Fixnum arithmetic is typically limited-precision integer arithmetic implemented using one or more representations that may be especially efficient on the executing machine; flonum arithmetic is typically limited-precision floating-point arithmetic using one or more representations that may be especially efficient on the executing machine.)

This SRFI is an effort to extend and clarify the R5RS arithmetic to make it more portable, more comprehensive, and enable faster programs.

Furthermore, one of us (Sperber) has argued that Scheme's arithmetic requires radical overhaul. The other (Clinger) agrees that revisions are needed. Whether these revisions qualify as radical is best left to the judgement of individual readers.

This SRFI proposes to revise section 6.2 ("Numbers") of R5RS by:

Issues

Members of the Scheme community are encouraged to express themselves on the following issues:

Revision History

Rationale

Most implementations of Scheme fall into one of the following categories:

Under R5RS, it is hard to write programs whose arithmetic is portable across the above categories, and it is unnecessarily difficult even to write programs whose arithmetic is portable between different implementations in the same category.

The portability problems can most easily be solved by requiring all implementations to support the full numeric tower. To prevent that requirement from making Scheme substantially more difficult to implement, we provide a reference implementation that constructs the full numeric tower from a fixnum/flonum base. To ensure the portability of such reference implementations, the fixnum/flonum base must be described and (at least partially) standardized.

Fixnum/flonum arithmetic is already supported by many systems, mainly for efficiency. Standardization of fixnum/flonum arithmetic would increase the portability of code that uses it, but we cannot standardize the precision of fixnum/flonum arithmetic without making it inefficient on some systems, which would defeat its purpose. We therefore propose to specify the syntax and much of the semantics of fixnum/flonum arithmetic, but to make the precision a parameter of the specification.

Several details of R5RS are inconsistent or incomplete with respect to the IEEE standards for binary floating point arithmetic, which are generally used to implement Scheme's inexact real arithmetic. Furthermore, some details of R5RS make it unnecessarily difficult to implement Scheme's arithmetic efficiently.

This SRFI is incompatible with SRFI 70 [Jaffer 2005] in several ways, including:

Both of the above differences are motivated by closure properties that make it easier for an implementation to generate efficient numerical code.

Moreover, unlike SRFI 70, this alternative operations for integer division div, mod, div0, and mod0, which are slightly more generally applicable and easier to specify. It also does not extend the gcd and lcm to rational numbers.

The sections on Fixnums, Flonums, Exact Arithmetic, and Inexact Arithmetic are new in the SRFI and not in SRFI 70. This SRFI also omits SRFI 70's discussion of infinities and offers its own.

Other, more minor differences with SRFI 70 are highlighted in the hypertext. (The sections mentioned in the previous paragraph are not marked up, as they would be (almost in the case of generic exact arithmetic) completely red.

Specification

We assume that Section 6.2.3 ("Implementation restrictions") of R5RS remains essentially as it stands. The text of this SRFI describes the differences between the proposed additions and changes to R5RS and/or SRFI 70.

The R6RS is expected to describe some kind of library facility, but this SRFI does not rely on that feature. We expect some of the new arithmetic procedures specified by this SRFI will be available only within certain libraries.

Infinities and NaNs

Positive infinity is regarded as a real (but not rational) number, whose value is indeterminate but greater than all rational numbers. Negative infinity is regarded as a real (but not rational) number, whose value is indeterminate but less than all rational numbers.

A NaN is regarded as a real (but not rational) number whose value is so indeterminate that it might represent any real number, including positive or negative infinity, and might even be greater than positive infinity or less than negative infinity.

This SRFI is written as though infinities and NaNs are representable, and specifies many operations with respect to these numbers in ways that are consistent with the IEEE 754 standard for binary floating point arithmetic. Although implementations of Scheme are not required to represent infinities and NaNs, an implementation must report a violation of an implementation restriction whenever it is unable to represent an infinity or NaN as required by the specification below. This requirement also applies to conversions between numbers and external representations, including the reading of program source code.

Note: We expect the R6RS to refine this specification in enough detail so programs can specify exception handlers that recover from these particular violations of implementation restrictions by substituting alternatives values for the unrepresentable infinity or NaN.

External Representations

This SRFI adds the following external representations to Scheme:

Implementations that use binary floating point representations of real numbers should represent x|p using a p-bit significand if practical, or by a greater precision if a p-bit significand is not practical, or by the largest available precision if p or more bits of significand is not practical within the implementation.

Note: The precision of a significand should not be confused with the number of bits used to represent the significand. In the IEEE floating point standards, for example, the significand's most significant bit is implicit in single and double precision but is explicit in extended precision. Whether that bit is implicit or explicit does not affect the mathematical precision. In implementations that use binary floating point, the default precision can be calculated by calling the following procedure:

    (define (precision)
      (do ((n 0 (+ n 1))
           (x 1.0 (/ x 2.0)))
        ((= 1.0 (+ 1.0 x)) n)))

Note: When the underlying floating-point representation is IEEE double precision, the |p suffix should not be omitted for all cases: Denormalized numbers have diminished precision, and therefore should carry a |p suffix with the actual width of the significand.

The number->string procedure is generalized over the R5RS version to support the x|p notation.

To be consistent with this SRFI, the write procedure would be required to write inexact numbers in the external representation produced by number->string with one argument.

Implementations are not required to use floating-point representations, but every implementation is required to designate a subset of its inexact reals as flonums, and to convert certain external representations into flonums.

The R6RS section on the lexical structure of numerical tokens should read as as follows:

The following rules for <num R>, <complex R>, <real R>, <ureal R>, <uinteger R>, and <prefix R> should be replicated for R = 2, 8, 10, and 16. There are no rules for <decimal 2>, <decimal 8>, and <decimal 16>, which means that numbers containing decimal points or exponents or mantissa widths must be in decimal radix.

<num R>  --> <prefix R> <complex R>
<complex R> --> <real R> | <real R> @ <real R>
    | <real R> + <ureal R> i | <real R> - <ureal R> i
    | <real R> + i | <real R> - i
    | + <ureal R> i | - <ureal R> i | + i | - i
<real R> --> <sign> <ureal R>
<ureal R>  -->  <uinteger R>
    |  <uinteger R> / <uinteger R>
    |  <decimal R> <mantissa width>
    |  inf.0 | nan.0
<decimal 10>  -->  <uinteger 10> <suffix>
    |  . <digit 10>+ #* <suffix>
    |  <digit 10>+ . <digit 10>* #* <suffix>
    |  <digit 10>+ #* . #* <suffix>
<uinteger R>  -->  <digit R>+ #*
<prefix R>  -->  <radix R> <exactness>
    |  <exactness> <radix R>

<suffix>  -->  <empty>
    |  <exponent marker> <sign> <digit 10>+
<exponent marker>  -->  e  |  s  |  f  |  d  |  l
<mantissa width> -> <empty>
    | | <digit 10>+
<sign>  -->  <empty>  |  +  |  -
<exactness>  -->  <empty>  |  #i  |  #e
<radix 2>  -->  #b
<radix 8>  -->  #o
<radix 10>  -->  <empty>  |  #d
<radix 16>  -->  #x
<digit 2>  -->  0  |  1
<digit 8>  -->  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7
<digit 10>  -->  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9
<digit 16>  -->  <digit 10>  |  a  |  b  |  c  |  d  |  e  |  f

If a <decimal 10> does not contain a non-empty <mantissa width> and does not contain one of the exponent markers s, f, d, or l, but does contain a decimal point or the exponent marker e, then it is an external representation for a flonum. Furthermore inf.0, +inf.0, -inf.0, nan.0, +nan.0, and -nan.0 are external representations for flonums. Some or all of the other external representations for inexact reals may also represent flonums, but that is not required by this SRFI.

If a <decimal 10> contains a non-empty <mantissa width> or one of the exponent markers s, f, d, or l, then it represents an inexact number, but does not necessarily represent a flonum.

Safe and Unsafe Mode

The R6RS is expected to require implementations to provide a "safe" mode in which specified exceptional situations must be detected and handled in standard ways, while allowing (but not requiring) implementations to support an "unsafe" mode that is not guaranteed to detect those situations or to handle them in the standard way even when detected. These modes may interact with many features of Scheme, but are particularly relevant to the fixnum and flonum operations. In safe mode, these operations must check that their arguments are actually fixnums or flonums respectively, or perform possible additional checking as required by the specifications of the operations. In unsafe mode, these operations are not required to perform such checking. This distinction allows programmers to request more efficient numerical code for those operations at the cost of less effective run-time checking.

This SRFI uses the phrase "all bets are off" to describe situations in which the behavior of a procedure is unspecified when executing in unsafe mode. Specifically, a procedure call for which all bets are off is free to crash the system.

Equivalence of Objects

The R6RS specification of eqv? for numbers should be changed as follows.

The eqv? procedure returns #t if:

The eqv? procedure returns #f if:

Numerical Type Predicates

The following description is a revised form of the description given in SRFI 70. Changes from SRFI 70 are highlighted in red.

procedure: number? obj
procedure: complex? obj
procedure: real? obj
procedure: rational? obj
procedure: integer? obj

These numerical type predicates can be applied to any kind of argument, including non-numbers. They return #t if the object is of the named type, and otherwise they return #f. In general, if a type predicate is true of a number then all higher type predicates are also true of that number. Consequently, if a type predicate is false of a number, then all lower type predicates are also false of that number.

If z is an inexact a complex number, then `(real? z)' is true if and only if `(zero? (imag-part z))' and `(exact? (imag-part z))' are both true.

If x is a real number, then `(rational? x)' is true if and only if there exist exact integers k1 and k2 such that `(= x (/ k1 k2))' and `(= (numerator x) k1)' and `(= (denominator x) k2)' are all true. Thus infinities and NaNs are not rational numbers.

If x is an inexact real number, then `(integer? x)' is true if and only if
    (and (finite? x) (= x (round x)))
If q is a rational number, then `(integer? q)' is true if and only if `(= (denominator q) 1)' is true. If q is not a rational number, then `(integer? q)' is false.
(complex? 3+4i)                        ==>  #t
(complex? 3)                           ==>  #t
(real? 3)                              ==>  #t
(real? -2.5+0.0i)                      ==>  #f
(real? -2.5+0i)                        ==>  #t
(real? -2.5)                           ==>  #t
(real? #e1e10)                         ==>  #t
(rational? 6/10)                       ==>  #t
(rational? 6/3)                        ==>  #t
(rational? 2)                          ==>  #t
(integer? 3+0i)                        ==>  #t
(integer? 3.0)                         ==>  #t
(integer? 8/4)                         ==>  #t

(number? +nan.0)                       ==>  #t
(complex? +nan.0)                      ==>  #t
(real? +nan.0)                         ==>  #t
(rational? +nan.0)                     ==>  #f
(complex? +inf.0)                      ==>  #t
(real? -inf.0)                         ==>  #t
(rational? -inf.0)                     ==>  #f
(integer? -inf.0)                      ==>  #f

Note: In many implementations the rational? procedure will be the same as real?, and the complex? procedure will be the same as number?, but unusual implementations may be able to represent some irrational numbers exactly or may extend the number system to support some kind of non-complex numbers.

Note: The behavior of these type predicates on inexact numbers is unreliable, because any inaccuracy may affect the result.

procedure: real-valued? obj
procedure: rational-valued? obj
procedure: integer-valued? obj

These numerical type predicates can be applied to any kind of argument, including non-numbers. They return #t if the object is a number and is equal in the sense of = to some object of the named type, and otherwise they return #f.

(real-valued? +nan.0)                  ==>  #f
(real-valued? -inf.0)                  ==>  #t
(real-valued? 3)                       ==>  #t
(real-valued? -2.5+0.0i)               ==>  #t
(real-valued? -2.5+0i)                 ==>  #t
(real-valued? -2.5)                    ==>  #t
(real-valued? #e1e10)                  ==>  #t

(rational-valued? +nan.0)              ==>  #f
(rational-valued? -inf.0)              ==>  #f
(rational-valued? 6/10)                ==>  #t
(rational-valued? 6/10+0.0i)           ==>  #t
(rational-valued? 6/10+0i)             ==>  #t
(rational-valued? 6/3)                 ==>  #t

(integer-valued? 3+0i)                 ==>  #t
(integer-valued? 3+0.0i)               ==>  #t
(integer-valued? 3.0)                  ==>  #t
(integer-valued? 3.0+0.0i)             ==>  #t
(integer-valued? 8/4)                  ==>  #t

Note: The behavior of these type predicates on inexact numbers is unreliable, because any inaccuracy may affect the result.

procedure: exact? z
procedure: inexact? z

These numerical predicates provide tests for the exactness of a quantity. For any Scheme number, precisely one of these predicates is true.

(exact? 5)                   ==>  #t
(inexact? +inf.0)            ==>  #t

Generic Conversions

procedure: exact->inexact z
procedure: inexact->exact z

Exact->inexact returns an inexact representation of z. If inexact numbers of the appropriate type have bounded precision, then the value returned is an inexact number that is nearest to the argument. If an exact argument has no reasonably close inexact equivalent, then a violation of an implementation restriction may be reported.

Inexact->exact returns an exact representation of z. The value returned is the exact number that is numerically closest to the argument; in most cases, the result of this procedure should be numerically equal to its argument. If an inexact argument has no reasonably close exact equivalent, then a violation of an implementation restriction may be reported.

These procedures implement the natural one-to-one correspondence between exact and inexact integers throughout an implementation-dependent range.

Exact->inexact and inexact->exact are idempotent.

procedure: real->flonum x

Real->flonum returns a flonum representation of x, which must be a real number. The value returned is a flonum that is numerically closest to the argument.

Rationale: The flonums are a subset of the inexact reals, but may be a proper subset. The real->flonum procedure converts an arbitrary real to the flonum type required by flonum-specific procedures.

Note: If flonums are represented in binary floating point, then implementations are strongly encouraged to break ties by preferring the floating point representation whose least significant bit is zero.

Numerical Input and Output

procedure: number->string z
procedure: number->string z radix
procedure: number->string z radix precision

Radix must be an exact integer, either 2, 8, 10, or 16. If omitted, radix defaults to 10. If a precision is specified, then z must be an inexact complex number, precision must be an exact positive integer, and the radix must be 10. The procedure number->string takes a number and a radix and returns as a string an external representation of the given number in the given radix such that

    (let ((number number)
          (radix radix))
      (eqv? number
            (string->number (number->string number
                                            radix)
                            radix)))

is true. It is an error if no possible result makes this expression true.

If a precision is specified, then the representations of the inexact real components of the result, unless they are infinite or NaN, specify an explicit <mantissa width> p, and p is the least pprecision for which the above expression is true.

If z is inexact, the radix is 10, and the above expression and condition can be satisfied by a result that contains a decimal point, then the result contains a decimal point and is expressed using the minimum number of digits (exclusive of exponent, trailing zeroes, and mantissa width) needed to make the above expression and condition true [Burger, Dybvig 1996; Clinger 1990]; otherwise the format of the result is unspecified.

The result returned by number->string never contains an explicit radix prefix.

Note: The error case can occur only when z is not a complex number or is a complex number with a non-rational real or imaginary part.

Rationale: If z is an inexact number represented using binary floating point, and the radix is 10, then the above expression is normally satisfied by a result containing a decimal point. The unspecified case allows for infinities, NaNs, and representations other than binary floating point.

procedure: string->number string
procedure: string->number string radix

Returns a number of the maximally precise representation expressed by the given string. Radix must be an exact integer, either 2, 8, 10, or 16. If supplied, radix is a default radix that may be overridden by an explicit radix prefix in string (e.g. "#o177"). If radix is not supplied, then the default radix is 10. If string is not a syntactically valid notation for a number, then string->number returns #f.

(string->number "100")                 ==>  100
(string->number "100" 16)              ==>  256
(string->number "1e2")                 ==>  100.0
(string->number "15##")                ==>  1500.0
(string->number "+inf.0")              ==>  +inf.0
(string->number "-inf.0")              ==>  -inf.0
(string->number "+nan.0")              ==>  +nan.0

Note: The domain of string->number may be restricted by implementations in the following ways. String->number is permitted to return #f whenever string contains an explicit radix prefix. If all numbers supported by an implementation are real, then string->number is permitted to return #f whenever string uses the polar or rectangular notations for complex numbers. If all numbers are integers, then string->number may return #f whenever the fractional notation is used. If all numbers are exact, then string->number may return #f whenever an exponent marker or explicit exactness prefix is used, or if a # appears in place of a digit. If all inexact numbers are integers, then string->number may return #f whenever a decimal point is used. An implementation may return #f for "+nan.0".

Integer Division

For various kinds of arithmetic (fixnum, flonum, exact, inexact, and generic), this SRFI provides operations for performing integer division. They rely on mathematical operations div, mod, div0, and mod0, that are defined as follows:

div, mod, div0, and mod0 each accept two real numbers x1 and x2 as operands, where x2 must be nonzero.

div returns an integer, mod returns a real. Their results are specified by

x1 div x2         ==> nd
x1 mod x2         ==> xm
where
  1. x1 = nd * x2 + xm
  2. 0 <= xm < |x2|

Examples:

5 div 3    =  1
5 div -3   =  -1

5 mod 3    =  2
5 mod -3   =  2

Div0 and mod0 are like div and mod, except the result of mod0 lies within a half-open interval centered on zero. The results are specified by

x1 div0 x2        ==> nd
x1 mod0 x2        ==> xm
where:
  1. x1 = nd * x2 + xm
  2. -|x2/2| ≤ xm < |x2/2|

Examples:

5 div 3    =  2
5 div -3   =  -2

5 mod 3    =  -1
5 mod -3   =  -1

Rationale: The half-open symmetry about zero is convenient for some purposes.

Fixnums

A subrange of the exact integers is designated as the set of fixnums. Conversely, a fixnum is an exact integer whose value lies within this fixnum range.

Every implementation must define its fixnum range as a closed interval [-2w-1, 2w-1 - 1] such that w is a a (mathematical) integer w ≥ 24. Every mathematical integer within an implementation's fixnum range must correspond to an exact integer that is representable within the implementation.

This section specifies two kinds of operations on fixnums. Operations whose names begin with fixnum perform arithmetic modulo 2w. Operations whose names begin with fx perform integer arithmetic on their fixnum arguments, but signal an error if the result is not a fixnum.

Rationale: The operations whose names begin with fixnum implement arithmetic on a quotient ring of the integers, but their results will not be the same in every implementation because the particular ring is parameterized by w. The operations whose names begin with fx do not have as nice a closure property, and the arguments that cause them to signal an error will not be the same in every implementation, but any results they return without signalling an error will be the same in all implementations.

Some operations (e.g. fixnum< and fx<) behave the same in both sets.

Rationale: Duplication of names reduces bias toward either set, and saves programmers from having to remember which names are supplied.

We will use fx, fx1 and fx2 as metavariables that range over fixnums.

If an argument to the following procedures that corresponds to a fixnum metavariable is not actually a fixnum, then these procedures signal an error, unless the implementation is running in unsafe mode, in which case all bets are off.

procedure: fixnum? obj

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

procedure: fixnum-width
procedure: least-fixnum
procedure: greatest-fixnum

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

procedure: fixnum= fx1 fx2 fx3 ...
procedure: fixnum> fx1 fx2 fx3 ...
procedure: fixnum< fx1 fx2 fx3 ...
procedure: fixnum>= fx1 fx2 fx3 ...
procedure: fixnum<= fx1 fx2 fx3 ...
procedure: fx= fx1 fx2 fx3 ...
procedure: fx> fx1 fx2 fx3 ...
procedure: fx< fx1 fx2 fx3 ...
procedure: fx>= fx1 fx2 fx3 ...
procedure: 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.

procedure: fixnum-zero? fx
procedure: fixnum-positive? fx
procedure: fixnum-negative? fx
procedure: fixnum-odd? fx
procedure: fixnum-even? fx
procedure: fxzero? fx
procedure: fxpositive? fx
procedure: fxnegative? fx
procedure: fxodd? fx
procedure: 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 is zero, greater than zero, less than zero, odd, or even.

procedure: fixnum-max fx1 fx2 ...
procedure: fixnum-min fx1 fx2 ...
procedure: fxmax fx1 fx2 ...
procedure: fxmin fx1 fx2 ...

These procedures return the maximum or minimum of their arguments.

procedure: fixnum+ fx1 ...
procedure: fixnum* fx1 ...

These procedures return the unique fixnum that is congruent mod 2w to the sum or product of their arguments.

procedure: fx+ fx1 fx2
procedure: fx* fx1 fx2

These procedures return the sum or product of their arguments, provided that sum or product is a fixnum. An error is signalled if that sum or product is not a fixnum, unless the implementation is running in unsafe mode, in which case all bets are off.

Rationale: These procedures are restricted to two arguments because their generalizations to three or more arguments would require precision proportional to the number of arguments.

procedure: fixnum- fx1 fx2 ...
procedure: fixnum- fx

With two or more arguments, this procedure returns the unique fixnum that is congruent mod 2w to the difference of its arguments, associating to the left. With one argument, however, it returns the the unique fixnum that is congruent mod 2w to the additive inverse of its argument.

procedure: fx- fx1 fx2
procedure: fx- fx

With two arguments, this procedure returns the difference of its arguments, provided that difference is a fixnum.

With one argument, this procedure returns the additive inverse of its argument, provided that integer is a fixnum.

An error is signalled if the mathematically correct result of this procedure is not a fixnum.

(fx- (least-fixnum))  ==>  error

procedure: fixnum-div+mod fx1 fx2
procedure: fixnum-div fx1 fx2
procedure: fixnum-mod fx1 fx2
procedure: fixnum-div0+mod0 fx1 fx2
procedure: fixnum-div0 fx1 fx2
procedure: fixnum-mod0 fx1 fx2

These procedures implement number-theoretic integer division modulo 2w. Each procedure returns the unique fixnum(s) congruent modulo 2w to the result(s) specified in the section on Integer Division. An error is signalled if the second argument is zero, unless the implementation is running in unsafe mode, in which case all bets are off.

(fixnum-div x1 x2)         ==> x1 div x2
(fixnum-mod x1 x2)         ==> x1 mod x2
(fixnum-div+mod x1 x2)     ==> x1 div x2, x1 mod x2 ; two return values
(fixnum-div0 x1 x2)        ==> x1 div0 x2
(fixnum-mod0 x1 x2)        ==> x1 mod0 x2
(fixnum-div0+mod0 x1 x2)   ==> x1 div0 x2, x1 mod0 x2 ; two return values

procedure: fxdiv+mod fx1 fx2
procedure: fxdiv fx1 fx2
procedure: fxmod fx1 fx2
procedure: fxdiv0+mod0 fx1 fx2
procedure: fxdiv0 fx1 fx2
procedure: fxmod0 fx1 fx2

These procedures implement number-theoretic integer division and return the results of the corresponding mathematical operations specified in the section on Integer Division. An error is signalled if a result specified by that section is not a fixnum, unless the implementation is running in unsafe mode, in which case all bets are off. An error is signalled if the second argument is zero, unless the implementation is running in unsafe mode, in which case all bets are off.

(fxdiv x1 x2)         ==> x1 div x2
(fxmod x1 x2)         ==> x1 mod x2
(fxdiv+mod x1 x2)     ==> x1 div x2, x1 mod x2 ; two return values
(fxdiv0 x1 x2)        ==> x1 div0 x2
(fxmod0 x1 x2)        ==> x1 mod0 x2
(fxdiv0+mod0 x1 x2)   ==> x1 div0 x2, x1 mod0 x2 ; two return values

procedure: fixnum+/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))

Note: The results returned by the fixnum+/carry, fixnum-/carry, and fixnum*/carry procedures depend upon the precision w, so there are no fx equivalents to these procedures.

procedure: fixnum-/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))

procedure: fixnum*/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))

procedure: fixnum-not fx
procedure: fxnot fx

Both of these procedures return the unique fixnum that is congruent mod 2w to the one's-complement of their argument.

procedure: fixnum-and fx1 ...
procedure: fixnum-ior fx1 ...
procedure: fixnum-xor fx1 ...
procedure: fxand fx1 ...
procedure: fxior fx1 ...
procedure: 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.

procedure: fixnum-if fx1 fx2 fx3
procedure: fxif fx1 fx2 fx3

These procedures return the fixnum result of the following computation:

    (fixnum-ior (fixnum-and fx1 fx2)
                (fixnum-and (fixnum-not fx1) fx3))

procedure: fixnum-bit-count fx
procedure: fxbit-count fx

If the argument fx is non-negative, these procedures return the number of 1 bits in the two's complement representation of fx. Otherwise they return the number of 0 bits in the two's complement representation of fx.

procedure: fixnum-length fx
procedure: fxlength fx

These procedures return the fixnum result of the following computation:

    (do ((result 0 (+ result 1))
         (bits (if (fixnum-negative? fx)
                   (fixnum- fx)
                   fx)
               (fixnum-logical-shift-right bits 1)))
        ((fixnum-zero? bits)
         result))

procedure: fixnum-first-bit-set fx
procedure: fxfirst-bit-set fx

These procedures return the index of the least significant 1 bit in the two's complement representation of their argument. If the argument is 0, then -1 is returned.

(fixnum-first-bit-set 0)        ==>  -1
(fixnum-first-bit-set 1)        ==>  0
(fixnum-first-bit-set -4)       ==>  2

procedure: fixnum-bit-set? fx1 fx2

If the second argument is non-negative, this procedure returns the fixnum result of the following computation:

    (not (fixnum-zero?
          (fixnum-and fx1
                      (fixnum-logical-shift-left 1 fx2))))
If the second argument is negative, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off.

procedure: fxbit-set? fx fx2

If the first argument is negative, or greater than or equal to (fixnum-width), then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off. Otherwise this procedure returns the same result returned by fixnum-bit-set?.

procedure: fixnum-copy-bit fx1 fx2 fx3

If the second argument is non-negative, then this procedure returns the fixnum result of the following computation:

    (let* ((mask (fixnum-logical-shift-left 1 fx2)))
      (fixnum-if mask
                 (fixnum-logical-shift-left fx3 fx2)
                 fx2))
If the second argument is negative, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off.

procedure: fxcopy-bit fx1 fx2 fx3

If the second argument is negative, or greater than or equal to (fixnum-width), or the third argument is anything other than 0 or 1, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off. Otherwise this procedure returns the same result returned by fixnum-copy-bit.

procedure: fixnum-bit-field fx1 fx2 fx3

If the second and third arguments are non-negative, this procedure returns the fixnum result of the following computation:

    (let* ((mask (fixnum-not
                  (fixnum-logical-shift-left -1 fx3))))
      (fixnum-logical-shift-right (fixnum-and fx1 mask)
                                  fx2))
If the second or third argument is negative, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off.

procedure: fxbit-field fx1 fx2 fx3

If the second or third argument is negative, or greater than (fixnum-width), or the second argument is greater than the third, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off. Otherwise this procedure returns the same result returned by fixnum-bit-field.

procedure: fixnum-copy-bit-field fx1 fx2 fx3 fx4

If the second and third arguments are non-negative, this procedure returns the fixnum result of the following computation:

    (let* ((to    fx1)
           (start fx2)
           (end   fx3)
           (from  fx4)
           (mask1 (fixnum-logical-shift-left -1 start))
           (mask2 (fixnum-not
                   (fixnum-logical-shift-left -1 end)))
           (mask (fixnum-and mask1 mask2)))
      (fixnum-if mask from to))
If the second or third argument is negative, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off.

procedure: fxcopy-bit-field fx1 fx2 fx3 fx4

If the second or third argument is negative, or greater than (fixnum-width), or the second argument is greater than the third, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off. Otherwise this procedure returns the same result returned by fixnum-copy-bit-field.

procedure: fixnum-arithmetic-shift fx1 fx2

Returns the unique fixnum that is congruent mod 2w to the result of the following computation:

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

procedure: fxarithmetic-shift fx1 fx2

If the absolute value of the second argument is greater than or equal to (fixnum-width), then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off. If

    (exact-floor (* fx1 (expt 2 fx2)))
is a fixnum, then that fixnum is returned. Otherwise an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off.

procedure: fixnum-arithmetic-shift-left fx1 fx2
procedure: fixnum-arithmetic-shift-right fx1 fx2

If the second argument is non-negative, then fixnum-arithmetic-shift-left returns the same result as fixnum-arithmetic-shift, and (fixnum-arithmetic-shift-right fx1 fx2) returns the same result as (fixnum-arithmetic-shift fx1 (fixnum- fx2)). If the second argument is negative, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off.

procedure: fxarithmetic-shift-left fx1 fx2
procedure: fxarithmetic-shift-right fx1 fx2

If the second argument is non-negative, then fxarithmetic-shift-left behaves the same as fxarithmetic-shift, and (fxarithmetic-shift-right fx1 fx2) behaves the same as (fxarithmetic-shift fx1 (fixnum- fx2)). If the second argument is negative, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off.

procedure: fixnum-logical-shift-left fx1 fx2

This procedure behaves the same as fixnum-arithmetic-shift-left.

procedure: fixnum-logical-shift-right fx1 fx2

If the second argument is non-negative, then this procedure returns the result of the following computation:

    (let* ((n       fx1)
           (shift   fx2)
           (shifted (fixnum-arithmetic-shift-right n shift)))
      (let* ((mask-width (fixnum- (fixnum-width)
                                  (fixnum-mod shift (fixnum-width))))
             (mask (fixnum-not
                    (fixnum-logical-shift-left -1 mask-width))))
        (fixnum-and shifted mask))
If the second argument is negative, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off.

Note: The results of fixnum-logical-shift-left and fixnum-logical-shift-left can depend upon the precision w, so they have no fx equivalents.

procedure: fixnum-rotate-bit-field fx1 fx2 fx3 fx4

If the second, third, and fourth arguments are non-negative, this procedure returns the result of the following computation:

    (let* ((n     fx1)
           (start fx2)
           (end   fx3)
           (count fx4)
           (width (fixnum- end start)))
      (if (fixnum-positive? width)
          (let* ((count (fixnum-mod count width))
                 (field0 (fixnum-bit-field n start end))
                 (field1 (fixnum-logical-shift-left field0 count))
                 (field2 (fixnum-logical-shift-right field0
                                                     (fixnum- width count)))
                 (field (fixnum-ior field1 field2)))
            (fixnum-copy-bit-field n field start end))
          n))

procedure: fxrotate-bit-field fx1 fx2 fx3 fx4

If the second, third, or fourth argument is negative, or greater than (fixnum-width), or the fourth argument is greater than or equal to the difference between the third and second arguments, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off. Otherwise this procedure returns the same result as the fixnum-rotate-bit-field procedure.

procedure: fixnum-reverse-bit-field fx1 fx2 fx3

Returns the fixnum obtained from the first argument by reversing the bit field specified by the second and third arguments.

(fixnum-reverse-bit-field #b1010010 1 4)    ==>  88 ; #b1011000
(fixnum-reverse-bit-field #b1010010 91 -4)  ==>  82 ; #b1010010

procedure: fxreverse-bit-field fx1 fx2 fx3

If the second or third argument is negative, or greater than (fixnum-width), or the second argument is greater than the third, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off. Otherwise this procedure returns the same result as the fixnum-reverse-bit-field procedure.

Flonums

Implementations are not required to use floating-point representations, but every implementation is required to designate a subset of its inexact reals as flonums, and to convert certain external representations into flonums. The flonums must be closed under the flonum operations described in this section.

We will use fl, fl1 and fl2 as metavariables that range over flonums, and ifl, ifl1 and ifl2 as metavariables that range over integer-valued flonums, i.e. flonums for which the integer-valued? predicate is true.

If an argument to the following procedures that corresponds to a (integral) flonum metavariable is not actually a (integral) flonum, then these procedures signal an error, unless the implementation is running in unsafe mode, in which case all bets are off.

procedure: flonum? obj

This returns #t if obj is a flonum, and otherwise returns #f.

procedure: fl= fl1 fl2 fl3 ...
procedure: fl< fl1 fl2 fl3 ...
procedure: fl<= fl1 fl2 fl3 ...
procedure: fl> fl1 fl2 fl3 ...
procedure: fl>= fl1 fl2 fl3 ...

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

(fl= +inf.0 +inf.0)           ==>  #t
(fl= -inf.0 +inf.0)           ==>  #f
(fl= -inf.0 -inf.0)           ==>  #t
(fl= 0.0 -0.0)                ==>  #t
(fl< 0.0 -0.0)                ==>  #f
(fl= +nan.0 fl)               ==>  #f
(fl< +nan.0 fl)               ==>  #f

procedure: flinteger? fl
procedure: flzero? fl
procedure: flpositive? fl
procedure: flnegative? fl
procedure: flodd? ifl
procedure: fleven? ifl
procedure: flfinite? fl
procedure: flinfinite? fl
procedure: flnan? fl

These numerical predicates test a flonum for a particular property, returning #t or #f. Flinteger? tests it if the number is an integer, flzero? tests if it is fl= to zero, flpositive? tests if it is greater than zero, flnegative? tests if it is less than zero, flodd? tests if it is odd, fleven? tests if it is even, flfinite? tests if it is not an infinity and not a NaN, flinfinite? tests if it is an infinity, flnan? tests if it is a NaN.

(flnegative? -0.0)   ==> #f
(flfinite? +inf.0)   ==> #f
(flfinite? 5.0)      ==> #t
(flinfinite? 5.0)    ==> #f
(flinfinite? +inf.0) ==> #t

Note: `(flnegative? -0.0)' must return #f, else it would lose the correspondence with (fl< -0.0 0.0), which is #f according to the IEEE standards.

procedure: flmax fl1 fl2 ...
procedure: flmin fl1 fl2 ...

These procedures return the maximum or minimum of their arguments.

procedure: fl+ fl1 ...
procedure: fl* fl1 ...

These procedures return the flonum sum or product of their flonum arguments. In general, they should return the flonum that best approximates the mathematical sum or product. (For implementations that represent flonums as IEEE binary floating point numbers, the meaning of "best" is reasonably well-defined by the IEEE standards.)

(fl+ +inf.0 -inf.0)      ==>  +nan.0
(fl+ +nan.0 fl)          ==>  +nan.0
(fl* +nan.0 fl)          ==>  +nan.0

procedure: fl- fl1 fl2 ...
procedure: fl- fl
procedure: fl/ fl1 fl2 ...
procedure: fl/ fl

With two or more arguments, these procedures return the flonum difference or quotient of their flonum arguments, associating to the left. With one argument, however, they return the additive or multiplicative flonum inverse of their argument. In general, they should return the flonum that best approximates the mathematical difference or quotient. (For implementations that represent flonums as IEEE binary floating point numbers, the meaning of "best" is reasonably well-defined by the IEEE standards.)

(fl- +inf.0 +inf.0)      ==>  +nan.0

For undefined quotients, fl/ behaves as specified by the IEEE standards:

(fl/ 1.0 0.0)  ==> +inf.0
(fl/ -1.0 0.0) ==> -inf.0
(fl/ 0.0 0.0)  ==> +nan.0

procedure: flabs fl

This returns the absolute value of its argument.

procedure: fldiv+mod fl1 fl2
procedure: fldiv fl1 fl2
procedure: flmod fl1 fl2
procedure: fldiv0+mod0 fl1 fl2
procedure: fldiv0 fl1 fl2
procedure: flmod0 fl1 fl2

These procedures implement number-theoretic integer division and return the results of the corresponding mathematical operations specified in the section on Integer Division. For zero divisors, these procedures may return a NaN or some meaningless flonum.

(fldiv x1 x2)         ==> x1 div x2
(flmod x1 x2)         ==> x1 mod x2
(fldiv+mod x1 x2)     ==> x1 div x2, x1 mod x2 ; two return values
(fldiv0 x1 x2)        ==> x1 div0 x2
(flmod0 x1 x2)        ==> x1 mod0 x2
(fldiv0+mod0 x1 x2)   ==> x1 div0 x2, x1 mod0 x2 ; two return values

procedure: flnumerator fl
procedure: fldenominator fl

These procedures return the numerator or denominator of their argument as a flonum; the result is computed as if the argument was represented as a fraction in lowest terms. The denominator is always positive. The denominator of 0 is defined to be 1.

(flnumerator +inf.0)           ==>  +inf.0
(flnumerator -inf.0)           ==>  -inf.0
(fldenominator +inf.0)         ==>  1.0
(fldenominator -inf.0)         ==>  1.0
(flnumerator 0.75)             ==>  3.0 ; example
(fldenominator 0.75)           ==>  4.0 ; example
The following behavior is strongly recommended but not required by R6RS:
(flnumerator -0.0)             ==> -0.0

procedure: flfloor fl
procedure: flceiling fl
procedure: fltruncate fl
procedure: flround fl

These procedures return integral flonums for flonum arguments that are not infinities or NaNs. For such arguments, flfloor returns the largest integral flonum not larger than fl. Flceiling returns the smallest integral flonum not smaller than fl. Fltruncate returns the integral flonum closest to fl whose absolute value is not larger than the absolute value of fl. Flround returns the closest integral flonum to fl, rounding to even when fl is halfway between two integers.

Rationale: Flround rounds to even for consistency with the default rounding mode specified by the IEEE floating point standard.

Although infinities and NaNs are not integers, these procedures return an infinity when given an infinity as an argument, and a NaN when given a NaN:

(flfloor +inf.0)                       ==>  +inf.0
(flceiling -inf.0)                     ==>  -inf.0
(fltruncate +nan.0)                    ==>  +nan.0

procedure: flexp fl
procedure: fllog fl
procedure: flsin fl
procedure: flcos fl
procedure: fltan fl
procedure: flasin fl
procedure: flatan fl
procedure: flatan fl1 fl2

These procedures compute the usual transcendental functions. Fllog computes the natural logarithm of fl (not the base ten logarithm). Flasin, flacos, and flatan compute arcsine (sin-1), arccosine (cos-1), and arctangent (tan-1), respectively. `(flatan fl1 fl2)' computes the arc tangent of fl1/fl2. The range of flatan lies between -pi/2 and pi/2, both inclusive if -0.0 is distinguished, both exclusive otherwise.

In general, the mathematical functions log, arcsine, arccosine, and arctangent are multiply defined. The value of log z is defined to be the one whose imaginary part lies in the range from -pi (exclusive) to pi (inclusive). With log defined this way, the values of sin-1 fl, cos-1 z, and tan-1 z are according to the following formulae:

sin-1 z = -i log (i z + sqrt(1 - z2))

cos-1 z = pi / 2 - sin-1 z

tan-1 z = (log (1 + i z) - log (1 - i z)) / (2 i)

If the function has a real-valued limit as its argument tends toward positive infinity, then that is the value returned by the function applied to +inf.0. If the function has a real-valued limit as its argument tends toward negative infinity, then that is the value returned by the function applied to -inf.0.

In the event that these formulae do not yield a real result for the given arguments, the result may be a NaN, or may be some meaningless flonum.

Implementations that use IEEE binary floating point arithmetic are encouraged to follow the relevant standards for these procedures.

Specifically, the range of `(flatan x y)' is as in the following table. The asterisk (*) indicates that the entry applies to implementations that distinguish minus zero.

y Condition x Condition Range of result
y = 0.0 x > 0.0 0.0
* y = +0.0 x > 0.0 +0.0
* y = -0.0 x > 0.0 -0.0
y > 0.0 x > 0.0 0.0 < result< pi/2
y > 0.0 x = 0.0 pi/2
y > 0.0 x < 0.0 pi/2 < result< pi
y = 0.0 x < 0 pi
* y = +0.0 x < 0.0 +pi
* y = -0.0 x < 0.0 -pi
y < 0.0 x < 0.0 -pi< result< -pi/2
y < 0.0 x = 0.0 -pi/2
y < 0.0 x > 0.0 -pi/2 < result< 0.0
y = 0.0 x = 0.0 undefined
* y = +0.0 x = +0.0 +0.0
* y = -0.0 x = +0.0 -0.0
* y = +0.0 x = -0.0 +pi
* y = -0.0 x = -0.0 -pi

The above specification follows the branch cut specification of Common Lisp in [Pitman 1996], and [Steele 1990], which in turn cites [Penfield 1981]; refer to these sources for more detailed discussion of branch cuts, boundary conditions, and implementation of these functions.

(flexp +inf.0)                ==> +inf.0
(flexp -inf.0)                ==> 0.0
(fllog +inf.0)                ==> +inf.0
(fllog 0.0)                   ==> -inf.0
(fllog -0.0)                  ==> unspecified ; if -0.0 is distinguished
(fllog -inf.0)                ==> +nan.0
(flatan -inf.0)               ==> -1.5707963267948965 ; approximately
(flatan +inf.0)               ==> 1.5707963267948965  ; approximately

procedure: flsqrt fl

Returns the principal square root of z. For a negative argument, the result may be a NaN, or may be some meaningless flonum.

(flsqrt +inf.0)               ==>  +inf.0

procedure: flexpt fl1 fl2

Returns fl1 raised to the power fl2. For nonzero fl1

fl1fl2 = ez2 log z1

0fl is 1 if z = 0, and 0 if fl is positive. Otherwise, the result may be a NaN, or may be some meaningless flonum.

Fixnum/Flonum Conversions

procedure: fixnum->flonum fx

Returns a flonum that is numerically closest to its argument.

Note: The result of this procedure may not be numerically equal to its argument, because the fixnum precision may be greater than the flonum precision.

If the argument to fixnum->flonum is not a fixnum, then an error is signalled, unless the implementation is running in unsafe mode, in which case all bets are off.

Exact Arithmetic

The exact arithmetic provides generic operations on exact numbers; these operations correspond to their mathematical counterparts. The exact numbers include rationals of arbitrary precision, and exact rectangular complex numbers. A rational number with a denominator of 1 is indistinguishable from its numerator. An exact rectangular complex number with a zero imaginary part is indistinguishable from its real part.

procedure: exact-number? ex
procedure: exact-complex? ex
procedure: exact-rational? ex
procedure: exact-integer? ex

These numerical type predicates can be applied to any kind of argument, including non-numbers. They return #t if the object is an exact number of the named type, and otherwise return #f. In general, if a type predicate is true of a number then all higher type predicates are also true of that number. Consequently, if a type predicate is false of a number, then all lower type predicates are also false of that number.

We will use ex, ex1, ex2, and ex3 as metavariables that range over the exact complex numbers, ef, ef1, ef2, and ef3 as metavariables that range over the exact rational numbers, and ei, ei1, ei2, and ei3 as metavariables that range over the exact integers.

If an argument to the following procedures that corresponds to an exact (rational, integer) metavariable is not actually an exact (rational, integer) number, then these procedures signal an error (and should signal an error even in unsafe mode).

procedure: exact= ex1 ex2 ex3 ...
procedure: exact>? ef1 ef2 ef3 ...
procedure: exact<? ef1 ef2 ef3 ...
procedure: exact>=? ef1 ef2 ef3 ...
procedure: exact<=? ef1 ef2 ef3 ...

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

procedure: exact-zero? ex
procedure: exact-positive? ef
procedure: exact-negative? ef
procedure: exact-odd? ei
procedure: exact-even? ei

These numerical predicates test an exact number for a particular property, returning #t or #f. Exact-zero? tests if the number is exact=? to zero, exact-positive? tests if it is greater than zero, exact-negative? tests if it is less than zero, exact-odd? tests if it is odd, exact-even? tests if it is even.

procedure: exact-max ef1 ef2 ...
procedure: exact-min ef1 ef2 ...

These procedures return the maximum or minimum of their arguments.

procedure: exact+ ex1 ex2 ...
procedure: exact* ex1 ex2 ...

These procedures return the sum or product of their arguments.

procedure: exact- ex1 ex2 ...
procedure: exact- ex
procedure: exact/ ex1 ex2 ...
procedure: exact/ ex

With two or more arguments, these procedures return the difference or quotient of their arguments, associating to the left. With one argument, however, they return the additive or multiplicative inverse of their argument. Exact/ signals an error if a divisor is 0.

procedure: exact-abs ef

This procedure returns the absolute value of its argument.

procedure: exact-div+mod ef1 ef2
procedure: exact-div ef1 ef2
procedure: exact-mod ef1 ef2
procedure: exact-div0+mod0 ef1 ef2
procedure: exact-div0 ef1 ef2
procedure: exact-mod0 ef1 ef2

These procedures implement number-theoretic integer division and return the results of the corresponding mathematical operations specified in the section on Integer Division. In each case, x1 must be neither infinite nor a NaN, and x2 must be nonzero; otherwise, an exception is raised.

(exact-div x1 x2)         ==> x1 div x2
(exact-mod x1 x2)         ==> x1 mod x2
(exact-div+mod x1 x2)     ==> x1 div x2, x1 mod x2 ; two return values
(exact-div0 x1 x2)        ==> x1 div0 x2
(exact-mod0 x1 x2)        ==> x1 mod0 x2
(exact-div0+mod0 x1 x2)   ==> x1 div0 x2, x1 mod0 x2 ; two return values

procedure: exact-gcd ei1 ei2 ...
procedure: exact-lcm ei1 ei2 ...

These procedures return the greatest common divisor or least common multiple of their arguments.

procedure: exact-numerator ef
procedure: exact-denominator ef

These procedures return the numerator or denominator of their argument. The result is computed as if the argument was represented as a fraction in lowest terms. The denominator is always positive. The denominator of 0 is defined to be 1.

procedure: exact-floor ef
procedure: exact-ceiling ef
procedure: exact-truncate ef
procedure: exact-round ef

These procedures return exact integers. Exact-floor returns the largest integer not larger than ef. Exact-ceiling returns the smallest integer not smaller than ef. Exact-truncate returns the integer closest to ef whose absolute value is not larger than the absolute value of ef. Exact-round returns the closest integer to ef, rounding to even when ef is halfway between two integers.

procedure: exact-expt ef1 ei2

Returns ef1 raised to the power ei2. 0ei is 1 if ei = 0 and 0 if ei is positive. Otherwise, this procedure signals an error.

procedure: exact-make-rectangular ex1 ex2
procedure: exact-real-part ex
procedure: exact-imag-part ex

The arguments of exact-make-rectangular must be exact rationals. Suppose z is a complex number such that z = ef1 + ef2*i. Then:

(exact-make-rectangular ef1 ef2) ==> z
(exact-real-part z)              ==> ef1
(exact-imag-part z)              ==> ef2

procedure: exact-integer-sqrt ei

Ei must be a non-negative exact integer; if it is not, an error is signalled. Exact-integer-sqrt returns two non-negative exact integers s and r where ei = s2 + r and ei < (s+1)2.

procedure: exact-not ei

Returns the exact integer whose two's complement representation is the one's complement of the two's complement representation of its argument.

procedure: exact-and ei1 ...
procedure: exact-ior ei1 ...
procedure: exact-xor ei1 ...

These procedures return the exact integer 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 integer (either -1 or 0) that acts as identity for the operation.

procedure: exact-if ei1 ei2 ei3

Returns the exact integer that is the result of the following computation:

    (exact-ior (exact-and ei1 ei2)
               (exact-and (exact-not ei1) ei3))

procedure: exact-bit-count ei

If the argument is non-negative, this procedure returns the number of 1 bits in the two's complement representation of its argument. Otherwise it returns the number of 0 bits in the two's complement representation of its argument.

procedure: exact-length ei

These procedures return the exact integer that is the result of the following computation:

    (do ((result 0 (+ result 1))
         (bits (if (exact-negative? ei)
                   (exact- ei)
                   ei)
               (exact-arithmetic-shift bits -1)))
        ((exact-zero? bits)
         result))

procedure: exact-first-bit-set ei

This procedures returns the index of the least significant 1 bit in the two's complement representation of its argument. If the argument is 0, then -1 is returned.

(exact-first-bit-set 0)        ==>  -1
(exact-first-bit-set 1)        ==>  0
(exact-first-bit-set -4)       ==>  2

procedure: exact-bit-set? ei1 ei2

If the second argument is negative, then an error is signalled. Otherwise returns the result of the following computation:

    (not (exact-zero?
          (exact-and (exact-arithmetic-shift-left 1 ei2)
                     ei1)))

procedure: exact-copy-bit ei1 ei2 ei3

If the second argument is negative, or the third argument is anything other than 0 or 1, then an error is signalled. Otherwise returns the result of the following computation:

    (let* ((mask (exact-arithmetic-shift-left 1 ei2)))
      (exact-if mask
                (exact-arithmetic-shift-left ei3 ei2)
                ei1))

procedure: exact-bit-field ei1 ei2 ei3

If the second or third argument is negative, or the second argument is greater than the third, then an error is signalled. Otherwise returns the result of the following computation:

    (let* ((mask (exact-not
                  (exact-arithmetic-shift-left -1 ei3))))
      (exact-arithmetic-shift-right (exact-and ei1 mask)
                                    ei2))

procedure: exact-copy-bit-field ei1 ei2 ei3 ei4

If the second or third argument is negative, or the second argument is greater than the third, then an error is signalled. Otherwise returns the result of the following computation:

    (let* ((to    fx1)
           (start fx2)
           (end   fx3)
           (from  fx4)
           (mask1 (exact-logical-shift-left -1 start))
           (mask2 (exact-not
                   (exact-arithmetic-shift-left -1 end)))
           (mask (fixnum-and mask1 mask2)))
      (exact-if mask from to))

procedure: exact-arithmetic-shift ei1 ei2

Returns the exact integer result of the following computation:

    (exact-floor (* ei1 (expt 2 ei2)))

procedure: exact-arithmetic-shift-left ei1 ei2
procedure: exact-arithmetic-shift-right ei1 ei2

If the second argument is non-negative, then exact-arithmetic-shift-left returns the same result as exact-arithmetic-shift, and (exact-arithmetic-shift-right fx1 fx2) returns the same result as (exact-arithmetic-shift fx1 (exact- fx2)). If the second argument is negative, then an error is signalled.

procedure: exact-rotate-bit-field ei1 ei2 ei3 ei4

If the second, third, and fourth arguments are non-negative, or the fourth argument is greater than or equal to the difference between the second and third arguments, then an error is signalled.

    (let* ((n     ei1)
           (start ei2)
           (end   ei3)
           (count ei4)
           (width (exact- end start)))
      (if (exact-positive? width)
          (let* ((count (exact-mod count width))
                 (field0 (exact-bit-field n start end))
                 (field1 (exact-arithmetic-shift field0 count))
                 (field2 (exact-arithmetic-shift field0
                                                 (exact- width count)))
                 (field (exact-ior field1 field2)))
            (exact-copy-bit-field n field start end))
          n))

procedure: exact-reverse-bit-field ei1 ei2 ei3

If the second or third argument is negative, or the second argument is greater than the third, then an error is signalled. Otherwise returns the result obtained from the first argument by reversing the bit field specified by the second and third arguments.

(exact-reverse-bit-field #b1010010 1 4)    ==>  88 ; #b1011000
(exact-reverse-bit-field #b1010010 91 -4)  ==>  error

Inexact Arithmetic

The inexact arithmetic provides generic operations on inexact numbers. The inexact numbers include inexact reals and inexact complex numbers, both of which are distinguishable from the exact numbers. The inexact complex numbers include the flonums, and the procedures described here behave consistently with the corresponding flonum procedures if passed flonum arguments.

procedure: inexact-number? obj
procedure: inexact-complex? obj
procedure: inexact-real? obj
procedure: inexact-rational? obj
procedure: inexact-integer? obj

These numerical type predicates can be applied to any kind of argument, including non-numbers. They return #t if the object is an inexact number of the named type, and otherwise they return #f. In general, if a type predicate is true of a number then all higher type predicates are also true of that number. Consequently, if a type predicate is false of a number, then all lower type predicates are also false of that number.

We will use in, in1, in2, and in3 as metavariables that range over the inexact numbers, ir, ir1, ir2, and ir3 as metavariables that range over the inexact real numbers, if, if1, if2, and if3 as metavariables that range over the inexact rationals. and ii, ii1, ii2, and ii3 as metavariables that range over the inexact integers.

If an argument to the following procedures that corresponds to an inexact metavariable is not actually an inexact number, then these procedures signal an error (and should signal an error even in unsafe mode). The same holds true for arguments corresponding to inexact real metavariables.

procedure: inexact=? in1 in2 in3 ...
procedure: inexact>? ir1 ir2 ir3 ...
procedure: inexact<? ir1 ir2 ir3 ...
procedure: inexact>=? ir1 ir2 ir3 ...
procedure: inexact<=? ir1 ir2 ir3 ...

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

procedure: inexact-zero? in
procedure: inexact-positive? ir
procedure: inexact-negative? ir
procedure: inexact-odd? ii
procedure: inexact-even? ii
procedure: inexact-finite? in
procedure: inexact-infinite? in
procedure: inexact-nan? in

These numerical predicates test an inexact number for a particular property, returning #t or #f. Inexact-zero? tests if the number is inexact=? to zero, inexact-positive? tests if it is greater than zero, inexact-negative? tests if it is less than zero, inexact-odd? tests if it is odd, inexact-even? tests if it is even, inexact-finite? tests if it is not an infinity and not a NaN, inexact-infinite? tests if it is an infinity, inexact-nan? tests if it is a NaN.

procedure: inexact-max ir1 ir2 ...
procedure: inexact-min ir1 ir2 ...

These procedures return the maximum or minimum of their arguments.

procedure: inexact+ in1 in2 ...
procedure: inexact* in1 in2 ...

These procedures return the sum or product of their arguments.

procedure: inexact- in1 in2 ...
procedure: inexact- in
procedure: inexact/ in1 in2 ...
procedure: inexact/ in

With two or more arguments, these procedures return the difference or quotient of their arguments, associating to the left. With one argument, however, they return the additive or multiplicative inverse of their argument.

procedure: inexact-abs in

This procedure returns the absolute value of its argument.

procedure: inexact-div+mod ir1 ir2
procedure: inexact-div ir1 ir2
procedure: inexact-mod ir1 ir2
procedure: inexact-div0+mod0 ir1 ir2
procedure: inexact-div0 ir1 ir2
procedure: inexact-mod0 ir1 ir2

These procedures implement number-theoretic integer division and return the results of the corresponding mathematical operations specified in the section on Integer Division. In each case, x1 must be neither infinite nor a NaN, and x2 must be nonzero; otherwise, an exception is raised.

(inexact-div x1 x2)         ==> x1 div x2
(inexact-mod x1 x2)         ==> x1 mod x2
(inexact-div+mod x1 x2)     ==> x1 div x2, x1 mod x2 ; two return values
(inexact-div0 x1 x2)        ==> x1 div0 x2
(inexact-mod0 x1 x2)        ==> x1 mod0 x2
(inexact-div0+mod0 x1 x2)   ==> x1 div0 x2, x1 mod0 x2 ; two return values

procedure: inexact-gcd ii1 ii2 ...
procedure: inexact-lcm ii1 ii2 ...

These procedures return the greatest common divisor or least common multiple of their arguments.

procedure: inexact-numerator if
procedure: inexact-denominator if

These procedures return the numerator or denominator of their argument. The result is computed as if the argument was represented as a fraction in lowest terms. The denominator is always positive. The denominator of 0 is defined to be 1.

procedure: inexact-floor ir
procedure: inexact-ceiling ir
procedure: inexact-truncate ir
procedure: inexact-round ir

These procedures return inexact integers for real arguments that are not infinities or NaNs. For such arguments, inexact-floor returns the largest integer not larger than ir. Inexact-ceiling returns the smallest integer not smaller than ir. Inexact-truncate returns the integer closest to in whose absolute value is not larger than the absolute value of in. Inexact-round returns the closest integer to in, rounding to even when in is halfway between two integers.

Rationale: Round rounds to even for consistency with the default rounding mode specified by the IEEE floating point standard.

Although infinities and NaNs are not integers, these procedures return an infinity when given an infinity as an argument, and a NaN when given a NaN.

procedure: inexact-exp in
procedure: inexact-log in
procedure: inexact-sin in
procedure: inexact-cos in
procedure: inexact-tan in
procedure: inexact-asin in
procedure: inexact-atan in
procedure: inexact-atan ir1 ir2

These procedures compute the usual transcendental functions. Inexact-log computes the natural logarithm of in (not the base ten logarithm). Inexact-asin, Inexact-acos, and Inexact-atan compute arcsine (sin-1), arccosine (cos-1), and arctangent (tan-1), respectively. The two-argument variant of Inexact-atan computes `(inexact-angle (inexact-make-rectangular ir1 ir2))' (see below).

In general, the mathematical functions log, arcsine, arccosine, and arctangent are multiply defined. The value of log z is defined to be the one whose imaginary part lies in the range from -pi (inclusive if -0.0 is distinguished, exclusive otherwise) to pi (inclusive). With log defined this way, the values of sin-1 z, cos-1 z, and tan-1 z are according to the following formulae:

sin-1 z = -i log (i z + sqrt(1 - z2))

cos-1 z = pi / 2 - sin-1 z

tan-1 z = (log (1 + i z) - log (1 - i z)) / (2 i)

If the function has a real-valued limit as its argument tends toward positive infinity, then that is the value returned by the function applied to +inf.0. If the function has a real-valued limit as its argument tends toward negative infinity, then that is the value returned by the function applied to -inf.0.

In the event that these formulae do not yield a real result for the given arguments, the result may be +nan.0, or may be some meaningless inexact number.

Specifically, the range of `(inexact-atan x y)' is as in the following table. The asterisk (*) indicates that the entry applies to implementations that distinguish minus zero.

y Condition x Condition Range of result
y = 0.0 x > 0.0 0.0
* y = +0.0 x > 0.0 +0.0
* y = -0.0 x > 0.0 -0.0
y > 0.0 x > 0.0 0.0 < result< pi/2
y > 0.0 x = 0.0 pi/2
y > 0.0 x < 0.0 pi/2 < result< pi
y = 0.0 x < 0 pi
* y = +0.0 x < 0.0 +pi
* y = -0.0 x < 0.0 -pi
y < 0.0 x < 0.0 -pi< result< -pi/2
y < 0.0 x = 0.0 -pi/2
y < 0.0 x > 0.0 -pi/2 < result< 0.0
y = 0.0 x = 0.0 undefined
* y = +0.0 x = +0.0 +0.0
* y = -0.0 x = +0.0 -0.0
* y = +0.0 x = -0.0 +pi
* y = -0.0 x = -0.0 -pi

The above specification follows the branch cut specification of Common Lisp in [Pitman 1996], and [Steele 1990], which in turn cites [Penfield 1981]; refer to these sources for more detailed discussion of branch cuts, boundary conditions, and implementation of these functions.

procedure: inexact-sqrt in

Returns the principal square root of z. For a negative argument, the result may be +nan.0, or may be some meaningless inexact number. With log defined as above, the value of `(inexact-sqrt in)' could be expressed as

e(log in) / 2

procedure: inexact-expt in1 in2

Returns in1 raised to the power in2. For nonzero in1

in1in2 = ein2 log in1

0.0z is 1 if z = 0.0, and 0.0 if `(inexact-real-part z)' is positive. Otherwise, this procedure reports a violation of an implementation restriction or returns an unspecified number.

procedure: inexact-make-rectangular ir1 ir2
procedure: inexact-make-polar ir1 ir2
procedure: inexact-real-part in
procedure: inexact-imag-part in
procedure: inexact-magnitude in
procedure: inexact-angle in

Suppose in1, in2, in3, and in4 are inexact rational numbers, and z is a complex number, such that z = in1 + in2*i = in3 * ei*in4. Then (inexactly):

(inexact-make-rectangular in1 in2) ==> z
(inexact-make-rectangular in3 in4) ==> z
(inexact-real-part z)              ==> in1
(inexact-imag-part z)              ==> in2
(inexact-magnitude z)              ==> |in3|
(inexact-angle z)                  ==> inangle

where -pi <= inangle <= pi with inangle = in4 + 2pi n for some integer n.

(inexact-angle -1.0)         ==> pi
(inexact-angle -1.0+0.0)     ==> pi
(inexact-angle -1.0-0.0)     ==> -pi ; if -0.0 is distinguished

Moreover, suppose in1, in2 are such that either in1 or in2 is an infinity, then

(inexact-make-rectangular in1 in2) ==> z
(inexact-magnitude z)              ==> +inf.0

Generic Arithmetic

The section on exactness reads as follows:

Scheme numbers are either exact or inexact. A number is exact if it was written as an exact constant or was derived from exact numbers using only exact operations. A number is inexact if it is infinite, if it was written as an inexact constant, if it was derived using inexact ingredients, or if it was derived using inexact operations. Thus inexactness is a contagious property of a number. A number is inexact if it was written as an inexact constant or was derived from inexact numbers. Thus inexactness is contagious. The generic operations generally return the correct exact result when all of their arguments are exact and the result is mathematically well-defined, but return an inexact result when any argument is inexact. Exceptions are sqrt, exp, log, sin, cos, tan, asin, acos, atan, expt, make-polar, magnitude, and angle, which are allowed (but not required) to return inexact results even when given exact arguments, as indicated in the specification of these procedures.

One general exception to the rule above is that an implementation may return an exact result despite inexact arguments if that exact result would be the correct result for all possible substitutions of exact arguments for the inexact ones.

Each exact number corresponds to a single mathematical number. It is the programmer's responsibility to avoid using exact numbers with magnitude or precision too large to be represented in the implementation. For inexact numbers, it is the programmer's responsibility to avoid using complex numbers with magnitude too large to be represented in the implementation.

It is the programmer's responsibility to avoid using numbers with magnitude or significand too large to be represented in the implementation.

If two implementations produce exact results for a computation that did not involve inexact intermediate results, the two ultimate results will be mathematically equivalent. This is generally not true of computations involving inexact numbers because approximate methods such as floating point arithmetic may be used, but it is the duty of each implementation to make the result as close as practical to the mathematically ideal result.

Rational operations such as + should always produce exact results when given exact arguments. If the operation is unable to produce an exact result, then it may either report the violation of an implementation restriction or it may silently coerce its result to an inexact value. See section 6.2.3.

With the exception of inexact->exact exact-round, exact-ceiling, exact-floor, and exact-truncate, the operations described in this section must return inexact results when given any inexact arguments.

The procedures described here behave consistently with the corresponding inexact- procedure if passed inexact arguments, and with the corresponding exact- procedure if passed exact arguments.

We will use z, z1, z2, and z3 as metavariables that range over the complex numbers, x, x1, x2, and x3 as metavariables that range over the real numbers, q, q1, q2, and q3 as metavariables that range over the rationals. and n, n1, n2, and n3 as metavariables that range over the inexact integers.

If an argument to the following procedures that corresponds to a metavariable is not in the set specified for that metavariable, then these procedures signal an error (and should signal an error even in unsafe mode).

procedure: = z1 z2 z3 ...
procedure: < x1 x2 x3 ...
procedure: > x1 x2 x3 ...
procedure: <= x1 x2 x3 ...
procedure: >= x1 x2 x3 ...

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

(= +inf.0 +inf.0)           ==>  #t
(= -inf.0 +inf.0)           ==>  #f
(= -inf.0 -inf.0)           ==>  #t
For any real number x that is neither infinite nor NaN:
(< -inf.0 x +inf.0))        ==>  #t
(> +inf.0 x -inf.0))        ==>  #t

These predicates are required to be transitive.

Note: The traditional implementations of these predicates in Lisp-like languages are not transitive.

Note: While it is not an error to compare inexact numbers using these predicates, the results may be unreliable because a small inaccuracy may affect the result; this is especially true of = and zero?. When in doubt, consult a numerical analyst.

procedure: zero? z
procedure: positive? x
procedure: negative? x
procedure: odd? n
procedure: even? n
procedure: finite? x
procedure: infinite? x
procedure: nan? x

These numerical predicates test a number for a particular property, returning #t or #f. See note above. Zero? tests if the number is = to zero, positive? tests if it is greater than zero, negative? tests if it is less than zero, odd? tests if it is odd, even? tests if it is even, finite? tests if it is not an infinity and not a NaN, infinite? tests if it is an infinity, nan? tests if it is a NaN.

(positive? +inf.0)            ==>  #t
(negative? -inf.0)            ==>  #t
(finite? +inf.0)              ==>  #f
(finite? 5)                   ==>  #t
(finite? 5.0)                 ==>  #t
(infinite? 5.0)               ==>  #f
(infinite? +inf.0)            ==>  #t

procedure: max x1 x2 ...
procedure: min x1 x2 ...

These procedures return the maximum or minimum of their arguments.

(max 3 4)                              ==>  4    ; exact
(max 3.9 4)                            ==>  4.0  ; inexact
For any real number x:
(max +inf.0 x)                         ==>  +inf.0
(min -inf.0 x)                         ==>  -inf.0

Note: If any argument is inexact, then the result will also be inexact (unless the procedure can prove that the inaccuracy is not large enough to affect the result, which is possible only in unusual implementations). If min or max is used to compare numbers of mixed exactness, and the numerical value of the result cannot be represented as an inexact number without loss of accuracy, then the procedure may report a violation of an implementation restriction.

procedure: + z1 ...
procedure: * z1 ...

These procedures return the sum or product of their arguments.

(+ 3 4)                                ==>  7
(+ 3)                                  ==>  3
(+)                                    ==>  0
(+ +inf.0 +inf.0)                      ==>  +inf.0
(+ +inf.0 -inf.0)                      ==>  +nan.0

(* 4)                                  ==>  4
(*)                                    ==>  1
(* 5 +inf.0)                           ==>  +inf.0
(* -5 +inf.0)                          ==>  -inf.0
(* +inf.0 +inf.0)                      ==>  +inf.0
(* +inf.0 -inf.0)                      ==>  -inf.0
(* 0 +inf.0)                           ==>  0 or +nan.0
(* 0 +nan.0)                           ==>  0 or +nan.0
For any real number x that is neither infinite nor NaN:
(+ +inf.0 x)                           ==>  +inf.0
(+ -inf.0 x)                           ==>  -inf.0
(+ +nan.0 x)                           ==>  +nan.0
For any real number x that is neither infinite nor NaN nor 0:
(* +nan.0 x)                           ==>  +nan.0

If any of these procedures are applied to mixed non-rational real and non-real complex arguments, they either report a violation of an implementation restriction or return an unspecified number.

procedure: - z
optional procedure: - z1 z2 ...
procedure: / z
optional procedure: / z1 z2 ...

With two or more arguments, these procedures return the difference or quotient of their arguments, associating to the left. With one argument, however, they return the additive or multiplicative inverse of their argument.

(- 3 4)                                ==>  -1
(- 3 4 5)                              ==>  -6
(- 3)                                  ==>  -3
(- +inf.0 +inf.0)                      ==>  +nan.0

(/ 3 4 5)                              ==>  3/20
(/ 3)                                  ==>  1/3
(/ 0.0)                                ==>  +inf.0
(/ 1.0 0)                              ==>  +inf.0 or error
(/ -1 0.0)                             ==>  -inf.0
(/ +inf.0)                             ==>  0.0
(/ 0 0.0)                              ==>  +nan.0 0 or +nan.0
(/ 0.0 0)                              ==>  +nan.0 or error
(/ 0.0 0.0)                            ==>  +nan.0

If any of these procedures are applied to mixed non-rational real and non-real complex arguments, they either report a violation of an implementation restriction or return an unspecified number.

procedure: abs x

Abs returns the absolute value of its argument.

(abs -7)                               ==>  7
(abs -inf.0)                           ==>  +inf.0

procedure: div+mod x1 x2
procedure: div x1 x2
procedure: mod x1 x2
procedure: div0+mod0 x1 x2
procedure: div0 x1 x2
procedure: mod0 x1 x2

These procedures implement number-theoretic integer division and return the results of the corresponding mathematical operations specified in the section on Integer Division. In each case, x1 must be neither infinite nor a NaN, and x2 must be nonzero; otherwise, an exception is raised.

(div x1 x2)         ==> x1 div x2
(mod x1 x2)         ==> x1 mod x2
(div+mod x1 x2)     ==> x1 div x2, x1 mod x2 ; two return values
(div0 x1 x2)        ==> x1 div0 x2
(mod0 x1 x2)        ==> x1 mod0 x2
(div0+mod0 x1 x2)   ==> x1 div0 x2, x1 mod0 x2 ; two return values

procedure: gcd r1 n1 ...
procedure: lcm r1 n1 ...

Note: This is the R5RS definition.

These procedures return the greatest common divisor or least common multiple of their arguments. The result is always non-negative.

For exact integer arguments, these procedures are the familiar number theoretic operators:

(gcd 32 -36)                           ==>  4
(gcd)                                  ==>  0
(lcm 32 -36)