Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Infinities in Scheme

4 views
Skip to first unread message

Aubrey Jaffer

unread,
Aug 9, 2003, 1:54:28 PM8/9/03
to
Infinities in Scheme
--------------------
http://swissnet.ai.mit.edu/~jaffer/III/RAWI

Introduction
============

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.

Background
==========

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 (string->number "1/0"). 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.

Apparatus
=========

* Scheme interpreter or compiler.

* The Scheme program "inf.scm"
http://swissnet.ai.mit.edu/~jaffer/III/inf.scm

Procedures
==========

* Invoke Scheme interactively, then (load "inf.scm");

or

* 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.

Method
======

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.

The procedure 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 REAL-INFS.

* STR2NUM is called with each string in COMPLEX-INFS.

* The procedure TRYDIVS calls / with all possible combinations of
one or two exact or inexact zeros, printing each expression and
its result.

* The procedure INEX-PROPS calls / with the combinations having
inexact denominator "0." and prints HTML rows detailing the
numerical predicates applied to the ratio.

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)

* (trydivs (interaction-environment))

* (inex-props (interaction-environment))

string->number
==============

Table 1: string->number of (real) infinity strings

Input glibc 2.2 Gambit Mz Scheme SCM Scheme 48 MIT Scheme
strtod() 3.0 202 5d8 0.57 7.8
=======================================================================
"+inf.0" inf [2] +inf.0
"-inf.0" -inf[2] -inf.0
"+nan.0" nan [2] +nan.0
"-nan.0" nan [2] +nan.0
"nan.0" nan [2]
"+inf." inf [1] +inf.
"-inf." -inf[1] -inf.
"+nan." nan [1] +nan.
"-nan." nan [1]
"nan." nan [1]
"+INF" inf
"-Inf" -inf
"inf" inf
"+NAN" nan
"-Nan" nan
"nan" nan
"+#.#" 5.5
"-#.#" -5.5
"#.#"
"1/0" 1/0 [r] [s]
"-1/0" () -1/0 [r] [s]
"0/0" 0/0 [r] [s]
=======================================================================
[1], [2] Characters left at end

[s] ;Division by zero signaled by /.

[r] Error: rational division by zero

Notes:

* Empty entries indicate #f was returned.
* scanf() reads identically with strtod().
* strtod() also accepts "infinity", but no substrings of it other
than "inf".
* Gambit string->number returns (). when passed "-1/0" or "-0/0".
* Gambit string->number does not accept "-nan.".
* MzScheme string->number accepts "-nan.0".


Table 2: string->number of complex infinity strings

