[clean-list] Re: Functions that look the same

Ronny Wichers Schreur ronny@cs.kun.nl
Thu, 19 Jul 2001 14:36:52 +0200


Lloyd Smith writes (to the Clean discussion list):

>I have a question about why these two expressions give different
>results? 
>
>reduce:: (Real -> Real)
>reduce = \x->x/10.0
>
>Start = until ((==)0.0 o \x->x/10.0) reduce 1.0 
>will evaluate to 0
>while 
>Start = until ((==)0.0 o reduce) (reduce) 1.0 
>will evaluate to  0e-324
>
>This was done on win98 using Clean 1.3.3

This is a subtle rounding issue. The x86 floating point registers
are double-extended floats (80 bits), but if you move a floating
point register to memory it gets rounded to an extended float (64
bits).

The Clean compiler tries to generate efficient code by passing
arguments in registers. But in the case of floating point numbers
the compiler's ability to keep values in registers can influence
the result.

See my message to the Haskell mailing list (archived at
<http://www.mail-archive.com/haskell@haskell.org/msg05749.html>)
for a similar and simpler example.

Your program computes the smallest value x for which x/10.0
is 0.0. Through a combination of substitutions and transformations
your two versions are equivalent to

    Start
        =   until predicate reduce 1.0 
        where
            predicate x
                =   (x/10.0) == 0.0
and
    Start
        =   until (predicate ((==) 0.0) reduce) reduce 1.0 
        where
            predicate f g x
                =   f (g x)

In the first program the computation (x/10.0) == 0.0 is done
in 80 bits: the result of x/10.0 is passed in a register to
the floating point comparison. In the second program this is
not the case and the result of x/10.0 will be rounded to
64 bits before it is compared to 0.0.

So be aware of these rounding issues, remember that Clean's
Reals are not really real reals (see also the references in
Siegfried Gonzi's message).

If you need the full control over the precision avoid using
higher-order and polymorhic functions with floats. This may
be contrary to the declarative spirit of functional
programming, but that's the current state of affairs.


Cheers,

Ronny Wichers Schreur