jsdy@hadron.UUCP (Joseph S. D. Yao) (11/18/86)
In article <213@cartan.Berkeley.EDU> ballou@brahms (Kenneth R. Ballou) writes: >main () >{ > printf ("%u\n", ~ ((unsigned) 0)); > printf ("%lf\n", (double) (~ ((unsigned) 0))); > printf ("%lf\n", 4294967295.0); /* surely double is large enough for this? */ >} >% bug >4294967295 >-1.000000 >4294967295.000000 This didn't work (actually, worked as expected!) on our ISI 68000- based machine. It worked as above when I compiled and ran it on the VAX. What's happening on the VAX is that it's folding the constant (~((unsigned int) 0)) to the bit pattern $-1, while the 68K is clearing and negating a register: no problem so far! But apparently type is lost or ignored on the VAX, because it then does a cvtld (convert long to double). This is clever-not-clever use of the VAX FP instruction set, which doesn't have an unsigned long data type. The 68K calls a subroutine: jbsr dpufloat which comprehends and translates unsigned longs, as dpfloat does for signed longs. (Doing it in software has occasional advantages over doing it in hardware.) -- Joe Yao hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP} jsdy@hadron.COM (not yet domainised)
rgenter@labs-b.bbn.com (Rick Genter) (11/18/86)
In article <618@hadron.UUCP> jsdy%hadron.uucp@brl.ARPA (Joseph S. D. Yao) writes: > In article <213@cartan.Berkeley.EDU> ballou@brahms (Kenneth R. Ballou) writes: > [ program which shows that (double) ~ ((unsigned) 0) is -1.00, not 2**32-1 ] > > This didn't work (actually, worked as expected!) on our ISI 68000- > based machine. It worked as above when I compiled and ran it on > the VAX. What's happening on the VAX is that it's folding the > [...] This is indeed a bug in the 4.[23] BSD VAX compilers, though it can also be attributed to a (mis)interpretation of how to deal with ~. I don't have K & R or H & S in front of me, but from the April 1985 draft of X3J11: "The result of the ~ operator is the bitwise complement of its operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The operand must have integral type. The integral widening conversion is performed, and the result has the widened type." From this it is clear that the result of ~ing an (unsinged int) [integral type] should be an (unsigned int) [widened type]. > (Doing it in software has occasional advantages > over doing it in hardware.) Allow me to rephrase that: Doing it *right* in software is almost always preferable to doing it *wrong* in hardware. - Rick -------- Rick Genter BBN Laboratories Inc. (617) 497-3848 10 Moulton St. 6/512 rgenter@labs-b.bbn.COM (Internet new) Cambridge, MA 02238 rgenter@bbn-labs-b.ARPA (Internet old) seismo!bbncca!rgenter (UUCP)
woods@hao.UUCP (Greg Woods) (11/20/86)
In article <618@hadron.UUCP>, jsdy@hadron.UUCP (Joseph S. D. Yao) writes: > In article <213@cartan.Berkeley.EDU> ballou@brahms (Kenneth R. Ballou) writes: > >main () > >{ > > printf ("%u\n", ~ ((unsigned) 0)); > > printf ("%lf\n", (double) (~ ((unsigned) 0))); > > printf ("%lf\n", 4294967295.0); /* surely double is large enough for this? */ > >} > >% bug > >4294967295 > >-1.000000 > >4294967295.000000 > > This didn't work (actually, worked as expected!) on our ISI 68000- > based machine. I've seen something similar, and I think your bug probably has to do with the same thing. On a VAX, and every machine I've worked on EXCEPT the ISI-68K, the first 32 bits of a double form a float. Not true on the 68000. Consider the following trivial C program: main() { float f=1.0; test1(f); exit(0); } test1(f) float f; { printf("test1: f=%f\n",f); test2(&f); } test2(f) float *f; { printf("test2: f=%f\n",*f); What one observes is that on the VAX, both printf's print the same value, as they do on a Pyramid 90X, but on the ISI 68020/68881 (both with and without the -f option to enable use of the 68881) they are different. Since I was curious, I ran the same program on a Sun-2 and a Sun-3 that I have access to. Different values there too. The reason is that according to the C standard, when f is passed to test1, it is converted to a double and placed on the stack. When test1 calls test2, it DOESN'T CONVERT the stacked value back to a float before calling test2, so that test2 is passed the address of something that is really a double, not a float as declared in the code. This is a BUG, and it has bitten us badly in many big libraries where we have little stubs designed to allow the calling of FORTRAN routines from C without having to observe FORTRAN calling conventions, e.g.: sub(f) float f; { sub_(&f); } This allows C calls like "sub(2.)" which would otherwise require the creation of a temporary variable like "float temp=2; sub_(&temp)". I maintain this is a BUG, because I specifically declare that what I am passing the address of is a float, when in fact it's a double. --Greg -- {ucbvax!hplabs | decvax!noao | mcvax!seismo | ihnp4!seismo} !hao!woods CSNET: woods@ncar.csnet ARPA: woods%ncar@CSNET-RELAY.ARPA
throopw@dg_rtp.UUCP (11/22/86)
> woods@hao.UUCP (Greg Woods) > I've seen something similar, and I think your bug probably has to do with > the same thing. On a VAX, and every machine I've worked on EXCEPT the ISI-68K, > the first 32 bits of a double form a float. The two problems are very likely unrelated, except in a most tenuous sense. The original bug in the ((double)~(unsigned)1) was a either a problem in implementing the conversion from type unsigned to double, or a problem in deciding what type a twiddle of an unsigned type was. The nature of the error (integer max becomes -1) made it very likely that the original problem was an integer format problem, not a floating point format problem. > This is a BUG, and it has bitten us > badly in many big libraries where we have little stubs designed to allow > the calling of FORTRAN routines from C without having to observe FORTRAN > calling conventions, It is not clear that this is a bug under K&R semantics. I think it likely that ANSI would consider this a bug, since they already mandated that taking the address of a character formal would "work right". In essence, it means that the compiler would be obliged to copy the declared-float-but-really-double formal argument into an invisible float local variable when the address of the formal is taken. -- There was a radical defect somewhere, and I must search it out and cure it. --- Mark Twain -- Wayne Throop <the-known-world>!mcnc!rti-sel!dg_rtp!throopw
mouse@mcgill-vision.UUCP (11/23/86)
In article <295@hao.UUCP>, woods@hao.UUCP (Greg Woods) writes: > On a VAX, and every machine I've worked on EXCEPT the ISI-68K, the > first 32 bits of a double form a float. And it has led to some of the *sloppiest* code, just because some machines will let you get away with it.... > Not true on the 68000. Consider the following trivial C program: > main() { float f=1.0; test1(f); exit(0); } > test1(f) float f; { printf("test1: f=%f\n",f); test2(&f); } > test2(f) float *f; { printf("test2: f=%f\n",*f); > The reason is that according to the C standard, when f is passed to > test1, it is converted to a double and placed on the stack. [...] so > that test2 is passed the address of something that is really a > double, not a float as declared in the code. This is a BUG, [...] Yes - in your code. K&R, page 205: C converts all float actual parameters to double, so formal parameters declared float have their declaration adjusted to read double. That is, the argument to test1 is not a float, it is a double (which has been declared in a misleading manner). Thus test1 is passing a pointer to double, not to float. But test2 is expecting a pointer to float, not to double. Of *course* it's losing! > it DOESN'T CONVERT the stacked value back to a float before calling > test2, so that test2 is passed the address of something that is > really a double, not a float as declared in the code. The code declares f to be a double, albeit in a confusing way. I agree that having C behave this way is a misfeature. I posted something very similar to net.lang.c a while ago, and someone (I forget who) pointed this detail of the C definition out to me then. der Mouse USA: {ihnp4,decvax,akgua,utzoo,etc}!utcsri!mcgill-vision!mouse think!mosart!mcgill-vision!mouse Europe: mcvax!decvax!utcsri!mcgill-vision!mouse ARPAnet: think!mosart!mcgill-vision!mouse@harvard.harvard.edu [USA NSA food: terrorist, cryptography, DES, drugs, CIA, secret, decode]
roger@celtics.UUCP (Roger Klorese) (11/25/86)
In-Reply-To: <562@mcgill-vision.UUCP> Cc: Bcc: In article <562@mcgill-vision.UUCP> you write: >In article <295@hao.UUCP>, woods@hao.UUCP (Greg Woods) writes: >> On a VAX, and every machine I've worked on EXCEPT the ISI-68K, the >> first 32 bits of a double form a float. >And it has led to some of the *sloppiest* code, just because some >machines will let you get away with it.... >> Not true on the 68000. Or on any other IEEE-conforming floating-point implementation. The IEEE formats call for eight bits of exponent on floats, and eleven on doubles. Any piece of code depending on this silly coincidence on the VAX and other very common but non-compliant architectures is askin' fer it. -- =================================== "Speak for the company?! Gee, I have a hard enough time speaking for myself!" ==================== Roger B.A. Klorese | ///==\\ | Celerity Computing (Eastern Region) | /// | 40 Speen St., Framingham, MA 01701 +1 617 872-1552 | \\\ | | \\\==// | celerity!rklorese@sdcsvax.ARPA (sdcsvax!celerity!rklorese) ==================== celtics!roger@seismo.CSS.GOV (seismo!celtics!roger)
guy@sun.uucp (Guy Harris) (12/01/86)
> But apparently type is lost or ignored on the VAX, because it then > does a cvtld (convert long to double). This is clever-not-clever > use of the VAX FP instruction set, which doesn't have an unsigned > long data type. Not on 4.3BSD, it doesn't! It generates a "movd", but the constant it moves is "-1.0", not "4.2949...e9". It's probably due to the following bit of bizarre code in "makety" in "trees.c" - that's part of the machine-independent code, so it will affect other machines: if( p->in.op == ICON && p->tn.rval == NONAME){ if( t==DOUBLE||t==FLOAT ){ p->in.op = FCON; if( ISUNSIGNED(p->in.type) ){ p->fpn.dval = /* (unsigned CONSZ) */ p->tn.lval; } else { p->fpn.dval = p->tn.lval; } p->in.type = p->fn.csiz = t; return( clocal(p) ); } } The commented-out cast is rather peculiar. If you uncomment it, it looks like it should work - and it does, at least where I tried it. > The 68K calls a subroutine: > jbsr dpufloat > which comprehends and translates unsigned longs, as dpfloat does > for signed longs. (Doing it in software has occasional advantages > over doing it in hardware.) *Our* 68Ks don't do this - they do the conversion at compile time, as they should! (Although our compiler currently generates code that does the same wrong thing that the code generated by the VAX compiler does.) It's not a question of whether it's done in hardware or software; it's a question of whether the compiler does the conversion correctly at compile time or not. -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com (or guy@sun.arpa)