[comp.lang.c] Yet another pcc botch

lvc@cbnews.ATT.COM (Lawrence V. Cipriani) (01/20/89)

This program demonstrates a bug that is in some versions of pcc:

main()
{
	float f, g;
	unsigned short u, v;
	short s, t;

	u = 250;
	s = 250;

	t = 100;
	v = 100;

	f = t - s;
	g = v - u;

	printf("f = %f, g = %f\n", f, g);
}

When compiled and executed the output is:

f = -150.000000, g = 65386.000000

The correct value for g is -150.000000.  This bug is *not* present
in the cc that comes with SVR3 from AT&T.  It is present in SVR2 for
VAX and 3B20.
-- 

Larry Cipriani, AT&T Network Systems, Columbus OH,
Path: att!cbnews!lvc    Domain: lvc@cbnews.ATT.COM

dg@lakart.UUCP (David Goodenough) (01/23/89)

lvc@cbnews.ATT.COM (Lawrence V. Cipriani) sez:
] This program demonstrates a bug that is in some versions of pcc:
] 
] main()
] {
] 	float f, g;
] 	unsigned short u, v;
] 	short s, t;
] 
] 	u = 250;
] 	s = 250;
] 
] 	t = 100;
] 	v = 100;
] 
] 	f = t - s;
] 	g = v - u;
] 
] 	printf("f = %f, g = %f\n", f, g);
] }
] 
] When compiled and executed the output is:
] 
] f = -150.000000, g = 65386.000000
] 
] The correct value for g is -150.000000.

No. The correct value for g is 65386.0 [1]. If you read the gospel
according to Kernighan and Ritchie [2], it says that when you do
mathematics, and at least one of the operands is unsigned, and the
other is NOT float or better (as above), it is done in an unsigned
manner. Now last time _I_ checked, -150 was a negative number, which
simply doesn't exist in the land of unsigned. HOWEVER this type
conversion DOES NOT OCCUR ACROSS ASSIGNMENTS.

[1] depends on your size of short. 65386.0 is correct for those with
16 bit shorts. Check your system, as your actual mileage may vary.

[2] :-)
-- 
	dg@lakart.UUCP - David Goodenough		+---+
						IHS	| +-+-+
	....... !harvard!xait!lakart!dg			+-+-+ |
AKA:	dg%lakart.uucp@xait.xerox.com		  	  +---+

lvc@cbnews.ATT.COM (Lawrence V. Cipriani) (01/25/89)

In article <3310@cbnews.ATT.COM>, I wrote:

+ This program demonstrates a bug that is in some versions of pcc:
+ 
+ main()
+ {
+ 	float f, g;
+ 	unsigned short u, v;
+ 	short s, t;
+ 
+ 	t = 100; s = 250;
+ 	v = 100; u = 250;
+ 	f = t - s; g = v - u;
+ 
+ 	printf("f = %f, g = %f\n", f, g);
+ }
+ 
+ When compiled and executed the output is:
+ 
+ f = -150.000000, g = 65386.000000
+ 
+ The correct value for g is -150.000000.  This bug is *not* present
+ in the cc that comes with SVR3 from AT&T.  It is present in SVR2 for
+ VAX and 3B20.

I consulted with the C compiler gurus in AT&T and they said that the result
as originally stated is correct, and that the value of -150.000000 is wrong.
To force the result to -150.000000 the statement:

	g = v - u;
should be:
	g = (int)v - (int)u;

Though some compilers even get this wrong, e.g., the SVR2 3b20 C compiler.
-- 
Larry Cipriani, att!cbnews!lvc or lvc@cbnews.att.com

chris@mimsy.UUCP (Chris Torek) (01/25/89)

The program fragment:
	float g;
	unsigned short u, v;

	u = 250;
	v = 100;
	g = v - u;

>>... The correct value for g is -150.000000.

In article <398@lakart.UUCP> dg@lakart.UUCP (David Goodenough) writes:
>No. The correct value for g is 65386.0 [for 16 bit short].

Actually, the answer depends on two (or three) things:

If you implement classic C, the answer is some positive number.  The
type of (u_short-u_short) is the type of (expand(u_short)-expand(u_short))
which is (u_int-u_int) which is u_int.  65368 is a typical value.

