That Linux Squeak 2.3 float error again

David T. Lewis lewis at mail.msen.com
Wed Feb 24 01:41:47 UTC 1999


> 
> "Richard L. Peskin" <rlpcon at vermontel.net> wrote:
> > Has anyone verified the float error in Squeak 2.3 Linux, that is the
> error:
> > 0.0 raisedTo: 0.75 ==> NaN     ?
> 
> On linux it seems to be the C library exp() which is at fault.
> 
> 	log(0.0) = -Inf
> 	log(0.0)*0.75 = -Inf
> 	exp(log(0.0)*0.75) = NaN      
>

Some further explanation of the behavior of Float>>exp in Squeak:

The Float>>exp method in Squeak is based on the behavior of exp() in
the C runtime library. The Squeak VM (at least on Unix) assumes that
the underlying C library behaves reasonably for the boundary conditions
of negative infinity and positive infinity. In fact, however,
implementations of the C library vary.

On my Intel Linux system, the exp() function returns NaN when passed
either negative infinity or infinity as an argument. On an Intel BSDI
system (Berkeley derived system), the exp() function returns zero
and Inf respectively, which I presume to be the "correct" results.

As far as I know, all Squeak VMs will rely on the underlying C
library, as they are all built on the C code generated from
the Interpreter class>>translate:doInlining: method. Therefore,
I would expect Mac, Windows, and other systems to have Float>>exp
methods which behave only as well as their underlying C libraries.

Certainly it is possible to add tests for the boundary conditions
in the Squeak VM code, albeit at some cost of complexity and
performance. But first the question would be, what is the "right
thing to do" here? Should Squeak expect the underlying system
libraries to be correct, or should it attempt to compensate for
behavior of the runtime libraries in the interest of consistent
Squeak behavior? My own inclination would be to leave Squeak
well enough alone, but possibly document the dependency on the
underlying libraries in the class documentation.

For reference, here is the output of a test program (derived from
Lex's earlier post) run first on Linux, then on BSDI. Following
the output is a copy of the C test program.

------- Linux output -----------
show behavior of C library exp() function at boundary conditions for
Linux dtlewis 2.0.35 #3 Fri Jan 1 17:22:57 EST 1999 i586 unknown

negative infinity:
log(0.0) = -Inf (ff f0 00 00 00 00 00 00 )

negative infinity again:
log(0.0)*0.75 = -Inf (ff f0 00 00 00 00 00 00 )

exp of negative infinity:
exp(log(0.0)*0.75) = NaN (ff f8 00 00 00 00 00 00 )

positive infinity:
exp(1.0e100)) = Inf (7f f0 00 00 00 00 00 00 )

exp of positive infinity:
exp(exp(1.0e100))) = NaN (ff f8 00 00 00 00 00 00 )
------- BSDI output ------------
show behavior of C library exp() function at boundary conditions for
BSD/OS conch.msen.com 2.1 BSDI BSD/OS 2.1 Kernel #0: Fri Jan 16 18:51:12 EST 1998     wayne at ww2.msen.com:/msen/sys/compile/CONCH.gated  i386

negative infinity:
log(0.0) = -Inf (ff f0 00 00 00 00 00 00 )

negative infinity again:
log(0.0)*0.75 = -Inf (ff f0 00 00 00 00 00 00 )

exp of negative infinity:
exp(log(0.0)*0.75) = 0.000000 (00 00 00 00 00 00 00 00 )

positive infinity:
exp(1.0e100)) = Inf (7f f0 00 00 00 00 00 00 )

exp of positive infinity:
exp(exp(1.0e100))) = Inf (7f f0 00 00 00 00 00 00 )
------- Test program -----------
#include <math.h>
#include <stdio.h>

void 
ddump (unsigned char *d)
{
  int i;
  d += (sizeof (double) - 1);
  printf ("(");
  for (i = 0; i < sizeof (double); i++)
    {
      printf ("%02x ", *d);
      d--;
    }
  printf (")\n");
}

int 
main (void)
{
  union
  {
    unsigned char c[sizeof (double)];
    double d;
  }
  v;

  printf ("show behavior of C library exp() function at boundary conditions for\n");
  fflush (stdout);
  system ("uname -a");

  printf ("\nnegative infinity:\n");
  v.d = log (0.0);
  printf ("log(0.0) = %f ", v.d);
  ddump (v.c);

  printf ("\nnegative infinity again:\n");
  v.d = log (0.0) * 0.75;
  printf ("log(0.0)*0.75 = %f ", v.d);
  ddump (v.c);

  printf ("\nexp of negative infinity:\n");
  v.d = exp (log (0.0) * 0.75);
  printf ("exp(log(0.0)*0.75) = %f ", v.d);
  ddump (v.c);

  printf ("\npositive infinity:\n");
  v.d = exp (1.0e100);
  printf ("exp(1.0e100)) = %f ", v.d);
  ddump (v.c);

  printf ("\nexp of positive infinity:\n");
  v.d = exp (exp (1.0e100));
  printf ("exp(exp(1.0e100))) = %f ", v.d);
  ddump (v.c);

  return 0;
}





More information about the Squeak-dev mailing list