[comp.lang.c] Conversion of unsigned long to double

tvdl@bsiao.UUCP (Timo van der Laan) (04/21/89)

The C-compiler for IX370 (running on a 9370 machine) treats an
unsigned long as a signed long if that unsigned long is assigned to
a double. (See the program below).

Is this behavior permitted in ANSI?

**** program ****
main(){
	unsigned long	l;
	double	d;

	l=2100000000L;
	d=l;
	printf("%11u %13.0f\n",l,d);
	l=2200000000L;
	d=l;
	printf("%11u %13.0f\n",l,d);
}

**** Output on IBM 9370 (IX370)**** | **** Output on a Vax (4.3 bsd) ****
 2100000000    2100000000           | 2100000000    2100000000
 2200000000   -2094967296           | 2200000000    2200000000

I found this just before a large program went into production.
If it's a bug, I'll bet that IBM will change the manual instead of
repairing the compiler. (Just as they did after I told them that
rm -rf ../dir did not remove the directory because of the ../ )

--
 Timo van der Laan, Postbank N.V., room 4.94        ...mcvax!hp4nl!bsiao!tvdl
 Pb 21009
 1000 EX  AMSTERDAM                                   Phone: + 31 20 5843175
                 "Real programmers don't wear ties"

chris@mimsy.UUCP (Chris Torek) (04/22/89)

In article <515@bsiao.UUCP> tvdl@bsiao.UUCP (Timo van der Laan) writes:
>The C-compiler for IX370 (running on a 9370 machine) treats an
>unsigned long as a signed long if that unsigned long is assigned to
>a double. (See the program below).

>Is this behavior permitted in ANSI?

No; but this mistake is easy to make when building a compiler.  4.2BSD
had the same bug.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

njk@freja.diku.dk (Niels J|rgen Kruse) (04/23/89)

tvdl@bsiao.UUCP (Timo van der Laan) writes:

>The C-compiler for IX370 (running on a 9370 machine) treats an
>unsigned long as a signed long if that unsigned long is assigned to
>a double. (See the program below).

>Is this behavior permitted in ANSI?

It has always been a bug, just a very common one.

The only reliable way to convert an unsigned long to double, if
you want your code to be compiled correctly by pcc derived
compilers, is to write something like
#define ul_to_dbl(ul) \
  ((ul)&(unsigned long)-1/2+1 \
   ? (long)((ul)&(unsigned long)-1/2) \
     + 2.0 * (long)((unsigned long)-1/4+1) \
   : (long)(ul))
(...)
  double d; unsigned long ul;
(...)
  d = ul_to_dbl(ul);

>**** program ****
(deleted)
>**** Output on IBM 9370 (IX370)**** | **** Output on a Vax (4.3 bsd) ****
(showing correct conversion on Bsd 4.3 Vax and incorrect on IBM 9370)

Lest you should harbour any delusions that the Bsd 4.3 cc
handles unsigned arithmetic and conversions correctly in
general, try running this little program :
------------- demo program -----------
#include <stdio.h>
main()
{
  static unsigned ut[5] = {0,0,-1,0,0};
  double dblt[5];
  int i = 0;

  printf ("First test : ");
  if ((unsigned)-1 < 1) printf ("*splat*\n");
  else printf ("correct.\n");

  printf ("Second test : the same value assigned to dblt[0] and dblt[1]\n");
  dblt[i] = ut[2];
  dblt[++i] = ut[2];
  printf ("  dblt[0] = %12.10lg, dblt[1] = %12.10lg\n",dblt[0],dblt[1]);

  printf ("Third test : assigning ut[i] to dblt[i]\n");
  for (i = 0; i < 5; i++)
    dblt[i] = ut[i];
  for (i = 0; i < 5; i++)
    printf ("    ut[%d] = %12u, dblt[%d] = %12.10lg\n",i,ut[i],i,dblt[i]);
}
------------- end program ------------

----------- Bsd 4.3 Vax output -------
First test : *splat*
Second test : the same value assigned to dblt[0] and dblt[1]
  dblt[0] =   4294967295, dblt[1] =   2147483519
Third test : assigning ut[i] to dblt[i]
    ut[0] =            0, dblt[0] =            0
    ut[1] =            0, dblt[1] = -1.701411733e+38
    ut[2] =   4294967295, dblt[2] =            0
    ut[3] =            0, dblt[3] =            0
    ut[4] =            0, dblt[4] =            0
--------------- end output -----------

Needless to say, behaviour like this can leed to ... um,
captivating debugging sessions.

>--
> Timo van der Laan, Postbank N.V., room 4.94        ...mcvax!hp4nl!bsiao!tvdl
> Pb 21009
> 1000 EX  AMSTERDAM                                   Phone: + 31 20 5843175
>                 "Real programmers don't wear ties"
-- 
Name         : Niels J|rgen Kruse
Organization : DIKU, University of Copenhagen, Computer Science dept.
Email        : njk@diku.dk
Mail         : Tustrupvej 7, 2 tv, 2720 Vanlose, Denmark

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

In article <4612@freja.diku.dk> njk@freja.diku.dk (Niels J|rgen Kruse) writes:
>Lest you should harbour any delusions that the Bsd 4.3 cc
>handles unsigned arithmetic and conversions correctly in
>general, try running this little program :

>  if ((unsigned)-1 < 1) printf ("*splat*\n");
>  else printf ("correct.\n");

Fixed in 4.3-tahoe.  (Donn uncommented a cast within PCC itself that
had been disabled.)

>  printf ("Second test : the same value assigned to dblt[0] and dblt[1]\n");
>  dblt[i] = ut[2];
>  dblt[++i] = ut[2];

Oops!  The compiler is using the subscript addressing modes (-40(fp)[r1])
for both the jbsc (to test and clear the sign bit) and the addd2 (to add
2^31); but the latter multiplies r1 by 8, not 4, so it adds to the wrong
variable.

Might be fixed in 4.4 :-) ,
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris