[comp.lang.c] unsigned int assigned to double yields negative # ... Why?

andrew@nsc.nsc.com (Andrew Lue) (03/18/88)

Using various C compilers on VAX and Series 32000 based machines, I've
compiled the code below.  I've gotten negative results instead of positive
results.

main()
{
unsigned int ui = 0xf0000000;
double d;

d = ui;
printf("%d\n");
}

The books by K&R and Harrison & Steele are unclear about how this conversion
should be applied.  Does anyone know what the definitive conversion is?
Or is the decision left up to the compiler writers?


-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Andrew H. Lue                                          {decwrl|sun}!nsc!andrew

donn@utah-cs.UUCP (Donn Seeley) (03/18/88)

This was a bug of long standing in the PCC.  I fixed it for 4.3 BSD;
vendors who use PCC-based compilers have been fixing it too, although
this coverage has been spotty (I see that HP-UX finally fixes this in
6.0).  For maximum portability you should probably restrict your use of
this conversion, because the workarounds for the bug are ugly and there
are still many buggy compilers.

It's true that neither K&R nor ANSI give special mention to unsigned-
to-floating conversions, but if the compilers weren't broken, I doubt
the issue would have arisen.

Donn Seeley    University of Utah CS Dept    donn@cs.utah.edu
40 46' 6"N 111 50' 34"W    (801) 581-5668    utah-cs!donn

PS -- Yes, I fixed the obvious printf() problems before trying the
example; it'd sure be nice if people could test examples before posting
them (especially in bug reports).

chris@mimsy.UUCP (Chris Torek) (03/18/88)

In article <5020@nsc.nsc.com> andrew@nsc.nsc.com (Andrew Lue) writes:
[a buggy example, but I know what the problem is]

Old versions of Vax PCC convert `unsigned' to `float' or `double' with

	cvtl[fd] src, dst

which is just wrong; the conversion should never produce a negative
float or double.  A surprising number of compilers have had the same
bug.  Donn Seeley has fixed this in recent versions of the 4BSD
compilers.  The 4.3BSD compiler turns

	main(){
		register unsigned u = 0xf0000000;
		register float f = u;
		printf("%u %u\n", u, (unsigned)f);
	}

into

	movl	$-268435456,r11		# u = 0xf0000000;
	movl	r11,r10			# begin f = u:
	jbsc	$31,r10,L99999		# was it negative?
	cvtlf	r10,r10			# it was not negative; convert
	jbr	L99998			# and done
L99999:
	cvtlf	r10,r10			# it was negative but is no longer
	addf2	$0f2.147483648e9,r10	# so convert and add 1<<31.
L99998:
	cvtfl	r10,-(sp)		# convert f to [unsigned] int & push
	pushl	r11			# push u
	pushal	L17			# push the format
	calls	$3,_printf		# printf()
	ret

Incidentally, the compiler distributed with 4.3BSD still goofs on
constants:

	double d = (unsigned)0xffffffff;

sets `d' to -1, rather than 2^32 - 1.  (This is already fixed in
later versions.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

jejones@mcrware.UUCP (James Jones) (03/19/88)

In article <5020@nsc.nsc.com>, andrew@nsc.nsc.com (Andrew Lue) writes:
> Using various C compilers on VAX and Series 32000 based machines...
> I've gotten negative results instead of positive results [from con-
> versions of unsigned to double when the unsigned value has its MSB
> set].

This one has clobbered me, too, under 4.2 on the VAX.  The code generated
was a VAX instruction that is determined to interpret the integer quantity
being converted as signed...so, I wound up compensating with something
like

	unsigned int x;
	double d;

	if ((d = x) < 0)
		d += /* whatever 2**32 is */;

to get what I wanted.  (The compiler on the Sun 3 I use does the moral
equivalent of this, since the fmove on the 68881 treats integers as signed
when converting them to floating-point.)

I would've added here what ANSI Draft says about the matter, but looking
at section 3.2 doesn't seem to indicate what happens.  Certainly getting
a negative result violates the Law of Least Amazement, if nothing else.

		James

sullivan@vsi.UUCP (Michael T Sullivan) (03/19/88)

In article <5020@nsc.nsc.com>, andrew@nsc.nsc.com (Andrew Lue) writes:
> {
> unsigned int ui = 0xf0000000;
> double d;
> 
> d = ui;
> printf("%d\n");
> }
> 
> The books by K&R and Harrison & Steele are unclear about how this conversion
> should be applied.  Does anyone know what the definitive conversion is?
> Or is the decision left up to the compiler writers?

Why leave the decision up to the compiler writers?  Cast ui:

	d = (double)ui;

Don't rely on what you think may happen if the compiler happens to be
what you expect it to be.

good
food
yum
yum
yum

-- 
Michael Sullivan		{uunet|attmail}!vsi!sullivan
				{ucbvax|ihnp4|sun}!amdcad!uport!vsi!sullivan
HE V MTL			sullivan@vsi.com