Richard Fateman <fateman at eecs.berkeley.edu> writes:
> The Scheme notion of exact/inexact seems to capture the right
> intuitions.
>
> My first reaction is that this is not a solution
> (a) The history or derivation of a number seems to affect whether
> it is exact or inexact.? I'm not sure this works with input and output
> of numbers.
In Scheme, the exactness of a number is uniquely determined by its
external representation as a string. Therefore if you write a number
and then read it back in, the exactness is preserved.
Specifically, numbers written with a decimal point or exponent marker
are inexact, otherwise they are exact. So 3.0 and 3.5 are inexact,
whereas 3 or 7/2 are exact. 'write' makes sure to use notation that
will be read back in properly.
It's also possible to override the above rules and specify the exactness
explicitly using a "#e" or "#i" prefix, so #e3.5 and #e1e100 are exact
and #i7/2 is inexact, but these notations are rarely used.
> (b) The important criterion of equality has not been mentioned.? Is
> (equal? 3 3.0)? true in Scheme
No. In Scheme, both (equal? 3 3.0) is false but (= 3 3.0) is true.
Similarly, (equal? 7/2 3.5) is false but (= 7/2 3.5) is true.
In Scheme, '=' tests numerical equality, whereas 'eqv?' is based on
operational equivalence. 'equal?' is the same as 'eqv?' for numbers.
In practice, operational equivalence on numbers compares not only the
numerical values, but also other properties such as exactness,
precision, and for IEEE 754 the sign of inexact zeroes.
> Are programmers going to have to worry about transitivity of the
> equality relation, testing whether quantities that are equal are also
> both exact or possibly inexact?
In Scheme, '=', 'eqv?' and 'equal?' are transitive (except possibly when
comparing procedures). When you need an operational equivalence test
(e.g. for implementing memoization), then you use 'eqv?' or 'equal?'.
In most other cases you want '='.
I'm not aware of cases where explicit testing of exactness is required
except in rare cases (e.g. when implementing something like 'write') or
when explicitly checking that an input argument is exact for purposes
for robustness (e.g. for things like 'vector-ref').
> (c) There is a transition allowed from exact to inexact, perhaps at
> overflow or underflow??
> ?that I don't understand.
Common examples of exact->inexact transitions are things like (sqrt 2),
since it is rare for implementations to support exact irrational
numbers. Furthermore, most implementations make no attempt to return
exact results from operations such as 'log', 'sin', etc, even when it is
possible to do so, e.g. (log 1) and (sin 0) usually return 0.0 in
practice.
Standard procedures are also provided to explicitly coerce a number to
be exact or inexact.
> Perhaps (/? 1 0) becomes a floating
> Infinity?? Or what?
Implementations differ on how they handle division by zero, but the most
recent Scheme standard (R6RS) requires that (/ 1 0) raises an exception,
and for (/ 1 0.0) to become a floating point infinity.
> (d) The practical issues of dealing with numbers, like exception
> handling, are not
> mentioned here.? Are they unaddressed in Scheme as they are in CL (and
> Maxima)?
The R6RS standard specifies a fairly comprehensive exception system, but
the earlier standards do not.
Regards,
Mark