If you implement pANS C, the answer depends on one thing:  The type of
(u_short-u_short) is either u_int or int.  If sizeof(int)>sizeof(short),
expand(u_short) is int, otherwise it is u_int.  I consider this `feature'
one of the major botches in the pANS (although something like it is
necessary to get unsigned chars to produce int values without casts).

Now, on a 3B, sizeof(int) > sizeof(short), so the answer depends
on whether your compiler implements classic C (65386.0) or pANS C
(-150.0).  But on a PDP-11, sizeof(int)==sizeof(short), so the
answer is 65368.0 in both classic C and pANS C.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

shirono@hcx3.SSD.HARRIS.COM (01/26/89)

In article <3310@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes:
> main()
> {
> 	float f, g;
> 	unsigned short u, v;
> 	short s, t;
> 
> 	u = 250; s = 250; t = 100; v = 100;
> 	f = t - s; g = v - u;
> 
> 	printf("f = %f, g = %f\n", f, g);
> }
> 
> f = -150.000000, g = 65386.000000
> 
> The correct value for g is -150.000000.

Excuse me...

Is the correct value of g REALLY -150.00?  Recall that both v and u are
unsigned short.  (v - u) should therefore be evaluated as unsigned short
and then converted to float, right?

According to K&R, (p. 183),
	Unsigned integers, declared ``unsigned,'' obey the laws of
	arithmetic modulo 2^n where n is the number of bits in the
	representation.

According to K&RII, (p. 36),

	unsigned numbers are always positive or zero, and obey the laws of
	arithmetic modulo 2^n, where n is the number of bits in the type.

So, assuming sizeof(unsigned short) is 2, then arithmetic of unsigned short
is done modulo 2^(16), or 65536.  In this case,

		(100 - 250) mod 65536	=  -150 mod 65536
					= 65386 mod 65536
					= 65386

				g = 65386.0		QED

--Roberto
______________________________________________________________________________
                               ||   Internet: shirono@ssd.harris.com
     Roberto Shironoshita      ||
      Harris Corporation       ||             ...!novavax---\
   Computer Systems Division   ||   UUCP:     ...!uunet-------!hcx1!shirono
                               ||             ...!mit-eddie-/
------------------------------------------------------------------------------
DISCLAIMER: The opinions expressed here are my own; they in no way reflect the
            opinion or policies of Harris Corporation.

diamond@csl.sony.JUNET (Norman Diamond) (01/26/89)

In article <398@lakart.UUCP>, dg@lakart.UUCP (David Goodenough) writes:
>
> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) sez:
> ] f = -150.000000, g = 65386.000000
> ] The correct value for g is -150.000000.
> 
> No. The correct value for g is 65386.0 [1]. If you read the gospel
> according to Kernighan and Ritchie [2],
> 
> [2] :-)

Is this first-edition :-) or second-edition :-) ?

The subtraction operator was applied to a short and an unsigned short,
and the result (either unsigned short or signed int) converted to float.
Under the old unsigned-preserving rules, both f and g should have been
65366.0.  Under the ANSI value-preserving rules, both f and g should be
-150.0.

Mr. Cipriani assumed that System V Releases 2 and 3 should support
modern semantics.  The gurus that he asked, and Mr. Goodenough, perhaps
in the interests of backwards compatibility, feel that they should
support Version 7 semantics.  The System V Release 2 version, in the
interests of pleasing everybody, took the middle road.  Conclusion:
that wasn't a bug, that was a feature.
-- 
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-inventing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?

chris@mimsy.UUCP (Chris Torek) (01/26/89)

In article <15620@mimsy.UUCP> I wrote:
>Now, on a 3B, sizeof(int) > sizeof(short), so the answer depends
>on whether your compiler implements classic C (65386.0) or pANS C
>(-150.0).

Oops: since sizeof(u_int)==4 and the range is 0..4294967295, a `classic
C' compiler should produce 4294967146.0, not 65368.0.  Thanks to Chris
Aoki at Sun for pointing this out, and to Donn Seeley for further noting
that some bits will then `rub off' if this is stored in a 32-bit float
(so that you might get, say, 4294967040.0).  (Donn also noticed a few
typos: 65386 for 65368.)

(In general, conversion from unsigned to float should be done using
machine instructions of the form:
	convert signed to float
	if result < 0, add pow(2.0,32.0)
e.g., on a vax,
		cvtlf	r1,r0
		jgeq	0f
		addf2	$0f4294967296.0,r0
	0:	...
)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

mouse@mcgill-vision.UUCP (der Mouse) (02/01/89)

In article <3310@cbnews.ATT.COM>, lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes:
> This program demonstrates a bug that is in some versions of pcc:

> main() { float f,g; unsigned short u,v; short s,t;
>          u = 250;    s = 250;
>          v = 100;    t = 100;
>          f = t - s;  g = v - u;
>          printf("f = %f, g = %f\n", f, g);       }
[code compressed -dM]

> When compiled and executed the output is:
> f = -150.000000, g = 65386.000000
> The correct value for g is -150.000000.

That depends on the promotion rules in use.  Using the "unsignedness
preserving" rules, the correct value for g is MAXUINT-149.  Using the
"value preserving" rules, it depends again: if short is the same size
as int, the correct result is still MAXUINT-149; if short is smaller
than int, the correct result is -150.  Your result looks like
MAXUINT-149 on a machine with 16-bit ints, of course - or a buggy
compiler.  This may in fact indicate a bug in your compiler, but you
haven't given enough information to convince me of it.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu