[clean-list] Handling of reals & boolean expressions?

John van Groningen johnvg@cs.kun.nl
Thu, 19 Dec 2002 15:30:23 +0100


Gé Vissers wrote:

>...
>When calling the function less, less2, less3 with complex numbers with the 
>same absolute value (as in the program above), I get the result
>(True,False,True).

I assume you are using an intel IA32 or compatible processor. On my
Macinstosh I get the result (False,True,False) and on a Windows PC
(False,False,True).

>My two questions are then of course
>a) why is in the functions less and less3 az1 < az2 evaluated to True?

The IA32 processors have a stack of floating point registers that
contain 80 bit floating point values, but floating point values are
stored in memory using 64 bits. The compiler tries to use the registers
in the floating point stack as much as possible, because this is faster.

The function 'less' contains two calls to the function 'absreal'. Both of
these calls will probably yield the same 80 bit floating point value
in a floating point stack register. But after the first call, this value
is put on the stack in memory, so it rounded to a 64 bit floating point
value. After the second call of 'absreal', the 80 bit result of this call
is compared to the previously stored 64 bit value of the first call.
Because of the difference in precision these results are not equal.
So az1==az2 could yield False, and depending on the order of the calls
to 'absreal', either az1<a2 or az1>az2 could yield True.

This does not just happen in Clean, but for example also in C if you use gcc.
For example the following C program:

double f (double d)
{
    return 1.0/d;
}

int main (void)
{
    printf ("%d\n",f (3.0)==f (3.0));

    return 0;
}

yields 0 (False) instead of 1 (True) on Linux using gcc and also on
a pc using Windows 98, gcc and cygwin. But yielded 1 on another pc
running Windows XP using gcc and cygwin. Visual C, Codewarrior and Watcom C
yielded 1 on both pc's.

These differences are not caused by differences in the generated code,
but because the runtime system sets a bit in the control word of the
floating point unit that causes the floating point unit to round the
result to the same precision as used for 64 bit floating point
values after each computation. Unfortunetaly this means that results are
less accurate.

So by enabling this bit we get more predictable results for floating
point comparisons, but less accurate results. It would be possible
to do this in Clean as well, but I don't know if this is better.

Many other processors like the PowerPC and Sparc do not compute
using extra precision in registers (except fmadd).

>b) if the behaviour in less and less3 is correct, then why is the result 
>   of less2 False? 

Maybe the compiler generated the calls to absreal in a different
order, so that az1<az2 yields False instead of True.

Regards,
John van Groningen