[net.unix-wizards] unsigned -> float conversion

cudcv@daisy.warwick.UUCP (Rob McMahon) (04/03/86)

<munch>

Pointed out to me by someone here - what does your favourite C compiler make
of this program :

main()
{
	unsigned long u;
	double d;
	float f;

	u = ~0;
	d = u;
	f = u;
	printf("u = %lu f = %f d = %lf\n", u, f, d);
	if (d < 0) printf("d < 0\n");
	if (f < 0) printf("f < 0\n");
}

On a VAX-780 running 4.2bsd or a Sun-2 running 2.0 it gives

u = 4294967295 f = -1.000000 d = -1.000000
d < 0
f < 0

On a Gould PN6000 running UTX/32 1.2 it gives


u = 4294967295 f = -1.000000 d = 4294967295.000000
f < 0

-----
UUCP:   ...!mcvax!ukc!warwick!cudcv
JANET:   cudcv%uk.ac.warwk.daisy
PHONE:  +44 204 523037
Rob McMahon, Computer Unit, Warwick University, Coventry CV4 7AL, England
-- 
UUCP:   ...!mcvax!ukc!warwick!cudcv
ARPA:   cudcv%warwk.daisy@ucl-cs.ARPA
PHONE:  +44 204 523037
Rob McMahon, Computer Unit, Warwick University, Coventry CV4 7AL, England

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/04/86)

In article <144@daisy.warwick.UUCP> cudcv@daisy.warwk.ac.uk (Rob McMahon) writes:
>main()
>{
>	unsigned long u;
>	double d;
>	float f;
>
>	u = ~0;
>	d = u;
>	f = u;
>	printf("u = %lu f = %f d = %lf\n", u, f, d);
>	if (d < 0) printf("d < 0\n");
>	if (f < 0) printf("f < 0\n");
>}
>
>On a VAX-780 running 4.2bsd or a Sun-2 running 2.0 it gives
>
>u = 4294967295 f = -1.000000 d = -1.000000
>d < 0
>f < 0
>
>On a Gould PN6000 running UTX/32 1.2 it gives
>
>
>u = 4294967295 f = -1.000000 d = 4294967295.000000
>f < 0

The Gould almost got it right; f should also be a large number,
approximately the same as d.  The SVR2 VAX PCC gets it right.

wendyt@pyramid.UUCP (Wendy Thrash) (04/08/86)

In article <144@daisy.warwick.UUCP> cudcv@daisy.warwk.ac.uk (Rob McMahon) writes
>Pointed out to me by someone here - what does your favourite C compiler make
>of this program :
>[program involving conversion of large unsigned to float/double]

A few months ago I posted a similar (but much larger) program to net.lang.c.
(My address at that time was ...pyramid!isieng!wendyt, for you greppers.)
Several people posted followups, others sent me mail, and I eventually
summarized to the net.  If you're interested in this problem you might want
to check your news archives, but to summarize briefly, Vaxen running System V
tend to do things right; just about everyone else messes up something (including
the compiler I was working on at the time).

This problem arises because hardware usually provides instructions to convert
float/double to/from int, but never seems to provide instructions for unsigned
conversion.  Doing the unsigned conversions correctly is a real pain in the
bazooka for a compiler writer, so s/he tends to take an "Oh well, who'd want
to do this anyway?" approach.  This is, of course, very bad form.

But say, folks, when you see something like this on the net and find it
to produce bizarre results on your hardware, please send a note off to the
manufacturer!  Believe it or not, not all hardware makers read the news;
perhaps some who don't still read their bug reports.

daemon@houligan.UUCP (04/19/86)

	<EAT THIS LINE>

I offer the following bits with the understanding that I do not work for
UTX support and have no access to the source, so please don't bombard me
with bug reports or fixes.

>Try this on your favorite C compiler and see what you get.
>
>main()
>{
>	unsigned u;
>	double d;
>	float f;
>
>	u = ~0;
>	d =  ((float)(u))+1;
>	f =  ((float)(u))+1;
>	printf("u = %lu f = %f d = %lf\n", u, f, d);
>	if (d < 0) printf("d < 0\n");
>	if (f < 0) printf("f < 0\n");
>}
>
>On a VAX-780 running 4.2bsd or a Sun-2 running 2.0 it gives
>
>u = 4294967295 f = -1.000000 d = -1.000000
>d < 0
>f < 0
>
>On a Gould PN6000 running UTX/32 1.2 it gives
>
>
>u = 4294967295 f = -1.000000 d = 4294967295.000000
>f < 0
>

I tried the given example on our PN9080 and got the same results that
the author of the original article got on the 6000.  The float value
comes out -1, and the double value comes out to the large positive
value which is the value of the unsigned.  On the other hand, if you
do this:


main()
{
	unsigned u;
	double d;
	float f;

	u = ~0;
	d =  (float) u;
	f =  (float) u;
	printf("u = %lu f = %f d = %lf\n", u, f, d);
	if (d < 0) printf("d < 0\n");
	if (f < 0) printf("f < 0\n");
}

you get the same results as the VAX.  It could be a problem with the Gould
compiler, which probably works by converting the unsigned to an 8-byte
quantity (there is a machine instruction that will extend the sign of an
integer through 8 bytes), then converting the result to an 8-byte floating-
point variable.  Apparently, in the first example, it fails for some reason
to do the sign extension.

But, now for a larger question: I claim that both the VAX and Gould results
are incorrect.  The Kernighan and Ritchie book doesn't say anything about
converting unsigned quantities directly to float, but I think that if I
wanted to assign an unsigned quantity to a float or double, I would damn
well expect to get a positive number.  It doesn't make sense to me to
take something that is explicitly declared as unsigned and treat it as if it
were signed.  (However, I fear that most machines don't have a convert-
unsigned-to-float instruction, so I may be stuck with this.)

What does everyone out there think?

Dave Cornutt
Gould Computer Systems
Ft. Lauderdale, FL
gould!dcornutt (if it works)

"The opinions expressed herein are not necessarily those of my employer; in
fact, the opinions expressed herein are not necessary."