[comp.lang.c] Mixing doubles and unsigned things

m5@lynx.uucp (Mike McNally) (06/08/89)

What is appropriate behavior in the following instance:

    double d;
    unsigned long u;

    u = BIGNUM;
    d = u;

Assuming that BIGNUM is between the biggest long and the biggest
unsigned long, shouldn't the double be the same value and not a
negative number?  Conversely,  if "d" already contained the
floating-point version of BIGNUM, shouldn't one be able to store the
value into an unsigned long and get the right value?

As an example, try this at home:
    
    main()
    {
        double d;
        unsigned long u;

        d = 3000000000.0 /* That's 3 billion. */
        u = d;
        printf("%lu\n", u);
    }

Under Microport, this generates a floating point exception, by the way.

Why do I ask?  Well, under Microport System V on a 386 machine and
under 4.3BSD on my 68020 machine (Greenhills compiler), it doesn't
work.  The root of the problem is the underlying floating point
processor architecture.  Neither the Intel 387 nor the Moto 68881 know
about unsigned integers.  The 387 does know about 64-bit integers, but
of course support is pretty limited, and the compiler would have to
generate nasty slow code to cope with the problem.  The situation is
much worse on the 881.

From K&RII, A6.3:

    When a value of floating type is converted to integral type,
    the fractional part is discarded; if the resulting value cannot
    be represented in the integral type, the behavior is
    undefined.

OK, but of course BIGNUM *can* be represented in the integral type!
(From section A4.2, second to the last paragraph, we are assured that
unsigned long is an integral type.)

Now, to be honest, I personally don't give two hoots about all this;
one of my customers complained, however, and I wanted to know how bad I
should feel about saying "tough crap".  (I'm not really that mean to
customers.)  Does *anyone* know of a compiler for a 386 or a 68K that
generates correct code?

-- 
Mike McNally                                    Lynx Real-Time Systems
uucp: {voder,athsys}!lynx!m5                    phone: 408 370 2233

            Where equal mind and contest equal, go.

chris@mimsy.UUCP (Chris Torek) (06/08/89)

In article <5709@lynx.UUCP> m5@lynx.uucp (Mike McNally) writes:
>What is appropriate behavior in the following instance:
>
>    double d;
>    unsigned long u;
>
>    u = BIGNUM;
>    d = u;
>
>Assuming that BIGNUM is between the biggest long and the biggest
>unsigned long, shouldn't the double be the same value and not a
>negative number?

Correct.

>Conversely,  if "d" already contained the floating-point version of
>BIGNUM, shouldn't one be able to store the value into an unsigned
>long and get the right value?

Yes.

>Does *anyone* know of a compiler for a 386 or a 68K that
>generates correct code?

The SunOS 3.5 SUNPRO C compiler manages to do the job.  GCC correctly
converts unsigned values to double values, even with -m68881; it relies
on a library routine (___fixunsdfsi) to convert from double to unsigned,
and I have not tested that routine.

The 4.3BSD-tahoe compiler for the VAX gets the unsigned->double
conversion correct, and apparently gets the double->unsigned conversion
wrong.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris