Path: utzoo!yunexus!geac!syntron!jtsv16!uunet!lll-winken!lll-lcc!ames!mailrus!tut.cis.ohio-state.edu!bloom-beacon!athena.mit.edu!scs From: scs@athena.mit.edu (Steve Summit) Newsgroups: comp.lang.c Subject: Re: Floating point puzzle Message-ID: <6672@bloom-beacon.MIT.EDU> Date: 14 Aug 88 02:15:38 GMT Article-I.D.: bloom-be.6672 References: <3117@emory.uucp> <225800048@uxe.cso.uiuc.edu> Sender: daemon@bloom-beacon.MIT.EDU Reply-To: scs@adam.pika.mit.edu (Steve Summit) Lines: 95 In article <225800048@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes: >I tried running the following program... > >#include> >main() >{ >union { > float fl; > unsigned long lo; >} x,y; > x.fl = 1.0/10.0; > y.fl = 1677721.0/16777216.0; > printf("x: %lx", x.lo); > printf("%20.17f\n",x.fl); > printf("y: %lx", y.lo); > printf("%20.17f\n",y.fl); >} > >/* output is: > >x: 3dcccccd 0.10000000149011610 >y: 3dccccc8 0.09999996423721313 > >/* > >Try running this program, or, if your compiler has 32bit ints, >substitute "int" for "long" and "%x" for %lx". Look, folks, if you're going to write machine-dependent programs, at least do so portably! Use sizeof() so you don't have to know how big floats and doubles are on your machine: main() { printfloat(1.0/10.0); printfloat(1677721.0/16777216.0); } int littlendian = 1; union u { double d; char c[sizeof(double)]; }; printfloat(d) double d; { union u u; int i; u.d = d; printf("%-10.7g = ", d); for(i = 0; i < sizeof(d); i++) { int ii = littlendian ? sizeof(d) - 1 - i : i; printf("%02x", u.c[ii] & 0xff); } printf("\n"); } Oops, it's still a little machine-dependent: for a pleasingly- arranged output, you have to know whether your machine stores things least-significant or mist-significant byte first, which is an issue I'll not diverge to now. You can leave out the &0xff in the next-to-last printf if you make the second member of the union an unsigned char array, if your compiler understands them. (Most newer ones do.) If you don't like unions, you can do it with pointer punning: printfloat(d) double d; { int i; printf("%-10.7g = ", d); for(i = 0; i < sizeof(d); i++) { int ii = littlendian ? sizeof(d) - 1 - i : i; printf("%02x", ((char *)&d)[ii] & 0xff); } printf("\n"); } The output (on a VAX; your actual funny hex numbers may vary) is: 0.1 = cccdcccccccc3ecc 0.09999996 = 00000000ccc83ecc They're quite a bit different, but the reasons why have been explained already. Steve Summit scs@adam.pika.mit.edu