Infinities in Scheme
The three special values inf, -inf, and nan of IEEE Standard 754 are well-defined and integrated into 754's arithmetic system.
With nearly every Scheme implementation using IEEE floating-point numbers, we should consider advancing the language to reap more of the benefits of IEEE-754 by standardizing Scheme syntaxes for infinities. Doing so would also improve storage and communication of numerical data between programs.
This article contains research conducted for the SRFI-70 proposal for numbers in the next revision of The Algorithmic Language Scheme. It has been updated for SCM 5e2 which implements SRFI-70.
Checks for division by zero (and their absence) remain one of the most
common programming errors. Table 1,
for example, shows Scheme48 and MIT-Scheme signaling errors evaluating
Is it merely a coincidence that these implementations are the
least tolerant (among those tested) of division by zeros?
The realization that division by zero "works" lets initialization of variables precede bounds checks and gives flexibility in placement of those checks. Halting of programs need not occur in order to test limit and corner cases. Preserving infinities in data sets can free presentation programs from imposing arbitrary range limits.
Scheme interpreter or compiler.
The Scheme program "inf.scm"
Invoke Scheme interactively, then
Edit the end of "inf.scm" to call
trydivs with or
without an argument as appropriate for the Scheme's
eval. Then compile "inf.scm" and run.
real-infs in "inf.scm" is a list of
all known (to me) literal representations of inf,
-inf, and nan.
complex-infs in "inf.scm" is a list of the combinations
within each group of infinity representations in one or both
components of complex numbers.
str2num prints its string argument, tries
to convert that string to a number, and writes out that number on the
same line if successful.
str2num is called with each string in
str2num is called with each string in
/ with all
possible combinations of one or two exact or inexact zeros,
printing each expression and its result.
the combinations having inexact denominator "
prints HTML rows detailing the numerical predicates applied to
If an error occurs while interactively running "inf.scm", the tests can be run manually:
(for-each str2num real-infs)
(for-each str2num complex-infs)
|Input||glibc 2.2 strtod()||Gambit 4.0||Chicken 1(89)||Guile 1.8.0||Mz Scheme 301||Chez Scheme 6.1||Larceny 0.90||SCM 5e2||kawa 1.8||Scheme 48 1.3||MIT Scheme 7.8|
|, ||Characters left at end|
|[s]||;Division by zero signaled by /.|
|[n]||*** ERROR -- NUMBER expected|
scanf()reads identically with
strtod()also accepts "infinity", but no substrings of it other than "inf".
string->numberdoes not accept
|[g]||*** ERROR -- REAL expected|
(make-rectangular #f 1)
string->numberaccepts imaginary infinities only with a real 0 part prepended, eg.
"#i-"lose the minus sign.
The floating-point string conversions in GNU glibc 2.2 support reading and writing of infinite values:
infis positive infinity;
-infis negative infinity;
IEEE 754 does not specify string representations for inf and nan. These names were apparently chosen to match 754 nomenclature.
Although not specified by the Revised5 Report on the Algorithmic Language Scheme, a few Scheme implementations support reading and literal use of their representations of infinities.
The richness of Scheme's syntax of numerical constants provides
several opportunities to support infinities. An idea which has
occurred to several authors independently is to use
place of all digits in a number:
+#.#is positive infinity;
-#.#is negative; and
#.#is NaN (not a number).
This notation is compact and would not be easily mistaken for any
other Scheme object. The problem arises when these objects are
components of complex numbers. The coefficient of
be prefixed by a sign, making
Remediations like disallowing complex NaNs would be modifying
semantics in pursuit of syntax; not a good practice.
Gambit and MzScheme both use strings derived from IEEE-754 nomenclature:
Requiring the leading sign character prevents confusion with identifiers, but "+inf" spoofs "+i". NaN, an intrinsically unsigned construct, is required to have a sign prefix by both systems. Gambit does not recognize "-nan." as NaN. MzScheme recognizes both "+nan.0" and "-nan.0" as NaN, but always prints "+nan.0".
SCM 5d8 printed infinities as rational numbers with denominators of "0". SCM's existing reader decodes this format without modification:
Kawa's infinities look like inexact rational numbers.
Since an implementation is allowed to coerce the result of division by 0 to inexact, SCM always does so.
If one of these procedures is unable to deliver an exact result when given exact arguments, then it may either report a violation of an implementation restriction or it may silently coerce its result to an inexact number.
Table 3 catalogs the results of dividing exact
and inexact numbers by exact and inexact zeros. In both
MzScheme and MIT-Scheme
(/ 0 0.) returns
"0". An inexact "0." is
apparently weaker than an exact "0" in those
|quotient||SCM 5e2||Kawa 1.8||Bigloo 2.7a-r2||glibc 2.2 printf||Larceny 0.90||Guile 1.8.0||Elk 3.0||Gambit 4.0||Mz Scheme 301||Chez Scheme 6.1||MIT Scheme 7.8|
|(/ -1. 0.)||-inf.0||#i-1/0||-Infinity||-inf||-inf.0||-inf.0||-Inf.0||-inf.||-inf.0||-inf.0||[t]|
|(/ -1 0.)||-inf.0||#i-1/0||-Infinity||-inf||-inf.0||-inf.0||-Inf.0||-inf.||-inf.0||-inf.0||[t]|
|(/ 0. 0.)||0/0||#i0/0||Infinity||nan||+nan.0||+nan.0||NaN||+nan.||+nan.0||+nan.0||[a]|
|(/ 0 0.)||0/0||#i0/0||Infinity||nan||+nan.0||+nan.0||NaN||+nan.||0||0||0|
|(/ -1. 0)||-inf.0||#i-1/0||-Infinity||-inf||-inf.0||[n]||[e]||[g]||[d]||[d]||[t]|
|(/ 0. 0)||0/0||#i0/0||Infinity||nan||+nan.0||[n]||[e]||[g]||[d]||[d]||[a]|
|(/ 0 0)||0/0||[j]||[b]||[c]||[d]||[n]||[e]||[g]||[d]||[d]||[s]|
|(/ -1 0)||-inf.0||-1/0||[b]||[c]||[d]||[n]||[e]||[g]||[d]||[d]||[s]|
|quotient||Scheme 48 1.3||Chicken 1(89)|
|(/ any 0.)||[r]||[d]|
|(/ any 0)||[r]||[d]|
|[a]||;Anonymous arithmetic error|
|[b]||*** ERROR:arithmetic procedure:|
`floating point' exception -- raised
|[c]||Floating point exception|
|[d]||/: division by zero|
|[e]||/: argument out of range: 0|
|[g]||*** ERROR -- Divide by zero|
|[j]||java.lang.ArithmeticException: / by zero|
|[s]||;Division by zero signaled by /.|
|[t]||;Division by zero|
|Mz Scheme 301||+inf.0||*||*||*||*||*|
|[p]||;ERROR: positive?: Wrong type in arg1 0/0|
|[n]||;ERROR: negative?: Wrong type in arg1 0/0|
Table 4 shows the numerical properties of each of the special values. Only Kawa supports (2) exact infinities. For inexact infinities the only variations are in the real, rational, and integer columns.
The glibc syntax for infinities has two undesirable aspects:
Nothing visually distinguishes inf and nan from text words.
Inf and nan will be meaningless acronyms to people unfamiliar with IEEE-754 who encounter them in data files.
Gambit and MzScheme address the first problem by requiring a sign
prefix. Glibc reads signed infinities, so they would
interoperate in one direction. But both implementations
add suffixes to inf and nan which
scanf() do not ignore.
discussions found general agreement on the
-inf.0 syntaxes for real infinities.
This survey of infinities in Scheme shows general agreement among implementations that scalar infinities are inexact reals. Most allow infinities as independent real and imaginary components of complex numbers.
Several implementations provide read/write invariance of inexact
complex infinities; but their syntaxes are incompatible.
Implementations should adopt the syntaxes
-inf.0, which should also be incorporated into the next
I am a guest and not a member of the MIT Computer Science and Artificial Intelligence Laboratory.
My actions and comments do not reflect in any way on
|agj @ alum.mit.edu||Go Figure!|