Input Gambit 3.0 Input MzScheme 202 Input SCM 5d8
============= ========== ============== ============ ========== =========
"inf.+i" "inf.0+i" "1/0+i" 1/0+1.0i
"-inf.+i" -inf.+i "-inf.0+i" -inf.0+1.0i "-1/0+i" -1/0+1.0i
"+nan.+i" +nan.+i "+nan.0+i" +nan.0+1.0i "0/0+i" 0/0+1.0i
"-nan.+i" "-nan.0+i" +nan.0+1.0i "+1/0i" 0.0+1/0i
"+inf.i" +inf.i "+inf.0i" "-1/0i" 0.0-1/0i
"-inf.i" -inf.i "-inf.0i" "+0/0i" 0.0+0/0i
"+nan.i" +nan.i "+nan.0i" "-0/0i" 0.0+0/0i
"-nan.i" "-nan.0i" "1/0+1/0i" 1/0+1/0i
"0+inf.i" +inf.i "0+inf.0i" 0+inf.0i "1/0-1/0i" 1/0-1/0i
"0-inf.i" -inf.i "0-inf.0i" 0-inf.0i "1/0+0/0i" 1/0+0/0i
"0+nan.i" +nan.i "0+nan.0i" 0+nan.0i "1/0-0/0i" 1/0+0/0i
"0-nan.i" "0-nan.0i" 0+nan.0i "-1/0+1/0i" -1/0+1/0i
"inf.+inf.i" "inf.0+inf.0i" "-1/0-1/0i" -1/0-1/0i
"inf.-inf.i" "inf.0-inf.0i" "-1/0+0/0i" -1/0+0/0i
"inf.+nan.i" "inf.0+nan.0i" "-1/0-0/0i" -1/0+0/0i
"inf.-nan.i" "inf.0-nan.0i" "0/0+1/0i" 0/0+1/0i
"-inf.+inf.i" -inf.+inf.i "-inf.0+inf.0i" -inf.0+inf.0i "0/0-1/0i" 0/0-1/0i
"-inf.-inf.i" -inf.-inf.i "-inf.0-inf.0i" -inf.0-inf.0i "0/0+0/0i" 0/0+0/0i
"-inf.+nan.i" -inf.+nan.i "-inf.0+nan.0i" -inf.0+nan.0i "0/0-0/0i" 0/0+0/0i
"-inf.-nan.i" "-inf.0-nan.0i" -inf.0+nan.0i
"+nan.+inf.i" +nan.+inf.i "+nan.0+inf.0i" +nan.0+inf.0i
"+nan.-inf.i" +nan.-inf.i "+nan.0-inf.0i" +nan.0-inf.0i
"+nan.+nan.i" +nan.+nan.i "+nan.0+nan.0i" +nan.0+nan.0i
"+nan.-nan.i" "+nan.0-nan.0i" +nan.0+nan.0i
"-nan.+inf.i" "-nan.0+inf.0i" +nan.0+inf.0i
"-nan.-inf.i" "-nan.0-inf.0i" +nan.0-inf.0i
"-nan.+nan.i" "-nan.0+nan.0i" +nan.0+nan.0i
"-nan.-nan.i" "-nan.0-nan.0i" +nan.0+nan.0i
"+1/0i" ... [g]
============================================================================
[g] *** ERROR -- REAL expected
(make-rectangular #f 1)

Notes:

* Empty entries indicate #f was returned.
* MzScheme string->number accepts imaginary infinities only with a
real 0 part prepended, eg. "0+inf.0i".


Reading and Writing Infinities
==============================

The floating-point string conversions in GNU glibc 2.2 support reading
and writing of infinite values:

* inf is positive infinity
* -inf is negative infinity
* nan is Not-a-Number.

I have not discovered which standard specifies these codes for string
representation, if any. They may have been inherited from the IEEE
754 nomenclature.

Although not specified by the Revised^5 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 # in 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 i must be prefixed
by a sign, making +#.#i ambiguous. 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:

* +inf. versus +inf.0
* -inf. versus -inf.0
* +nan. versus +nan.0

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 prints infinities as rational numbers with denominators of "0".
SCM's existing reader decoded this format without modification:

* 1/0 is positive infinity;
* -1/0 is negative infinity; and
* 0/0 is NaN (not a number).

SCM's infinities look like exact rational numbers, but are actually
inexacts. The inclusion of a decimal point (eg. 1/0.) would not be
R5RS-compliant syntax. Prepending #i (eg. #i1/0, #i-1/0, #i0/0) is
less evocative than the compact 3 and 4 character versions.

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.

Division by zero
================

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 implementations.

Table 3: Division by Zero

glibc Mz MIT Scheme
quotient SCM Guile Bigloo 2.2 Elk Gambit Scheme Scheme 48
5d8* 1.3.4 2.5c printf 3.0 3.0 202 7.8 0.57
==========================================================================
(/ 0.) 1/0 +#.# +#.# inf Inf.0 +inf. +inf.0 [t] [r]
(/ -1. 0.) -1/0 -#.# -#.# inf -Inf.0 -inf. -inf.0 [t] [r]
(/ -1 0.) -1/0 -#.# -#.# -inf -Inf.0 -inf. -inf.0 [t] [r]
(/ 0. 0.) 0/0 #.# #.# nan NaN +nan. +nan.0 [a] [r]
(/ 0 0.) 0/0 #.# #.# nan NaN +nan. 0 0 [r]
(/ -1. 0) -1/0 -#.# -#.# -inf [e] [g] [d] [t] [r]
(/ 0. 0) 0/0 #.# #.# nan [e] [g] [d] [a] [r]
(/ 0 0) 0/0 #.# [b] [c] [e] [g] [d] [s] [r]
(/ 0) 1/0 +#.# [b] [c] [e] [g] [d] [s] [r]
(/ -1 0) -1/0 -#.# [b] [c] [e] [g] [d] [s] [r]
==========================================================================
* Earlier versions of SCM printed identically to Guile.

[a] ;Anonymous arithmetic error

[b] *** ERROR:bigloo:arithmetic procedure:
`floating point' exception -- reached

[c] Floating point exception

[d] /: division by zero

[e] /: argument out of range: 0

[g] *** ERROR IN (stdin)@7.19 -- Division by zero

[r] Error: rational division by zero

[s] ;Division by zero signaled by /.

[t] ;Division by zero


Table 4: Properties of special quotients
==========================================================================
inexact exact rational integer real positive zero negative
1/0 * * * * *
SCM -1/0 * * * * *
0/0 * * *

+#.# * * * * *
Guile -#.# * * * * *
#.# * * *

+inf.0 * * * * *
MzScheme -inf.0 * * * * *
+nan.0 * * *

Inf.0 * * * * *
Elk -Inf.0 * * * * *
NaN * *

+#.# * * * *
Bigloo -#.# * * * *
#.# * * *

+inf. * * *
Gambit -inf. * * *
+nan. * *
==========================================================================

Table 4 shows the numerical properties of each of the special values.
None of the implementations support exact infinities. The only
variations are in the RATIONAL and INTEGER columns.

Discussion
==========

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 strtod() and scanf() do not ignore.

The denominator of 0 infinity representations improve both aspects.

Conclusion
==========

This survey of infinities in Scheme shows general agreement among
implementations that scalar infinities are inexact reals. Infinities
are allowed as independent real and imaginary components of complex
numbers.

Several implementations provide read/write invariance of inexact
complex infinities; but their syntaxes are incompatible. Settling on
one signed-nan-inf or denominator-of-0 format for infinities would
eliminate needless incompatibility and augment Scheme's substantial
numerical capabilities.

Copyright 2003 Aubrey Jaffer
-----------------------------------------------------------------------
I am a guest and *not* a member of the MIT Artificial Intelligence Lab.
My actions and comments do not reflect in any way on MIT.

agj @ alum.mit.edu Go Figure!

David Rush

unread,
Aug 11, 2003, 7:18:47 AM8/11/03
to
Aubrey Jaffer <a...@alum.mit.edu> writes:
> Reading and Writing Infinities
> ==============================
>
> The floating-point string conversions in GNU glibc 2.2 support reading
> and writing of infinite values:
>
> * inf is positive infinity
> * -inf is negative infinity
> * nan is Not-a-Number.
>
> I have not discovered which standard specifies these codes for string
> representation, if any. They may have been inherited from the IEEE
> 754 nomenclature.

> The richness of Scheme's syntax of numerical constants provides


> several opportunities to support infinities.

Indeed. I'm surprised that you didn't mention a slight variation of

> Gambit and MzScheme both use strings derived from IEEE-754
> nomenclature:
>
> * +inf. versus +inf.0
> * -inf. versus -inf.0
> * +nan. versus +nan.0

which would be

#+inf
#-inf
#nan

I have a pre-draft SRFI (for extended literal constants) floating
around on my drive at home which proposes just such a thing for
Schemes which support IEEE infinities and NaNs. Is there a problem
with my proposed syntax (apart from the fact that no-one currently
implements it)?

> 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".

david rush
--
He who would make his own liberty secure, must guard even his enemy
from repression
-- Thomas Paine

Aubrey Jaffer

unread,
Aug 11, 2003, 10:16:09 AM8/11/03
to
David Rush <dr...@aol.net> writes:

> Aubrey Jaffer <a...@alum.mit.edu> writes:
> > Reading and Writing Infinities
> > ==============================
>

> > The richness of Scheme's syntax of numerical constants provides
> > several opportunities to support infinities.
>
> Indeed. I'm surprised that you didn't mention a slight variation of
>
> > Gambit and MzScheme both use strings derived from IEEE-754
> > nomenclature:
> >
> > * +inf. versus +inf.0
> > * -inf. versus -inf.0
> > * +nan. versus +nan.0
>
> which would be
>
> #+inf
> #-inf
> #nan
>
> I have a pre-draft SRFI (for extended literal constants) floating
> around on my drive at home which proposes just such a thing for
> Schemes which support IEEE infinities and NaNs. Is there a problem
> with my proposed syntax (apart from the fact that no-one currently
> implements it)?

#+inf and #-inf conditionally (on presence of feature INF) skip the next
s-expression in Common-Lisp and SCM.

Scott G. Miller

unread,
Aug 11, 2003, 10:51:02 AM8/11/03
to
David Rush wrote:

> Indeed. I'm surprised that you didn't mention a slight variation of
>
>
>>Gambit and MzScheme both use strings derived from IEEE-754
>>nomenclature:
>>
>> * +inf. versus +inf.0
>> * -inf. versus -inf.0
>> * +nan. versus +nan.0
>
>
> which would be
>
> #+inf
> #-inf
> #nan
>
> I have a pre-draft SRFI (for extended literal constants) floating
> around on my drive at home which proposes just such a thing for
> Schemes which support IEEE infinities and NaNs. Is there a problem
> with my proposed syntax (apart from the fact that no-one currently
> implements it)?
>

I'm not a fan of the above. Many Schemes dispatch on sharp constants
using the first character following the sharp. This wouldn't look very
nice in that respect. Better would be #!+inf, #!-inf, #!nan.

However, I'm actually a bigger fan of the denominator-of-0 approach, as
it is more mathematically explicit as to what is indicated.

Scott

David Rush

unread,
Aug 11, 2003, 1:05:21 PM8/11/03
to
"Scott G. Miller" <scgm...@freenetproject.org> writes:
> David Rush wrote:
> > #+inf
> > #-inf
> > #nan

> > Is there a problem
> > with my proposed syntax (apart from the fact that no-one currently
> > implements it)?
>
> I'm not a fan of the above. Many Schemes dispatch on sharp
> constants using the first character following the sharp. This
> wouldn't look very nice in that respect. Better would be #!+inf,
> #!-inf, #!nan.

Ok, although I think that #!-inf looks a bit clunky.

> However, I'm actually a bigger fan of the denominator-of-0 approach,
> as it is more mathematically explicit as to what is indicated.

Is it really? What about (exp 9876543.4)? denominator-of-zero actually
obfuscates the source of that 'infinity'

Shiro Kawai

unread,
Aug 12, 2003, 6:53:39 AM8/12/03
to
Slightly off-topic, but if we have NaN in Scheme, it's nice
that we agree on the result of comparison of NaN's.

As far as I know, all implementations that support NaN
return #f for (= nan nan), which I think is IEEE754 compliant.
However, some implementations (AFAIK, all but Bigloo)
return #t for (eqv? nan nan) in some cases.

SCM5d8
> (let ((nan (/ 0.0 0.0))) (eqv? nan nan))
#t
> (let ((nan (/ 0.0 0.0))) (= nan nan))
#f

Petite Chez Scheme 6.0a
> (let ((nan (/ 0.0 0.0))) (eqv? nan nan))
#t
> (let ((nan (/ 0.0 0.0))) (= nan nan))
#f

Guile 1.6.0
guile> (let ((nan (/ 0.0 0.0))) (eqv? nan nan))
#t
guile> (let ((nan (/ 0.0 0.0))) (= nan nan))
#f

R5RS says "The eqv? procedure returns #f if ...
obj1 and obj2 are numbers for which the = procedure returns #f",
so should these eqv?'s always return #f?

Cf. http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche:NaN%A4%CE%B0%B7%A4%A4&l=en

Aubrey Jaffer

unread,
Aug 13, 2003, 11:30:52 AM8/13/03
to
sh...@acm.org (Shiro Kawai) writes:
>
> As far as I know, all implementations that support NaN
> return #f for (= nan nan), which I think is IEEE754 compliant.
> However, some implementations (AFAIK, all but Bigloo)
> return #t for (eqv? nan nan) in some cases.

Excellent catch! The appended patch fixes SCM so that:

> (= 0/0 0/0)
#f
> (eqv? 0/0 0/0)
#f
> (let ((nan 0/0)) (= nan nan))
#t
> (let ((nan 0/0)) (eqv? nan nan))
#t

Also fixed is (inexact->exact 0/0), which was never returning.

-=-=-=-=-

*** scl.c.~1.51.~ Tue Aug 12 14:17:07 2003
--- scl.c Wed Aug 13 11:15:42 2003
***************
*** 1112,1117 ****
--- 1113,1119 ----
# else
ASRTGO(NIMP(y) && INEXP(y), bady);
# endif
+ if (x==y) return BOOL_T;
if (REALPART(x) != REALPART(y)) return BOOL_F;
if CPLXP(x)
return (CPLXP(y) && (IMAG(x)==IMAG(y))) ? BOOL_T : BOOL_F;
***************
*** 2356,2362 ****
SCM ans = MAKINUM((long)u);
if (INUM(ans)==(long)u) return ans;
}
! ASRTGO(!IS_INF(u), badz); /* problem? */
return dbl2big(u);
}
# else
--- 2358,2364 ----
SCM ans = MAKINUM((long)u);
if (INUM(ans)==(long)u) return ans;
}
! ASRTGO(!(IS_INF(u) || (u)!=(u)), badz); /* problem? */
return dbl2big(u);
}
# else

Bradley J Lucier

unread,
Aug 13, 2003, 12:23:48 PM8/13/03
to
In article <vht4r0l...@aarau.ai.mit.edu>,

Aubrey Jaffer <a...@alum.mit.edu> wrote:
>sh...@acm.org (Shiro Kawai) writes:
>>
>> As far as I know, all implementations that support NaN
>> return #f for (= nan nan), which I think is IEEE754 compliant.
>> However, some implementations (AFAIK, all but Bigloo)
>> return #t for (eqv? nan nan) in some cases.
>
>Excellent catch! The appended patch fixes SCM so that:
>
>> (= 0/0 0/0)
>#f
>> (eqv? 0/0 0/0)
>#f
>> (let ((nan 0/0)) (= nan nan))
>#t
>> (let ((nan 0/0)) (eqv? nan nan))
>#t

At the 1998 Scheme workshop in Baltimore I argued that the semantics of =
and eqv? should be decoupled. = is about numerics; eqv? is about equivalence
under substitution. This is how the next version of Gambit will do it
(and perhaps the current version as well), and I think this is the right way
to go. I can't understand your reasoning at all; under IEEE 754, (= nan nan)
should always be false.

Brad

[zakon:~] lucier% /usr/local/Gambit-C/bin/gsc
Gambit Version 4.0 beta 1

> (eqv? (/ 0. 0.) (/ 0. 0.))
#t
> (= (/ 0. 0.) (/ 0. 0.))
#f
> (let ((nan (/ 0. 0.))) (eqv? nan nan))
#t
> (let ((nan (/ 0. 0.))) (= nan nan))
#f

Aubrey Jaffer

unread,
Aug 13, 2003, 7:59:13 PM8/13/03
to
b...@cs.purdue.edu (Bradley J Lucier) writes:

> In article <vht4r0l...@aarau.ai.mit.edu>,
> Aubrey Jaffer <a...@alum.mit.edu> wrote:
> >sh...@acm.org (Shiro Kawai) writes:
> >>
> >> As far as I know, all implementations that support NaN
> >> return #f for (= nan nan), which I think is IEEE754 compliant.
> >> However, some implementations (AFAIK, all but Bigloo)
> >> return #t for (eqv? nan nan) in some cases.
> >
> >Excellent catch! The appended patch fixes SCM so that:
> >
> >> (= 0/0 0/0)
> >#f
> >> (eqv? 0/0 0/0)
> >#f
> >> (let ((nan 0/0)) (= nan nan))
> >#t
> >> (let ((nan 0/0)) (eqv? nan nan))
> >#t
>
> At the 1998 Scheme workshop in Baltimore I argued that the semantics
> of = and eqv? should be decoupled. = is about numerics; eqv? is about
> equivalence under substitution. This is how the next version of
> Gambit will do it (and perhaps the current version as well), and I
> think this is the right way to go. I can't understand your reasoning
> at all; under IEEE 754, (= nan nan) should always be false.

R5RS *recommends* that IEEE-754 be followed, but
http://swissnet.ai.mit.edu/~jaffer/r5rs_8.html#SEC49
R5RS "Equivalence predicates" requires:

`Eq?''s behavior on numbers and characters is
implementation-dependent, but it will always return either true or
false, and will return true only when `eqv?' would also return true.

Under this rule, even Bigloo is non-compliant:

Bigloo (2.5c)
Welcome to the interpreter

1:=> (let ((nan (/ 0. 0.))) (eq? nan nan))
#t
1:=> (let ((nan (/ 0. 0.))) (eqv? nan nan))
#f
1:=> (let ((nan (/ 0. 0.))) (= nan nan))
#f

> Gambit Version 4.0 beta 1
>
> > (eqv? (/ 0. 0.) (/ 0. 0.))
> #t
> > (= (/ 0. 0.) (/ 0. 0.))
> #f
> > (let ((nan (/ 0. 0.))) (eqv? nan nan))
> #t
> > (let ((nan (/ 0. 0.))) (= nan nan))
> #f

This same section of R5RS mandates that EQV? follow = for numbers of the
same type.

-=-=-=-=-

I searched through IEEE-754; it is silent about the string
representations of infinities and NaN.

I have updated http://swissnet.ai.mit.edu/~jaffer/III/RAWI with data
collected from Kawa-1.7.

Bradley J Lucier

unread,
Aug 13, 2003, 10:28:50 PM8/13/03
to
In article <vhtoeyt...@chur.ai.mit.edu>,

Aubrey Jaffer <a...@alum.mit.edu> wrote:
>b...@cs.purdue.edu (Bradley J Lucier) writes:
>R5RS "Equivalence predicates" requires:
>
> `Eq?''s behavior on numbers and characters is
> implementation-dependent, but it will always return either true or
> false, and will return true only when `eqv?' would also return true.

My proposal follows this.

>> Gambit Version 4.0 beta 1
>>
>> > (eqv? (/ 0. 0.) (/ 0. 0.))
>> #t
>> > (= (/ 0. 0.) (/ 0. 0.))
>> #f
>> > (let ((nan (/ 0. 0.))) (eqv? nan nan))
>> #t
>> > (let ((nan (/ 0. 0.))) (= nan nan))
>> #f
>
>This same section of R5RS mandates that EQV? follow = for numbers of the
>same type.

Yes, and I'm suggesting a change.

This is part of a larger proposal I made to the '98 Scheme workshop that is
included below. Will Clinger said afterwards that, in his opinion, only the
definition of eqv? needed to be changed to implement these suggestions.

Brad

Proposals for integrating IEEE Floating-Point Arithmetic Standards 754
and 854 with RnRS.

I've gone over all of the back issues of the rrrs-authors mailing list
(OK, I haven't read everything about exceptions and modules, but ...),
and I would like to make certain proposals for Scheme arithmetic that I
believe would bring it more in line with IEEE 754 and 854 arithmetic,
*if* this arithmetic is used to implements (some) inexact numbers in
a Scheme system. If other inexact number systems are used, then my
suggestions would have no force.

Note that the IEEE arithmetic standards say nothing about mixing integer
(or exact) arithmetic with floating-point (or inexact) arithmetic; many of
my suggestions below try to Do-the-Right-Thing (TM) in these situations.

General Principles:

1. If an expression contains Not-a-Numbers (NaNs), and the same result
would be obtained for any substitution of those NaNs by finite or infinite
numbers, then that result should be returned.

2. I'm motivated by the following ansatz, taken from the
sequence+ultrafilter construction of the non-standard reals. On input,
+0. represents all sequences of positive numbers tending to zero;
-0. represents all sequences of negative numbers tending to zero;
+inf. represents all sequences of numbers tending to positive infinity;
-inf. represents all sequences of numbers tending to negative infinity;
and NaN represents all sequences of numbers. Results of operations
between these quantities and exact numbers should be motivated by applying
the same operation to all numbers of the sequence, e.g.,

(* 0 NaN) => the sequence (* 0 x1) (* 0 x2) (* 0 x3) .... for any (x1,
x2, ...)
=> the sequence 0 0 0 0 0 0 0 ... => exact 0

3. As a consequence of (2), +0. cannot be considered to lie exactly on
zero, it lies a little to the right of zero on the number line; similarly,
-0. lies a little to the left of zero.

Recommendations:

1. Infinities:

I suggest that Scheme adopt standard read and write forms for IEEE
positive and negative infinity, e.g., +inf. -inf.

2. Not-a-Numbers:

I suggest that Scheme adopt standard write forms for IEEE NaNs that
at least indicate the sign of the NaN, e.g., +nan. -nan.

3. eqv?:

If x and y are two inexact numbers implemented as IEEE floating point
numbers, then

(eqv? x y) => #t

if and only if x and y have the same base, sign, number of exponent
digits, biased exponents, number of significand digits, and significands.

Rationale: No matter what bit-level representation is used for IEEE
floating-point numbers (and Motorola, Intel, and others use several,
beyond the issue of byte ordering), the quantities I specified above
are well-defined by IEEE 754 and 854.

The current definition of eqv? does not distinguish between -0. and +0. (since
they are both equal (in the sense of Scheme =) and inexact. However,
operations on +0. and -0. can yield very different results, e.g.,

(/ 1. -0) => -inf.
(/ 1. +0.) => +inf.

Also, since

(= x x) => #f

if x is a NaN, the current definition would say that any Nan is not
eqv to itself, which doesn't make much sense.

4. Non-coercion of exact 0:

If x is any number, and 0 represents exact zero, then

(+ x 0) => x
(- x 0) => x
(- 0 x) => (- x)
(* x 0) => 0
(/ 0 x) => 0
(/ x 0) => error

Rationale: These results follow from a generalization of Priciple 1 that
goes as follows: If an expression contains inexact numbers, and the
result of the expression does not change no matter what exact numbers
are substituted for the inexact numbers, then that result should be
returned. There are other reasons for wanting to do this; the biggest
practical reason is that it makes operations between reals and complexes,
where the real x is coerced to (make-rectangular x 0), *much* easier
to get correct. Here are some other arguments.

IEEE arithmetic has two zeros associated with the two affine
infinities. Thus, there is no clear a priori choice of which inexact
0 (+0. or -0.) exact zero should be coerced to in these expressions.

IBM and Motorola indicate in their notes on the fused-multiply-add
instruction

a*b+c => d

that if one wants to only multiply two numbers, then one needs to set
d to -0., since if a*b is -0.,

-0. + +0. => +0.

will give the wrong result. In a similar way, the exact zero in

(+ x 0)

should be coerced to -0., not +0., when x is an IEEE floating-point
number. Similar analyses can be done with the other expressions given
above.

These rules simplify many basic arithmetic computations on complex numbers
with IEEE-conforming real and imaginary parts.

5. Extending the order operators to 0 or 1 arguments.

For any numbers x

(< x) => #t
(= x) => #t
etc.

Also

(<) => #t
etc.

Rationale: These operators are defined as asking whether a sequence
satisfies a certain order relationship. These order relationships are
automatically satisfied by sequences of length 0 or 1. This would simplify
(apply op lst) if lst is a list of 0 or 1 elements.

Note that even though

(op NaN x) => #f

for any order op, if

(op x) => #t

for any finite or infinite x (which I believe should be true), then

(op NaN) => #t

by General Principle 1.

6. Transcendental functions with special exact arguments

I think it's time to require

(log 1) => 0
(exp 0) => 1
(sin 0) => 0
(cos 0) => 1
(tan 0) => 0
(atan 0) => 0
(asin 0) => 0

etc.

7. Complex numbers with imaginary parts +0. or -0.

If IEEE arithmetic had only one zero, then I might be willing to have, e.g.,

(real? 1+0.i) => #t

However, it has two zeros, and I believe that those zeros should be considered
as lying either slightly above or slightly below the real axis (as the
specifications of the branch cuts of many transcendental functions already
consider them), so if the imaginary part of a number is represented using
IEEE arithmetic, I suggest

(real? 1.+0.i) => #f
(real? 1.-0.i) => #f

but still

(real? 1.+0i) => #t

If 1.+0.i is not real, it is not rational, integer, etc.

I realize that a similar argument could be made that Scheme should have

(integer? +0.) => #f
(integer? -0.) => #f

but I'm not sure that would be acceptable.

8. sqrt and log

If an implementation does not support complex numbers, and x is less
than zero then

(sqrt x) => nan.

as is required by IEEE 754; note that IEEE 754 also requires

(sqrt -0.) => -0.

and

(sqrt nan.) => nan.

I suggest that if x is not a NaN, and the sign of x is negative, then

(log x) => nan.

(log +0.) => -inf.

(log nan.) => nan.

without noting the sign of the NaNs. The first two requirements could
follow from my General Principle 2.

If an implementation does support complex numbers, then an argument
could be made that

(sqrt nan) => nan.+nan.i

following principle 2; similarly for log. However, I do not suggest
that the results of (sqrt nan) or (log nan) depend on whether complex
numbers are implemented.

9. magnitude

If z is a complex number, and one of the components of z is positive or
negative infinity, then

(magnitude z) => +inf.

whether or not the other component is a NaN. This is from Principle 1
(and is given as an example in some of Kahan's lecture notes).

10. max and min

There are two ways to deal with NaN arguments in max and min---either
return one of the NaN arguments, or treat NaN arguments as missing values.
The second choice is what Kahan suggests and what Apple implements.

I suggest we pick one of these ways of dealing with NaNs so that programs
can be portable; I don't care which way, but I generally don't like
differing with Kahan without a reason.

11. rational?

If arg is +inf., -inf., or a NaN, then

(real? arg) => #t

but

(rational? arg) => #f

Rationale: while the usual operations of arithmetic are defined in IEEE
754 and 854 as well for +inf., -inf., and NaNs as they are for other
floating-point numbers, there are some Scheme operations that do not
make sense with these arguments---numerator, denominator, round, etc.
(See below.) rational? should be a predicate that checks whether these
operators will return a reasonable result.

12. truncate, round, ceiling, floor

If op is one of truncate, round, ceiling, floor, and numerator, then

(op -0.) => -0.

and

(denominator -0.) => 1.

If op is any of the previous operators, then

(rational? arg) => #f

implies

(op arg) => error

Rationale: These operations should preserve the sign of zero, since -0.
is as much an integer as +0.

The listed ops do not make sense for objects that are not rational?.

13. rationalize

If x is not rational? (see above) or y is not greater or equal to zero

(rationalize x y) => error

If y is +inf. and x is inexact rational then

(rationalize x y) => 0.

or if x is exact rational then

(rationalize x y) => 0

13. atan, asin, acos, log, etc.

The complex functions with branch cuts should be changed to conform
to the following pages in the CL Hyperspec:

http://www.harlequin.com/education/books/HyperSpec/Body/fun_asincm_acoscm_atan.html

http://www.harlequin.com/education/books/HyperSpec/Issues/iss069-writeup.html

These changes conform to the interpretation given above of +0. and
-0. lying to the right and to the left of exact zero.

Aubrey Jaffer

unread,
Aug 16, 2003, 12:47:53 AM8/16/03
to
b...@cs.purdue.edu (Bradley J Lucier) writes:

> In article <vhtoeyt...@chur.ai.mit.edu>,
> Aubrey Jaffer <a...@alum.mit.edu> wrote:
> >b...@cs.purdue.edu (Bradley J Lucier) writes:
> >R5RS "Equivalence predicates" requires:
> >
> > `Eq?''s behavior on numbers and characters is
> > implementation-dependent, but it will always return either true or
> > false, and will return true only when `eqv?' would also return true.
>
> My proposal follows this.
>
> >> Gambit Version 4.0 beta 1
> >>
> >> > (eqv? (/ 0. 0.) (/ 0. 0.))
> >> #t
> >> > (= (/ 0. 0.) (/ 0. 0.))
> >> #f
> >> > (let ((nan (/ 0. 0.))) (eqv? nan nan))
> >> #t
> >> > (let ((nan (/ 0. 0.))) (= nan nan))
> >> #f

The reflexivity of equality is one of the most fundamental
mathematical principles. Is there any branch of mathematics in which
an object is not equal to itself? Acquiescence with floating-point
NaNs not being equal to themselves was responsible for non-conforming
(with R5RS) behavior in every Scheme implemenation tested.

> >
> >This same section of R5RS mandates that EQV? follow = for numbers of the
> >same type.
>

> Yes, and I'm suggesting a change:


>
> Proposals for integrating IEEE Floating-Point Arithmetic Standards 754
> and 854 with RnRS.
>
> I've gone over all of the back issues of the rrrs-authors mailing list
> (OK, I haven't read everything about exceptions and modules, but ...),
> and I would like to make certain proposals for Scheme arithmetic that I
> believe would bring it more in line with IEEE 754 and 854 arithmetic,
> *if* this arithmetic is used to implements (some) inexact numbers in
> a Scheme system. If other inexact number systems are used, then my
> suggestions would have no force.

Why would only Scheme be changing? Scheme already corrects some
deficiencies of IEEE-754. In "How to read floating point numbers
accurately" [ACM PLDI, 1990], William Clinger writes:

Consider the problem of converting decimal scientific notation for a
number into the best binary floating point approximation to that
number, for some fixed precision. This problem cannot be solved
using arithmetic of any fixed precision. Hence the IEEE Standard
for Binary Floating-Point Arithmetic does not require the result of
such a conversion to be the best approximation.

So reason has priority over IEEE-754 in defining Scheme.

> Note that the IEEE arithmetic standards say nothing about mixing integer
> (or exact) arithmetic with floating-point (or inexact) arithmetic; many of
> my suggestions below try to Do-the-Right-Thing (TM) in these situations.
>
> General Principles:
>
> 1. If an expression contains Not-a-Numbers (NaNs), and the same result
> would be obtained for any substitution of those NaNs by finite or infinite
> numbers, then that result should be returned.
>
> 2. I'm motivated by the following ansatz, taken from the
> sequence+ultrafilter construction of the non-standard reals. On input,
> +0. represents all sequences of positive numbers tending to zero;
> -0. represents all sequences of negative numbers tending to zero;
> +inf. represents all sequences of numbers tending to positive infinity;
> -inf. represents all sequences of numbers tending to negative infinity;
> and NaN represents all sequences of numbers. Results of operations
> between these quantities and exact numbers should be motivated by applying
> the same operation to all numbers of the sequence, e.g.,
>
> (* 0 NaN) => the sequence (* 0 x1) (* 0 x2) (* 0 x3) .... for any (x1, x2, ...)
> => the sequence 0 0 0 0 0 0 0 ... => exact 0
>
> 3. As a consequence of (2), +0. cannot be considered to lie exactly on
> zero, it lies a little to the right of zero on the number line; similarly,
> -0. lies a little to the left of zero.

Similarly, +0+1 would behave differently as an argument to

(lambda (x) (/ 1 (- x 1)))

than would -0+1. If we are to have shadings of every rational number,
then a zero-divisor transcendental element (eg. infinitesimal) must be
adjoined to the field. This is not difficult; most Schemes implement
complex numbers as reals (actually the rationals) with +i adjoined.

> Recommendations:
>
> 1. Infinities:
>
> I suggest that Scheme adopt standard read and write forms for IEEE
> positive and negative infinity, e.g., +inf. -inf.

Which IEEE specification makes the strings "+inf." and "-inf."
standard? The trailing periods are not recognized by glibc-2.2.
The "IEEE Standard for Binary Floating-Point Arithmetic" [ANSI/IEEE
Std 754­1985] states:

... Over/underflow, NaNs, and infinities encountered during binary to
decimal conversion should be indicated to the user by appropriate
strings. NaNs encoded in decimal strings are not specified in this
standard.

> 2. Not-a-Numbers:
>
> I suggest that Scheme adopt standard write forms for IEEE NaNs that
> at least indicate the sign of the NaN, e.g., +nan. -nan.

Which sign of NaN should (sin (/ 1.0 0.0)) return?

> 3. eqv?:
>
> If x and y are two inexact numbers implemented as IEEE floating
> point numbers, then
>
> (eqv? x y) => #t
>
> if and only if x and y have the same base, sign, number of exponent
> digits, biased exponents, number of significand digits, and significands.

What about infinities?

> Rationale: No matter what bit-level representation is used for IEEE
> floating-point numbers (and Motorola, Intel, and others use several,
> beyond the issue of byte ordering), the quantities I specified above
> are well-defined by IEEE 754 and 854.
>
> The current definition of eqv? does not distinguish between -0. and
> +0. (since they are both equal (in the sense of Scheme =) and
> inexact. However, operations on +0. and -0. can yield very
> different results, e.g.,
>
> (/ 1. -0) => -inf.
> (/ 1. +0.) => +inf.
>
> Also, since
>
> (= x x) => #f
>
> if x is a NaN, the current definition would say that any Nan is not
> eqv to itself, which doesn't make much sense.

I agree. So I am changing SCM so (= NaN NaN) ==> #t.

> 4. Non-coercion of exact 0:
>
> If x is any number, and 0 represents exact zero, then
>
> (+ x 0) => x
> (- x 0) => x
> (- 0 x) => (- x)
> (* x 0) => 0
> (/ 0 x) => 0
> (/ x 0) => error
>
> Rationale: These results follow from a generalization of Priciple 1
> that goes as follows: If an expression contains inexact numbers, and
> the result of the expression does not change no matter what exact
> numbers are substituted for the inexact numbers, then that result
> should be returned.

I don't find this distinction between exact and inexact compelling.
What if the substitution of the exact number causes an error?

> There are other reasons for wanting to do this; the biggest
> practical reason is that it makes operations between reals and
> complexes, where the real x is coerced to (make-rectangular x 0),
> *much* easier to get correct.

Complex coercions already work for me. Can you give an example where
they don't?

> Here are some other arguments. ...


>
> 5. Extending the order operators to 0 or 1 arguments.
>
> For any numbers x
>
> (< x) => #t
> (= x) => #t
> etc.
>
> Also
>
> (<) => #t
> etc.
>
> Rationale: These operators are defined as asking whether a sequence
> satisfies a certain order relationship. These order relationships
> are automatically satisfied by sequences of length 0 or 1. This
> would simplify (apply op lst) if lst is a list of 0 or 1 elements.

This is not specific to floating-point but is a reasonable idea.
I grepped through the rrrs-authors archive but didn't find this
discussed.

> 6. Transcendental functions with special exact arguments
>
> I think it's time to require
>
> (log 1) => 0
> (exp 0) => 1
> (sin 0) => 0
> (cos 0) => 1
> (tan 0) => 0
> (atan 0) => 0
> (asin 0) => 0
> etc.

An essential feature of trigonometric functions is that they are
periodic. When you treat just one value of argument specially, you
make it non-periodic.

What problem does requiring this solve?

> 7. Complex numbers with imaginary parts +0. or -0. ...

The rest is more signs dancing on zeros. 1/x is no more special a
function than 1/(x-1) or 1/(x-2). Having infinitesimals only around
zero just doesn't work. Signs of zeros are unnecessary and should be
ignored.

If you start with a system which is inconsistent, then you can prove
anything about it. Without first fixing IEEE-754's inconsistent
elements, constructs exercising those elements will suffer.

Bradley J Lucier

unread,
Aug 16, 2003, 3:22:29 PM8/16/03
to
In article <m2ptj6r...@aubrey.jaffer>,

Aubrey Jaffer <a...@alum.mit.edu> wrote:
>b...@cs.purdue.edu (Bradley J Lucier) writes:
>
>> In article <vhtoeyt...@chur.ai.mit.edu>,
>> Aubrey Jaffer <a...@alum.mit.edu> wrote:
>> >b...@cs.purdue.edu (Bradley J Lucier) writes:
>> >R5RS "Equivalence predicates" requires:
>> >
>> > `Eq?''s behavior on numbers and characters is
>> > implementation-dependent, but it will always return either true or
>> > false, and will return true only when `eqv?' would also return true.
>>
>> My proposal follows this.
>>
>> >> Gambit Version 4.0 beta 1
>> >>
>> >> > (eqv? (/ 0. 0.) (/ 0. 0.))
>> >> #t
>> >> > (= (/ 0. 0.) (/ 0. 0.))
>> >> #f
>> >> > (let ((nan (/ 0. 0.))) (eqv? nan nan))
>> >> #t
>> >> > (let ((nan (/ 0. 0.))) (= nan nan))
>> >> #f
>
>The reflexivity of equality is one of the most fundamental
>mathematical principles. Is there any branch of mathematics in which
>an object is not equal to itself? Acquiescence with floating-point
>NaNs not being equal to themselves was responsible for non-conforming
>(with R5RS) behavior in every Scheme implemenation tested.

You know as well as I do that there are several (many) notions of equality
in lisp(s). I'm suggesting that an object is always eq?/eqv?/equal? to
itself; it happens to be useful to have a NaN be not = to itself.

>> >This same section of R5RS mandates that EQV? follow = for numbers of the
>> >same type.
>>
>> Yes, and I'm suggesting a change:
>>
>> Proposals for integrating IEEE Floating-Point Arithmetic Standards 754
>> and 854 with RnRS.
>>
>> I've gone over all of the back issues of the rrrs-authors mailing list
>> (OK, I haven't read everything about exceptions and modules, but ...),
>> and I would like to make certain proposals for Scheme arithmetic that I
>> believe would bring it more in line with IEEE 754 and 854 arithmetic,

>> *if* this arithmetic is used to implement (some) inexact numbers in


>> a Scheme system. If other inexact number systems are used, then my
>> suggestions would have no force.
>
>Why would only Scheme be changing? Scheme already corrects some
>deficiencies of IEEE-754. In "How to read floating point numbers
>accurately" [ACM PLDI, 1990], William Clinger writes:
>
> Consider the problem of converting decimal scientific notation for a
> number into the best binary floating point approximation to that
> number, for some fixed precision. This problem cannot be solved
> using arithmetic of any fixed precision. Hence the IEEE Standard
> for Binary Floating-Point Arithmetic does not require the result of
> such a conversion to be the best approximation.
>
>So reason has priority over IEEE-754 in defining Scheme.

Having exact binary-decimal conversion in Scheme in no way contradicts
IEEE-754, it's a very reasonable extension to IEEE-754.

>> 3. As a consequence of (2), +0. cannot be considered to lie exactly on
>> zero, it lies a little to the right of zero on the number line; similarly,
>> -0. lies a little to the left of zero.
>
>Similarly, +0+1 would behave differently as an argument to
>
> (lambda (x) (/ 1 (- x 1)))
>
>than would -0+1. If we are to have shadings of every rational number,
>then a zero-divisor transcendental element (eg. infinitesimal) must be
>adjoined to the field. This is not difficult; most Schemes implement
>complex numbers as reals (actually the rationals) with +i adjoined.

What do you mean here by +0+1 and -0+1? Your notation seems quite nonstandard.

>> Recommendations:
>>
>> 1. Infinities:
>>
>> I suggest that Scheme adopt standard read and write forms for IEEE
>> positive and negative infinity, e.g., +inf. -inf.
>
>Which IEEE specification makes the strings "+inf." and "-inf."
>standard? The trailing periods are not recognized by glibc-2.2.
>The "IEEE Standard for Binary Floating-Point Arithmetic" [ANSI/IEEE
>Std 754­1985] states:
>
> ... Over/underflow, NaNs, and infinities encountered during binary to
> decimal conversion should be indicated to the user by appropriate
> strings. NaNs encoded in decimal strings are not specified in this
> standard.

"E.g." means "for example"; your comments are addressing something I didn't
write.

>> 2. Not-a-Numbers:
>>
>> I suggest that Scheme adopt standard write forms for IEEE NaNs that
>> at least indicate the sign of the NaN, e.g., +nan. -nan.
>
>Which sign of NaN should (sin (/ 1.0 0.0)) return?

Signs of NaNs could be useful in creating, e.g., signalling versus
non-signalling NaNs. If you have a system that deals with both types of
NaNs, and uses the signs of those NaNs to differentiate them, it would be
nice to have an input notation for this.

>> 3. eqv?:
>>
>> If x and y are two inexact numbers implemented as IEEE floating
>> point numbers, then
>>
>> (eqv? x y) => #t
>>
>> if and only if x and y have the same base, sign, number of exponent
>> digits, biased exponents, number of significand digits, and significands.
>
>What about infinities?

What about them? All those quantities are precisely defined for both
infinities and NaNs.

>> Rationale: No matter what bit-level representation is used for IEEE
>> floating-point numbers (and Motorola, Intel, and others use several,
>> beyond the issue of byte ordering), the quantities I specified above
>> are well-defined by IEEE 754 and 854.
>>
>> The current definition of eqv? does not distinguish between -0. and
>> +0. (since they are both equal (in the sense of Scheme =) and
>> inexact. However, operations on +0. and -0. can yield very
>> different results, e.g.,
>>
>> (/ 1. -0) => -inf.
>> (/ 1. +0.) => +inf.
>>
>> Also, since
>>
>> (= x x) => #f
>>
>> if x is a NaN, the current definition would say that any Nan is not
>> eqv to itself, which doesn't make much sense.
>
>I agree. So I am changing SCM so (= NaN NaN) ==> #t.

And I'm divorcing numerical = from other notions of identity/equality in
Scheme.

>> 4. Non-coercion of exact 0:
>>
>> If x is any number, and 0 represents exact zero, then
>>
>> (+ x 0) => x
>> (- x 0) => x
>> (- 0 x) => (- x)
>> (* x 0) => 0
>> (/ 0 x) => 0
>> (/ x 0) => error
>>
>> Rationale: These results follow from a generalization of Priciple 1
>> that goes as follows: If an expression contains inexact numbers, and
>> the result of the expression does not change no matter what exact
>> numbers are substituted for the inexact numbers, then that result
>> should be returned.
>
>I don't find this distinction between exact and inexact compelling.
>What if the substitution of the exact number causes an error?

???

>> There are other reasons for wanting to do this; the biggest
>> practical reason is that it makes operations between reals and
>> complexes, where the real x is coerced to (make-rectangular x 0),
>> *much* easier to get correct.
>
>Complex coercions already work for me. Can you give an example where
>they don't?

(* 1 +inf.+inf.i) => (* (make-rectangular 1 0) +inf.+inf.i)
=> (make-rectangular (- (* 1 +inf.) (* 0 +inf.))
(+ (* 0 +inf.) (* 1 +inf.)))
=> (make-rectangular (- (* 1. +inf.) (* 0. +inf.))
(+ (* 0. +inf.) (* 1. +inf.)))
=> (make-rectangular (- +inf. +nan.)
(+ +nan. +inf.))
=> +nan.+nan.i

My way (* 1 +inf.+inf.i) => +inf.+inf.i.

>> 6. Transcendental functions with special exact arguments
>>
>> I think it's time to require
>>
>> (log 1) => 0
>> (exp 0) => 1
>> (sin 0) => 0
>> (cos 0) => 1
>> (tan 0) => 0
>> (atan 0) => 0
>> (asin 0) => 0
>> etc.
>
>An essential feature of trigonometric functions is that they are
>periodic. When you treat just one value of argument specially, you
>make it non-periodic.

The period of these functions is either Pi or 2Pi. If you goes to the trouble
of having an exact representation of rational multiples of Pi in the your number
system, I'd presume you'd go to the trouble of making the appropriate
trigonometric functions periodic at those multiples.

>What problem does requiring this solve?

Mainly elementary functions of complex arguments; for example, Gambit gives

(- (expt (sqrt -1) (sqrt -1)) (exp (- (* (atan 1) 2)))) => 0.

Note that the imaginary part is exact 0.

>> 7. Complex numbers with imaginary parts +0. or -0. ...
>
>The rest is more signs dancing on zeros. 1/x is no more special a
>function than 1/(x-1) or 1/(x-2). Having infinitesimals only around
>zero just doesn't work. Signs of zeros are unnecessary and should be
>ignored.
>
>If you start with a system which is inconsistent, then you can prove
>anything about it. Without first fixing IEEE-754's inconsistent
>elements, constructs exercising those elements will suffer.

First, I agree that IEEE-754 is, in some ways, inconsistent. I claim it is
also useful.

Second, my introductory paragraph says

>> I would like to make certain proposals for Scheme arithmetic that I
>> believe would bring it more in line with IEEE 754 and 854 arithmetic,

>> *if* this arithmetic is used to implement (some) inexact numbers in


>> a Scheme system. If other inexact number systems are used, then my
>> suggestions would have no force.

You don't want to implement IEEE-754 in Scheme. Fine. I'm not making
suggestions for people who don't want to implement IEEE-754 in Scheme.

Brad


Sander Vesik

unread,
Aug 18, 2003, 5:38:43 PM8/18/03
to
Aubrey Jaffer <a...@alum.mit.edu> wrote:
> sh...@acm.org (Shiro Kawai) writes:
>>
>> As far as I know, all implementations that support NaN
>> return #f for (= nan nan), which I think is IEEE754 compliant.
>> However, some implementations (AFAIK, all but Bigloo)
>> return #t for (eqv? nan nan) in some cases.
>
> Excellent catch! The appended patch fixes SCM so that:
>
>> (= 0/0 0/0)
> #f
>> (eqv? 0/0 0/0)
> #f
>> (let ((nan 0/0)) (= nan nan))
> #t

umm... how so? why should comparing (numericaly) 0/0 with
0/0 be different depedning on whetever it is compared
directly or assigned (whetever via set! or let) to a location?

This looks really broken.

---
Sander

+++ Out of cheese error +++

Sander Vesik

unread,
Aug 18, 2003, 5:53:15 PM8/18/03
to
Aubrey Jaffer <a...@alum.mit.edu> wrote:
>
> The reflexivity of equality is one of the most fundamental
> mathematical principles. Is there any branch of mathematics in which
> an object is not equal to itself? Acquiescence with floating-point
> NaNs not being equal to themselves was responsible for non-conforming
> (with R5RS) behavior in every Scheme implemenation tested.
>

NaN needs to be numericaly (that is in teh sence of =) be unequal to
*any* number, including itself. If this is not so, why bother with
IEEE 754 if you are going to implement something that is like IEEE 754
but not quite it ? You might then just as well deifine division by zero
to return #unspecific.

If you don't bother to actually implement what IEEE 754 specifies then
you *should* *not* call what you implement IEEE754 or imply in any
way that there is a relation, because otherwise people might assume
you actually implement it (which would in no way be even approximating
truth) and teh resulting programs would be failing in various bizzare and
often unpredictable ways.

--

Aubrey Jaffer

unread,
Aug 19, 2003, 11:43:15 PM8/19/03
to

And I know the more stringent EQ? is #t only if the less stringent EQV?
is #t. That is true for Lisp and Scheme.

> I'm suggesting that an object is always eq?/eqv?/equal? to
> itself; it happens to be useful to have a NaN be not = to itself.

How is it useful? No longer does a loop halving an (inexact) variable
terminate when the halved variable is equal to the non-halved variable
-- Unless it checks for NaN explicitly.

> >> Recommendations:


>
> >> 2. Not-a-Numbers:
> >>
> >> I suggest that Scheme adopt standard write forms for IEEE NaNs that
> >> at least indicate the sign of the NaN, e.g., +nan. -nan.
> >
> >Which sign of NaN should (sin (/ 1.0 0.0)) return?
>
> Signs of NaNs could be useful in creating, e.g., signalling versus
> non-signalling NaNs. If you have a system that deals with both types of
> NaNs, and uses the signs of those NaNs to differentiate them, it would be
> nice to have an input notation for this.

Using sign to indicate something unreleated to arithmetic is bad
practice. To distinguish NaNs, how about "NaN" and "NaNq"?

> >> 3. eqv?:
> >>
> >> If x and y are two inexact numbers implemented as IEEE floating
> >> point numbers, then
> >>
> >> (eqv? x y) => #t
> >>
> >> if and only if x and y have the same base, sign, number of exponent
> >> digits, biased exponents, number of significand digits, and significands.
> >
> >What about infinities?
>
> What about them? All those quantities are precisely defined for both
> infinities and NaNs.

In that case, NaN == NaN because all of the fields you mentioned have
the same values.

> >> 4. Non-coercion of exact 0:
> >>
> >> If x is any number, and 0 represents exact zero, then
> >>
> >> (+ x 0) => x
> >> (- x 0) => x
> >> (- 0 x) => (- x)
> >> (* x 0) => 0
> >> (/ 0 x) => 0
> >> (/ x 0) => error
> >>
> >> Rationale: These results follow from a generalization of Priciple 1
> >> that goes as follows: If an expression contains inexact numbers, and
> >> the result of the expression does not change no matter what exact
> >> numbers are substituted for the inexact numbers, then that result
> >> should be returned.
> >
> >I don't find this distinction between exact and inexact compelling.
> >What if the substitution of the exact number causes an error?
>
> ???

(/ 0 x) does not => 0 because (/ 0 0) is an error.

> >> There are other reasons for wanting to do this; the biggest
> >> practical reason is that it makes operations between reals and
> >> complexes, where the real x is coerced to (make-rectangular x 0),
> >> *much* easier to get correct.
> >
> >Complex coercions already work for me. Can you give an example where
> >they don't?
>
> (* 1 +inf.+inf.i) => (* (make-rectangular 1 0) +inf.+inf.i)
> => (make-rectangular (- (* 1 +inf.) (* 0 +inf.))
> (+ (* 0 +inf.) (* 1 +inf.)))
> => (make-rectangular (- (* 1. +inf.) (* 0. +inf.))
> (+ (* 0. +inf.) (* 1. +inf.)))
> => (make-rectangular (- +inf. +nan.)
> (+ +nan. +inf.))
> => +nan.+nan.i
>
> My way (* 1 +inf.+inf.i) => +inf.+inf.i.

SCM gives the same answer *without* making your distinctions between
exact and inexact zeros:

SCM version 5d8, Copyright (C) 1990-2002 Free Software Foundation.
SCM comes with ABSOLUTELY NO WARRANTY; for details type `(terms)'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `(terms)' for details.
> (* 1 1/0+1/0i)
1/0+1/0i

> >> 6. Transcendental functions with special exact arguments
> >>
> >> I think it's time to require
> >>
> >> (log 1) => 0
> >> (exp 0) => 1
> >> (sin 0) => 0
> >> (cos 0) => 1
> >> (tan 0) => 0
> >> (atan 0) => 0
> >> (asin 0) => 0
> >> etc.
> >
> >An essential feature of trigonometric functions is that they are
> >periodic. When you treat just one value of argument specially, you
> >make it non-periodic.
>
> The period of these functions is either Pi or 2Pi. If you goes to the trouble
> of having an exact representation of rational multiples of Pi in the your number
> system, I'd presume you'd go to the trouble of making the appropriate
> trigonometric functions periodic at those multiples.
>
> >What problem does requiring this solve?
>
> Mainly elementary functions of complex arguments; for example, Gambit gives
>
> (- (expt (sqrt -1) (sqrt -1)) (exp (- (* (atan 1) 2)))) => 0.

SCM returns 0.0 for that expression -- so those exact identities
apparently are *not* required.

> (- (expt (sqrt -1) (sqrt -1)) (exp (- (* (atan 1) 2))))

0.0

> Note that the imaginary part is exact 0.

R5RS (http://www.swiss.ai.mit.edu/~jaffer/r5rs_8.html#SEC55)
does not allow mixed exactness:

- 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.

Bradley J Lucier

unread,
Aug 20, 2003, 11:52:24 AM8/20/03
to
In article <vhtwud9...@aarau.ai.mit.edu>,
Aubrey Jaffer <a...@alum.mit.edu> wrote:
...

It's clear we have different backgrounds and viewpoints in this issue. To
be frank, I consider some of your arguments to be nearly ludicrous and I don't
find them to be worth response. So I will back out of this discussion now.

Brad

be...@sonic.net

unread,
Aug 20, 2003, 1:42:40 PM8/20/03
to
As I see it, eq? isn't a mathematical equivalence at all.

eq? is not a mathematical equivalence predicate at all.
eq? is a test to see whether two things refer to the same
memory location. So, I'd expect

(eq? foo foo) => #t

regardless of what value was stored in foo.

eqv? however, is a value-equivalence predicate.
So I'd expect

(eqv? foo foo) => #t

whenever foo was bound to some meaningful and comparable
value. According to IEEE, a NaN is not both meaningful
and comparable. We could allow eqv? to return true because
eq? returns true in this case, guaranteeing that they are
from the same expression - that whatever the indeterminate
value may be, it is definitely the same indeterminate value.
I don't know whether this would be considered a violation
of IEEE.

But if we have

(eqv? (/ 1 0) (/ 1 0)) => #t,

I'd say that's wrong. These NaNs don't come from the same
expression, even though they come from lexically identical
expressions. They are incomparable, and IEEE specifies that
the results of comparison ought to be #f.

Bear

Joe Marshall

unread,
Aug 20, 2003, 2:06:19 PM8/20/03
to
Aubrey Jaffer <a...@alum.mit.edu> writes:

> b...@cs.purdue.edu (Bradley J Lucier) writes:
>
>> I'm suggesting that an object is always eq?/eqv?/equal? to
>> itself; it happens to be useful to have a NaN be not = to itself.
>
> How is it useful? No longer does a loop halving an (inexact) variable
> terminate when the halved variable is equal to the non-halved variable
> -- Unless it checks for NaN explicitly.

I'd have to agree with Bradley Lucier on this. There's a rationale
behind NaN != NaN. It's not what a Schemer would do, but it *is* what
is specified by IEEE 754 arithmetic. Kahan points out:

`NaNs must conform to mathematically consistent rules that were
deduced, not invented arbitrarily, in 1977 during the design of the
Intel 8087 that preceded IEEE 754.'

I suppose providing `IEEE754=' as a primitive that returned #f when
presented with EQ? NaN would be workable.

>> >The reflexivity of equality is one of the most fundamental
>> >mathematical principles. Is there any branch of mathematics in which
>> >an object is not equal to itself? Acquiescence with floating-point
>> >NaNs not being equal to themselves was responsible for non-conforming
>> >(with R5RS) behavior in every Scheme implemenation tested.

This is circular reasoning. You are saying `NaN must = NaN' because
Schemes that implement it that way do that, but Schemes that don't do
not.

> Using sign to indicate something unreleated to arithmetic is bad
> practice. To distinguish NaNs, how about "NaN" and "NaNq"?

I agree with Aubrey Jaffer on this.

>> >> 3. eqv?:
>> >>
>> >> If x and y are two inexact numbers implemented as IEEE floating
>> >> point numbers, then
>> >>
>> >> (eqv? x y) => #t
>> >>
>> >> if and only if x and y have the same base, sign, number of exponent
>> >> digits, biased exponents, number of significand digits, and significands.
>> >
>> >What about infinities?
>>
>> What about them? All those quantities are precisely defined for both
>> infinities and NaNs.
>
> In that case, NaN == NaN because all of the fields you mentioned have
> the same values.

Frankly, I don't understand what EQV? is for.

Originally, EQ? meant `compare these bits with those'. But that
means that fixnums are EQ? when =, but bignums aren't. So we paper
over that with EQV?. But it seems to me that EQ? means two things:

1. SYMBOL-EQ? Is this symbol the same as that.
2. MUTABLE-EQ? If I were to mutate this, would that change.
(although not quite, it works with some immutable
things, too)

>> >> 6. Transcendental functions with special exact arguments
>> >>
>> >> I think it's time to require
>> >>
>> >> (log 1) => 0
>> >> (exp 0) => 1
>> >> (sin 0) => 0
>> >> (cos 0) => 1
>> >> (tan 0) => 0
>> >> (atan 0) => 0
>> >> (asin 0) => 0
>> >> etc.
>> >
>> >An essential feature of trigonometric functions is that they are
>> >periodic. When you treat just one value of argument specially, you
>> >make it non-periodic.

I'd go with Bradley Lucier on this one. These functions are defined
exactly for those inputs. I'd expect them to produce exact results
for *any* result that is representable exactly.

Brad Lucier

unread,
Aug 24, 2003, 11:31:01 PM8/24/03
to
Someone suggested to me privately that it would be useful if we could
work something out here. Aubrey's comments have made me make my
thinking about notation of NaNs more precisely; perhaps some
discussion of the other points would be helpful, too.

Brad

Aubrey Jaffer <a...@alum.mit.edu> wrote in message news:<vhtwud9...@aarau.ai.mit.edu>...


> b...@cs.purdue.edu (Bradley J Lucier) writes:
>
> > In article <m2ptj6r...@aubrey.jaffer>,
> > Aubrey Jaffer <a...@alum.mit.edu> wrote:
> > >b...@cs.purdue.edu (Bradley J Lucier) writes:
> > >
> > >> In article <vhtoeyt...@chur.ai.mit.edu>,
> > >> Aubrey Jaffer <a...@alum.mit.edu> wrote:
> > >> >b...@cs.purdue.edu (Bradley J Lucier) writes:
>
> And I know the more stringent EQ? is #t only if the less stringent EQV?
> is #t. That is true for Lisp and Scheme.

Yes, and my proposal wouldn't change this.

> > I'm suggesting that an object is always eq?/eqv?/equal? to
> > itself; it happens to be useful to have a NaN be not = to itself.
>
> How is it useful? No longer does a loop halving an (inexact) variable
> terminate when the halved variable is equal to the non-halved variable
> -- Unless it checks for NaN explicitly.

It is useful in various ways that I'm not going to list here. They
aren't a secret, go to Kahan's web site if you're interested.

> > >> Recommendations:
>
> > >> 2. Not-a-Numbers:
> > >>
> > >> I suggest that Scheme adopt standard write forms for IEEE NaNs that
> > >> at least indicate the sign of the NaN, e.g., +nan. -nan.
> > >
> > >Which sign of NaN should (sin (/ 1.0 0.0)) return?
> >
> > Signs of NaNs could be useful in creating, e.g., signalling versus
> > non-signalling NaNs. If you have a system that deals with both types of
> > NaNs, and uses the signs of those NaNs to differentiate them, it would be
> > nice to have an input notation for this.
>
> Using sign to indicate something unreleated to arithmetic is bad
> practice. To distinguish NaNs, how about "NaN" and "NaNq"?

OK, my entire concern is that there are many different NaNs (any
floating point number with the maximum exponent and nonzero fractional
part of the mantissa) and it would be good to be able both to print
and to read any bit pattern for a NaN that may be produced as output
or relevant as input by the hardware or the library on any given
system. Perhaps +nan.xxxxxxxx where x is a hex digit and there are 8
(or 16 or however many are necessary) hex digits to specify a NaN.


>
> > >> 3. eqv?:
> > >>
> > >> If x and y are two inexact numbers implemented as IEEE floating
> > >> point numbers, then
> > >>
> > >> (eqv? x y) => #t
> > >>
> > >> if and only if x and y have the same base, sign, number of exponent
> > >> digits, biased exponents, number of significand digits, and significands.
> > >
> > >What about infinities?
> >
> > What about them? All those quantities are precisely defined for both
> > infinities and NaNs.
>
> In that case, NaN == NaN because all of the fields you mentioned have
> the same values.

This is getting nonsensical. My proposal divorces eqv? from =.
Period. And this statement was about eqv?, not =.

> > >> 4. Non-coercion of exact 0:
> > >>
> > >> If x is any number, and 0 represents exact zero, then
> > >>
> > >> (+ x 0) => x
> > >> (- x 0) => x
> > >> (- 0 x) => (- x)
> > >> (* x 0) => 0
> > >> (/ 0 x) => 0
> > >> (/ x 0) => error
> > >>
> > >> Rationale: These results follow from a generalization of Priciple 1
> > >> that goes as follows: If an expression contains inexact numbers, and
> > >> the result of the expression does not change no matter what exact
> > >> numbers are substituted for the inexact numbers, then that result
> > >> should be returned.
> > >
> > >I don't find this distinction between exact and inexact compelling.
> > >What if the substitution of the exact number causes an error?
> >
> > ???
>
> (/ 0 x) does not => 0 because (/ 0 0) is an error.

Yes, that's true. In grade school you learn you can't divide by zero;
in university you learn that in any ring 0 does not have an inverse;
having

(/ 0 x) => 0

unconditionally is not a safe optimization.

And you're being inconsistent---you object to (* 0 x) => 0
unconditionally.

> > >> There are other reasons for wanting to do this; the biggest
> > >> practical reason is that it makes operations between reals and
> > >> complexes, where the real x is coerced to (make-rectangular x 0),
> > >> *much* easier to get correct.
> > >
> > >Complex coercions already work for me. Can you give an example where
> > >they don't?
> >
> > (* 1 +inf.+inf.i) => (* (make-rectangular 1 0) +inf.+inf.i)
> > => (make-rectangular (- (* 1 +inf.) (* 0 +inf.))
> > (+ (* 0 +inf.) (* 1 +inf.)))
> > => (make-rectangular (- (* 1. +inf.) (* 0. +inf.))
> > (+ (* 0. +inf.) (* 1. +inf.)))
> > => (make-rectangular (- +inf. +nan.)
> > (+ +nan. +inf.))
> > => +nan.+nan.i
> >
> > My way (* 1 +inf.+inf.i) => +inf.+inf.i.
>
> SCM gives the same answer *without* making your distinctions between
> exact and inexact zeros:
>
> SCM version 5d8, Copyright (C) 1990-2002 Free Software Foundation.
> SCM comes with ABSOLUTELY NO WARRANTY; for details type `(terms)'.
> This is free software, and you are welcome to redistribute it
> under certain conditions; type `(terms)' for details.
> > (* 1 1/0+1/0i)
> 1/0+1/0i

I said that this property makes it easier to get complex
multiplication correct, not that it was necessary to get it correct;
it is certainly possible to get it correct without having this
property by special casing real * complex, purely imaginary * complex,
etc.

>
> > >> 6. Transcendental functions with special exact arguments
> > >>
> > >> I think it's time to require
> > >>
> > >> (log 1) => 0
> > >> (exp 0) => 1
> > >> (sin 0) => 0
> > >> (cos 0) => 1
> > >> (tan 0) => 0
> > >> (atan 0) => 0
> > >> (asin 0) => 0
> > >> etc.
> > >
> > >An essential feature of trigonometric functions is that they are
> > >periodic. When you treat just one value of argument specially, you
> > >make it non-periodic.
> >
> > The period of these functions is either Pi or 2Pi. If you goes to the trouble
> > of having an exact representation of rational multiples of Pi in the your number
> > system, I'd presume you'd go to the trouble of making the appropriate
> > trigonometric functions periodic at those multiples.
> >
> > >What problem does requiring this solve?
> >
> > Mainly elementary functions of complex arguments; for example, Gambit gives
> >
> > (- (expt (sqrt -1) (sqrt -1)) (exp (- (* (atan 1) 2)))) => 0.
>
> SCM returns 0.0 for that expression -- so those exact identities
> apparently are *not* required.
>
> > (- (expt (sqrt -1) (sqrt -1)) (exp (- (* (atan 1) 2))))
> 0.0

They may not be *required* to solve this problem, but they still solve
the problem, which is the only thing I claimed.

> > Note that the imaginary part is exact 0.
>
> R5RS (http://www.swiss.ai.mit.edu/~jaffer/r5rs_8.html#SEC55)
> does not allow mixed exactness:
>
> - 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.

And your point is? Should I have said that the result is real,
instead of saying that its imaginary part is exact zero?

Brad

Bradley J Lucier

unread,
Aug 25, 2003, 6:21:51 PM8/25/03
to
I've put together a small test program that computes the values of +, -, *, and
/ when the arguments are complex and the real and imaginary parts are all
possible combinations of

(define arguments (list 0
1
-1
plus-zero
minus-zero
1.
-1.
plus-infinity
minus-infinity
not-a-number))

The program and the results for Gambit can be found at

http://www.math.purdue.edu/~lucier/scheme/complex-tests

While some work is needed to port it to other Scheme (I used Gambit's built-in
exception handler) the results should be independent of the Scheme's system
notation for infinities and not-a-numbers.

The algorithms in Gambit use the ideas in my previous proposal, so if you find
that any of these 40,000 results should be different, I'd like to hear about
it. Hopefully you'll be able to compare the results from your favorite Scheme
with Gambit's results.

Brad Lucier

0 new messages