Scheme - "inexact" concept in R5RS numerical tower

518 views Asked by At

While thinking about the way to implement Scheme R5RS, I have become puzzled about the following extract of R5RS (pages 22-23):

(remainder -13 -4) ==> -1
(remainder -13 -4.0) ==> -1.0 ; inexact

(lcm 32 -36) ==> 288
(lcm 32.0 -36) ==> 288.0 ; inexact

(denominator (/ 6 4)) ==> 2
(denominator (exact->inexact (/ 6 4))) ==> 2.0

Should we understand that, even if -4.0, 32.0 and (exact->inexact (/ 6 4)) are inexact, the implementation shall "remember" their exact equivalent (-4, 32 and 3/2) in order to proceed to integer division, prime factors decomposition, etc?

Otherwise, how could the implementation succeed in giving the above answers?

Thanks in advance for any light you could throw on this subject! :)

Nicolas

2

There are 2 answers

2
Vijay Mathew On BEST ANSWER

There is no need for the implementation to remember the exact equivalent because as per R5RS it is OK to produce an inexact result given an operation involves an inexact operand. E.g:

> (+ -1.0 2)
=> 1.0

Internally, the interpreter can upgrade 2 to a float and call the addition operation for floats, there is no need to remember anything:

/* Assuming that the interpreter implements primitive operations in C. */
SchemeObject* addInts(SchemeObject* a, SchemeObject* b)
{
    if (a->type == FLOAT || b->type == FLOAT)
    {
        cast_int_value_to_float (a);
        cast_int_value_to_float (b);
        return addFloats (a, b);
    }
    return make_new_int_object (get_int_value (a) + get_int_value (b));
 }

In effect, the above addition in Scheme is treated by the interpreter as:

> (+ -1.0 2.0)
=> 1.0   
0
C. K. Young On

It doesn't have to "remember" the original exactness of the arguments. It can temporarily (internally) convert the numbers to exact during the calculation, and tag the result as inexact if any argument is inexact.

Examples:

(denominator 1/10)  ; 10
(denominator 0.1)   ; 3.602879701896397e+16

(The latter result is implementation-dependent. The number I quoted is from Racket 5.0.2 running on amd64. You'll get different results from other implementations.)

For lurkers and archives: the unusual-looking result is because most implementations use IEEE 754 for inexact numbers, which (being a binary floating-point format) cannot represent 0.1 with full precision (only a decimal floating-point format can).

In fact, if you use (inexact->exact 0.1), you will not get 1/10, unless your implementation uses decimal floating-point.