[comp.lang.c] BUG - unsigned long cast to double

mcdonald@uxe.cso.uiuc.edu (08/13/88)

>	printf ("y: %d -> %lf   z: %u -> %lf\n", y, (double) y, z, (double) z);

>	y++; z++;
>	printf ("y: %d -> %lf   z: %u -> %lf\n", y, (double) y, z, (double) z);

I tries this on my IBM-PC with microsoft C 5.1 and of course got 
garbage. The reason is obvious: %d SHOULD be %ld and %u should be %lu.
With these changes, the output, all 4 numbers, are exactly what one
would expect for a two's complement integer machine. The problem
with the original is that printf picks up the wrong bytes to output,
due to the size of the integer arguments not agreeing with the
format specifications. Try a corrected program and see what happens.

Doug McDonald

chris@mimsy.UUCP (Chris Torek) (08/13/88)

In article <1239500001@osiris.cso.uiuc.edu> olson@osiris.cso.uiuc.edu writes:
>... found this problem on Pyramid and Masscomp machines, and not on Sun
>machines.

The same bug *does* exist in 4.1BSD, and *not* in 4.3BSD (and I am not
sure about 4.2BSD).

>... casting unsigned long to double ... treat the cast as SIGNED long
>to double.

Actually, any conversion of u_long to double, regardless of context.

>	printf ("y: %d -> %lf   z: %u -> %lf\n", y, (double) y, z, (double) z);

%lf makes no sense here.  In K&R C, %f prints a double, since there are
no float rvalues.  In dpANS C, %lf prints a long double.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

olson@osiris.cso.uiuc.edu (08/15/88)

I muddied the waters using printf ... different machines accept different
things...  However, we examined the assembly language as compiled,
and SUN and PYRAMID compilers assemble differently.  The bug is real.
I expect the response about which BSD version one has is the key.
Our Pyramid has 4.2BSD... and the bug exists there.

I received mail from a CONVEX user whose machine compiled incorrectly.

matt@ncr-sd.SanDiego.NCR.COM (Matt Costello) (08/31/88)

In article <1239500001@osiris.cso.uiuc.edu> olson@osiris.cso.uiuc.edu writes:
>The problem involves casting unsigned long to double.  The Pyramid and
>Masscomp compilers treat the cast as SIGNED long to double.  If the
>value is large enough, you have troubles.

The problem has existed in PCC since the beginning, as the PDP-11
did not readily support 32 bit integers.  The few double-word instructions,
including the floating point conversions, only supported signed values.
Neither the VAX nor the M68881 support conversions to or from unsigned
values either.

The code sequences to handle the unsigned long to double conversion
(and vice versa) would have imposed an unacceptable performace penalty,
so it wasn't done.  I don't have my K&R here, but I don't even believe
that unsigned longs were legal back then.
-- 
Matt Costello	<matt.costello@SanDiego.NCR.COM>
+1 619 485 2926	<matt.costello%SanDiego.NCR.COM@Relay.CS.NET>
		{ucsd,att,pyramid,nosc.mil}!ncr-sd!matt

chris@mimsy.UUCP (Chris Torek) (08/31/88)

>In article <1239500001@osiris.cso.uiuc.edu> olson@osiris.cso.uiuc.edu writes:
[various compilers convert as if from signed long to double]

In article <2590@ncr-sd.SanDiego.NCR.COM> matt@ncr-sd.SanDiego.NCR.COM
(Matt Costello) writes:
>The problem has existed in PCC since the beginning,

Probably true (I have not been around long enough to really know; I
believe PCC appeared in phototypesetter V6, which I have never used.)

>as the PDP-11 did not readily support 32 bit integers.

Not a good excuse.  I imagine it was simply never tested.

>Neither the VAX nor the M68881 support conversions to or from unsigned
>values either.

Conversion on a VAX is easy:

	cvtl[fd] src,dst
	bgeq 0f; add[fd]2 $0[fd]4294967296.0,r2; 0:

On a 68000 it would be something longer, but also involve testing
the sign before or during conversion.

>The code sequences to handle the unsigned long to double conversion
>(and vice versa) would have imposed an unacceptable performace penalty,
>so it wasn't done.

Better slow than wrong.  I think it was just an oversight.  One could
make the claim that unsigned division and modulus on a VAX impose an
unacceptable performance penalty (it takes far more than the four
instructions above), yet they were done.

>I don't have my K&R here, but I don't even believe
>that unsigned longs were legal back then.

I believe the One True C Compiler (dmr's '11 compiler) :-) did not have
unsigned <char, short, long> variants.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

henry@utzoo.uucp (Henry Spencer) (09/08/88)

In article <13315@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>I believe the One True C Compiler (dmr's '11 compiler) :-) did not have
>unsigned <char, short, long> variants.

Well, originally of course it didn't have "unsigned" at all!

Unsigned long never did exist in the DMR compiler.  Unsigned short sort of
existed -- "short" essentially turned into "int" very early, as a quick
way of hacking "short" in.  Unsigned char wasn't present for a long time,
but the System V version did have it -- I don't know whether that was
Dennis's work or somebody else's.
-- 
Intel CPUs are not defective,  |     Henry Spencer at U of Toronto Zoology
they just act that way.        | uunet!attcan!utzoo!henry henry@zoo.toronto.edu