[comp.lang.c] Compiler bug or gray area in C?

daveb@ingres.com (When a problem comes along . . . you must whip it) (11/29/90)

Given this simplification:
	
	extern	double D, foo();
	
	foo( i )
	int i;
	{
		double	x;
		int	changes = 0;
		do {
	
			x = foo( i );
	
			if( x < D )
			{
				changed++;
				D = x;
			}
	
		} while( !changed );	
	}

is it reasonable for this to not terminate?

We see a number of compilers that keep x in a register with extended
precision, so that it has bits that are not in the global D.  Thus, the
comparison (x < D) fails, even after D is assigned the value of x.  

Yes, floating point in C is peculiar, but is it _this_ peculiar?

thanks,
-dB
--
"If it were easy to understand, we wouldn't call it 'code'"
David Brower: {amdahl, cpsc6a, mtxinu, sun}!rtech!daveb daveb@ingres.com

jeff@ingres.com (Jeff Anton) (11/29/90)

Dave ment to write:
	extern	double D, foo();
	
	bar( i )
	int i;
	{
		double	x;
		int	changes = 0;
		do {
	
			x = foo( i );
	
			if( x < D )
			{
				changed++;
				D = x;
			}
	
		} while( !changed );	
	}

The obvious compilation and recursion problems are clear
with the original code.  The issue is the legality
of compilers extending the precision of variable when
they are placed in registers.
				Jeff Anton

chris@mimsy.umd.edu (Chris Torek) (11/29/90)

In article <1990Nov28.220233.2630@ingres.Ingres.COM> daveb@ingres.com writes:
>Given this simplification:
>	
>	extern	double D, foo();
>
>	foo( i )
>	int i;
>	{

Type error, foo returns double and int.  Because of the next problem, I
am almost sure you meant `bar(i)':

>		double	x;
>		int	changes = 0;
>		do {
>	
>			x = foo( i );

Infinite recursion: to compute foo(i) we must first compute foo(i) before
doing anything else.

>			if( x < D )
>			{
>				changed++;
>				D = x;
>			}
>	
>		} while( !changed );	
>	}

Repaired example:

	fn() {
		double x, eval(void);
		extern double D;
		extern void nop(void);

		for (D = x = eval();;) {
			nop();	/* does not change D */
			if (x < D)
				D = x;
			else
				break;
		}
	}

>is it reasonable for this to not terminate?

I think so; I think that the reason you give here is not (quite) outlawed.

>We see a number of compilers that keep x in a register with extended
>precision, so that it has bits that are not in the global D.  Thus, the
>comparison (x < D) fails, even after D is assigned the value of x.  
>
>Yes, floating point in C is peculiar, but is it _this_ peculiar?

(Floating point in C is no more peculiar than floating point anywhere
else.  Or, more succinctly, floating point is peculiar everwhere.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

jap@convex.cl.msu.edu (Joe Porkka) (11/29/90)

daveb@ingres.com (When a problem comes along . . . you must whip it) writes:

>Given this simplification:
>	
>	extern	double D, foo();
>	
>	foo( i )
>	int i;
>	{
>		double	x;
>		int	changes = 0;
>		do {
>	
>			x = foo( i );

Ooops, the recursion starts but but does not stop.
You recurse BEFORE you do anything that could stop it, like an if.

gwyn@smoke.brl.mil (Doug Gwyn) (11/30/90)

In article <1990Nov28.220233.2630@ingres.Ingres.COM> daveb@hydra.Ingres.COM (When a problem comes along . . . you must whip it) writes:
>is it reasonable for this to not terminate?

The example you posted merely recurses "forever".  I couldn't
figure out a rewrite that would trigger the phenomenon you seemed
to want to discuss.

gwyn@smoke.brl.mil (Doug Gwyn) (11/30/90)

In article <1990Nov29.021553.12522@ingres.Ingres.COM> jeff@ingres.com (Jeff Anton) writes:
>The issue is the legality of compilers extending the precision of
>variable when they are placed in registers.

In many environments there is no choice; floating registers simply ARE
wider than floating storage.

The issue of exactly when an implementation is obliged to "scrape off"
the extra precision is still open in X3J11, if I recall correctly.  One
might think that any cast or assignment should do this, but there are
arguments why that isn't always desirable.  At this point there is a C
standard and it is "just" a matter of interpreting what requirements, if
any, it imposes in this area.  There should be an official interpretation
ruling on this sometime..

stanley@phoenix.com (John Stanley) (11/30/90)

daveb@ingres.com (When a problem comes along . . . you must whip it) writes:

> Given this simplification:
> 	
> 	extern	double D, foo();
> 	
> 	foo( i )
> 	int i;
> 	{
> 		double	x;
> 		int	changes = 0;
> 		do {
> 	
> 			x = foo( i );
> 	
> 			if( x < D )
> 			{
> 				changed++;
> 				D = x;
> 			}
> 	
> 		} while( !changed );	
> 	}
> 
> is it reasonable for this to not terminate?
> 
   Hmm. First thing foo does is invoke foo again. I would say this will
not terminate until the stack overflows. Is that reasonable?

   If this problem were introduced by the simplification, then there is
still the problem that foo never returns a value. Whatever happens to
show up in x will be whatever was left in the registers. Is that going to
be less than D? Who knows?

> We see a number of compilers that keep x in a register with extended
> precision, so that it has bits that are not in the global D.  Thus, the
> comparison (x < D) fails, even after D is assigned the value of x.  
> 
   Ah. Floating comparisons. This is a problem that was well known (at
least to me) in the Sun workstations (for one example). The 68881 FPU has
an 80 bit register.  This will rarely equal anything that has passed
through the 64 bit double. Sun had a flag on the compiler to force
floating ops to use only 64 bits from the FPU. I don't remember what it
is.

> Yes, floating point in C is peculiar, but is it _this_ peculiar?

   This is not C, it is hardware. Yes, that peculiar.


<> "If winning is not important, then why keep score?" -- Turtle Head
<> "Eaten any good books lately?" -- Q
<> "Sanity check!" "Sorry, we can't accept it, it's from out of state." - me