aglew@ccvaxa.UUCP (03/27/86)
Mouse Parker found a bug in Sun C's treatment of float parameters. His entire letter is reproduced below, since it was from another newsgroup. > First and foremost, get rid of the stupid promotion to doubles! I >have considered this a misfeature ever since I heard of it. >Tangentially to this topic, does X3J11 have anything to say on this >matter? X3J11 says "arguments that have type float are promoted to double". Too bad. The bug is real, but you've only been bitten by it because you are following bad programming practice in trying to make a parameter do two jobs. It has already imported a value into the called function, and now you are trying to give it another job to do by reading something into it. A compiler that could do a good liveness analysis (hard to do in C admittedly) should probably be the one to reuse the space, not you. The C practice of reusing parameters as temporaries should only really be permitted when the new values are related to the original value of the parameter, as, for example, in using a char* parameter to walk down a string. Squeak? Here is der Mouse's letter in full. >/**** ccvaxa:fa.sun-spots / mouse@mcgill-vi / 10:06 pm Mar 17, 1986 ****/ >From: mouse@mcgill-vision.UUCP (der Mouse) >Subject: Sun cc bug (Sun UNIX 2.0) > >Problem: > Taking the address of "float" formal function parameters does not > work right. > >Repeat-by: > Try the following program on your favorite Sun: > > main() > { > float r; > > r = 90; > foo(r); > } > > foo(r) > float r; > { > while (scanf("%f",&r) == 1) > { printf("%g\n",r); > } > } > > Compile. Run. Enter (for example) 90 and notice the printed value >is nowhere near 90. Try other values. Generally bad results. > >Analysis/discussion: > > I compiled the above with -S and looked at the assembly code. The >problem seems to be related to the way the C compiler promotes floats to >doubles in function calls. That is, foo() knows that its caller is >really going to pass a double rather than a float, so it behaves as if r >were a double. The trouble is, when we take the address of r, which is >supposedly a float variable, the pointer actually points to a double! >This is hardly the behaviour I expect from applying the "&" operator to >a variable which has been declared "float". > >Immediate fix: > > All I have is a workaround....declare your formal parameters as >doubles rather than floats, then make sure that when you take the >address of one that you realize you are taking the address of a double >and not a float! The above code works if changed as follows: > > foo(r) > double r; > { > while (scanf("%lf",&r) == 1) /* note we use %lf not %f */ > { printf("%g\n",r); > } > } > > I suspect, but have not yet verified, that the same problem exists >on our VAXen as well, where it is masked because you can get away with >treating a pointer to a double as if it were a pointer to a float and >all that will happen is the extra precision will be unchanged (the >exponent fields are the same size). This is not true on the Sun, which >uses a different floating-point format. > >Longterm recommendations for C compiler writers: > > First and foremost, get rid of the stupid promotion to doubles! I >have considered this a misfeature ever since I heard of it. >Tangentially to this topic, does X3J11 have anything to say on this >matter? > > If you can't or won't, then make sure that functions which take >"float" arguments make sure there is a valid "float" somewhere around >(this may mean generating another temporary variable and copying the >argument into it). > > der Mouse
kwh@bentley.UUCP (03/28/86)
In article <2600042@ccvaxa> ccvaxa!aglew writes: >X3J11 says "arguments that have type float are promoted to double". Too bad. I don't know anything about X3J11, but I thought ANSI C would allow the declaration of arguments of extern functions, and would honor "float" if so declared (but would continue to promote float to double for wild-card arguments). >Here is der Mouse's letter... >> foo(r) float r; { ... } My own feeling is that it is WRONG to declare a float argument. Since the language automatically promotes (which I agree is poor design, though I understand the reasons behind it), the variable "r" cannot possibly be a float. The compiler is being "nice" by letting you get away with it (it "knows" that floats can't be passed by value, so it treats it as a double declaration instead). I think it should get a warning at least. Similarly, I never declare a formal parameter as an array (e.g. char *argv[]). It may very well be the name of an array that was passed by the caller, but since it's automatically converted to a pointer, I prefer to declare the formal as a pointer rather than letting the compiler translate the declaration for me. (Also, I could swear I once used a compiler that didn't treat arrays and pointers identically as formal parameters.) Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint
ark@alice.UucP (Andrew Koenig) (03/29/86)
>> First and foremost, get rid of the stupid promotion to doubles! I >>have considered this a misfeature ever since I heard of it. >>Tangentially to this topic, does X3J11 have anything to say on this >>matter? >X3J11 says "arguments that have type float are promoted to double". Too bad. Ansi C also lets you declare types of formal parameters to externals: extern float f(float x); in which case: f(1); /* 1 is converted to float */ f(1.0); /* 1.0 is converted to float */ are both OK.
henry@utzoo.UUCP (Henry Spencer) (03/30/86)
> > Taking the address of "float" formal function parameters does not > > work right. > > ... > > ... The > >problem seems to be related to the way the C compiler promotes floats to > >doubles in function calls. That is, foo() knows that its caller is > >really going to pass a double rather than a float, so it behaves as if r > >were a double. The trouble is, when we take the address of r, which is > >supposedly a float variable, the pointer actually points to a double! > >This is hardly the behaviour I expect from applying the "&" operator to > >a variable which has been declared "float". > > X3J11 says "arguments that have type float are promoted to double". Too bad. > > The bug is real, but you've only been bitten by it because you are following > bad programming practice in trying to make a parameter do two jobs... der Mouse is actually dead wrong here; in pre-X3J11 C there is NO SUCH THING as a "float" formal parameter. If you read the C Reference Manual section 10.1, you will find that when declaring formal parameters, "float" is a synonym for "double". Whether this is bad design is a valid question, but saying that such a formal parameter is "supposedly a float variable" is simply the result of misunderstanding an (admittedly subtle) detail of the language. It is not a float variable, it is a double variable declared in a strange and misleading way. Not a compiler bug. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
meissner@dg_rtp.UUCP (Michael Meissner) (03/31/86)
In article <2600042@ccvaxa> aglew@ccvaxa.UUCP writes: > >Mouse Parker found a bug in Sun C's treatment of float parameters. >His entire letter is reproduced below, since it was from another newsgroup. > >> First and foremost, get rid of the stupid promotion to doubles! I >>have considered this a misfeature ever since I heard of it. >>Tangentially to this topic, does X3J11 have anything to say on this >>matter? > >X3J11 says "arguments that have type float are promoted to double". Too bad. Close, but no cigar. It is true that in the abscence of prototype information, a compiler conforming to X3J11 has to convert float to double on calls (but is allowed to use single precision in expressions). However, if you have a prototype in scope, the compiler is not obligated to convert to double precision. Michael Meissner, Data General
ray@vger.UUCP (Ray Swartz) (03/31/86)
> >X3J11 says "arguments that have type float are promoted to double". > > Karl W. Z. Heuer (ihnp4!bentley!kwh) X3J11 is the name of the committee standardizing the C language -- what you called ANSI C. While it is true that floats are promoted to type double in many cases, there are some where it isn't. For example, the compiler is free to use floats in expressions where such an answer doesn't deviate from the result if doubles were used: junk = 1.0 + 2.0; can be done in float. In addition, with the introduction of function prototypes, a float can be passed to a function. A function prototype declares (which is different than defines -- the function definition is where the code goes) what type the function's arguments are: int foo(float x, int y); now foo will see the first parameter passed as a float. The committee has also authorized a new data type called long double which has twice the precision of double (for all those 64 bit computers out there). There may be other places where float does get promoted... Ray Swartz (ucbvax!ucscc!v!ray) CSnet (ray@ucsc.CSnet) ARPA ray%vger%ucscc%uucp@ucbvax.EDU
greg@utcsri.UUCP (Gregory Smith) (04/01/86)
In article <5216@alice.uUCp> ark@alice.UucP (Andrew Koenig) writes: >>X3J11 says "arguments that have type float are promoted to double". Too bad. > >Ansi C also lets you declare types of formal parameters to externals: > > extern float f(float x); >in which case: > f(1); /* 1 is converted to float */ > f(1.0); /* 1.0 is converted to float */ > >are both OK. OK, but doesn't "extern float f(float x)" really mean "extern float f( double x )"? I.e. '1' and '1.0' are passed as doubles to f in the above examples. I don't know, but I suppose this feature has been added only to allow the compiler to check ( and convert when applicable ) the parameter types. If the above *is* correct, then apparently I can pass a float to a function ( provided it is not defined in the current file (!?!?!?!) ) but it is *not* possible to write a function that accepts a float as a parameter. C is strange, but not that strange - I suspect Mr. Koenig has read something into the standard that is not there. If anyone has reliable information to the contrary, let us know... -- "If you aren't making any mistakes, you aren't doing anything". ---------------------------------------------------------------------- Greg Smith University of Toronto UUCP: ..utzoo!utcsri!greg
mjs@sfsup.UUCP (M.J.Shannon) (04/02/86)
> In article <5216@alice.uUCp> ark@alice.UucP (Andrew Koenig) writes: > >>X3J11 says "arguments that have type float are promoted to double". Too bad. > > > >Ansi C also lets you declare types of formal parameters to externals: > > > > extern float f(float x); > >in which case: > > f(1); /* 1 is converted to float */ > > f(1.0); /* 1.0 is converted to float */ > > > >are both OK. > > OK, but doesn't "extern float f(float x)" really mean > "extern float f( double x )"? No. It really means what it says! > I.e. '1' and '1.0' are passed as doubles to > f in the above examples. I don't know, but I suppose this feature has been > added only to allow the compiler to check ( and convert when applicable ) the > parameter types. Wrong. The actual parameters (1 and 1.0) above are converted to float. > If the above *is* correct, then apparently I can pass a float to a function > ( provided it is not defined in the current file (!?!?!?!) ) but it is *not* > possible to write a function that accepts a float as a parameter. The following function accepts a float as a parameter: void f(float x) { return; } > C is strange, but not that strange - I suspect Mr. Koenig has read something > into the standard that is not there. If anyone has reliable information > to the contrary, let us know... Please read the latest (or any recent) draft from ANSI. Please do not speculate on subjects you don't know anything about. Ask questions, but please don't advance your speculations as facts. > "If you aren't making any mistakes, you aren't doing anything". You are doing *something*. > Greg Smith University of Toronto UUCP: ..utzoo!utcsri!greg -- Marty Shannon UUCP: ihnp4!attunix!mjs Phone: +1 (201) 522 6063 Disclaimer: I speak for no one. "If I never loved, I never would have cried." -- Simon & Garfunkel
guy@sun.uucp (Guy Harris) (04/03/86)
> OK, but doesn't "extern float f(float x)" really mean > "extern float f( double x )"? I.e. '1' and '1.0' are passed as doubles to > f in the above examples. I don't know, but I suppose this feature has been > added only to allow the compiler to check ( and convert when applicable ) > the parameter types. Mr. Koenig is correct. According to the August 11, 1985, X3J11 draft: C3.2.2 Function calls ... Also, *if no function prototype declarator is in scope*, the integral promotions are performed and arguments that have type "float" are promoted to "double". ("italics" mine) ... If a function prototype declarator is in scope, the arguments are compared with the formal parameters. ...The types must be such that each formal parameter may be initialized by the coresponding argument, and the arguments are converted accordingly. Yes, prototypes were added to allow the compiler to check parameter types and convert where applicable. However, this and other changes to the C language in the draft proposed ANSI standard permit the automatic integral and "float" to "double" promotions to be gotten rid of in most circumstances; there was no good reason *not* to eliminate those conversions in the case of functions with full declarations, and good reason to do so. -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.arpa (yes, really)
greg@utcsri.UUCP (Gregory Smith) (04/05/86)
In article <198@sfsup.UUCP> mjs@sfsup.UUCP (M.J.Shannon) writes: >[Me]: >> C is strange, but not that strange - I suspect Mr. Koenig has read something >> into the standard that is not there. If anyone has reliable information >> to the contrary, let us know... > >Please read the latest (or any recent) draft from ANSI. Please do not >speculate on subjects you don't know anything about. Ask questions, but >please don't advance your speculations as facts. > "mphhff mphhrrry" -Apology mumbled through foot in mouth. And thanks for the info. > Marty Shannon >Disclaimer: I speak for no one. You probably spoke for a lot of people. -- "If you aren't making any mistakes, you aren't doing anything". ---------------------------------------------------------------------- Greg Smith University of Toronto UUCP: ..utzoo!utcsri!greg
herndon@umn-cs.UUCP (04/08/86)
[Spare bits.] Oy! Floats & Doubles have certainly caused their share of troubles in both C & Unix. I believe that the original reason for doing all arithmetic in double precision originated with the PDP-11, which had some mis-features in its floating point processor. It seems that on the PDP-11 (/45 certainly, and I believe the /70 and others too) there was no way to write the floating point processor status word. Thus if more than two processes were using the FPP, one of which was generating overflows and the other of which was generating underflows, the two processes would get each other's errors after context switches. I also recall that there was an instruction (SETD) which caused all FPP instructions to be performed in double precision, and that there was no way (i'm not sure here) to query the FPP to see whether it was in double or single precision mode. Since double precision arithmetic was not much slower than single, and floating point wasn't used that much anyway, it was decided that all arithmetic would be done in double precision, and the kernel would assume that all processes ran in double precision mode. During context switches, the kernel would save all FPP registers, reload them for the new process, and leave the FPP in double mode. (Screwing any process which wanted to use single precision arithmetic.) As far as I know (admittedly, not far) there is no longer any good reason for the current schizophrenia about single/double precision arithmetic, other than historical precedent. Does anyone know any other good reasons, such as design faults in the VAX FPA? Robert Herndon ...!ihnp4!umn-cs!herndon herndon@umn-cs herndon.umn-cs@csnet-relay.ARPA Dept. of Computer Science, Univ. of Minnesota, 136 Lind Hall, 207 Church St. SE Minneapolis, MN 55455
kenny@uiucdcsb.CS.UIUC.EDU (04/11/86)
/* Written 10:34 pm Apr 7, 1986 by herndon@umn-cs in uiucdcsb:net.lang.c */ As far as I know (admittedly, not far) there is no longer any good reason for the current schizophrenia about single/double precision arithmetic, other than historical precedent. Does anyone know any other good reasons, such as design faults in the VAX FPA? Robert Herndon /* End of text from uiucdcsb:net.lang.c */ No, but you have (possibly) the wrong historical precedent. On the GE 635 (and its successors), *all* floating-point arithmetic was double-precision internally. Single-precision *instructions* existed, but all they did was to pad or truncate the operand appropriately. The GE Fortran library's mathematical functions all, therefore, accepted only double-precision operands (SIN and DSIN were the same function). When BCPL was built for the 635, it borrowed the existing Fortran library and hence had to adopt the convention that all float's are promoted to double's for parameter passing. 'B' (Anyone else remember 'B'? It was a neat language [compared to what was available before 'C']) and later 'C' inherited this kludge from BCPL. Kevin Kenny University of Illinois at Urbana-Champaign UUCP: {ihnp4,pur-ee,convex}!uiucdcs!kenny CSNET: kenny@UIUC.CSNET ARPA: kenny@B.CS.UIUC.EDU (kenny@UIUC.ARPA) "Yes, understanding today's complex world is a bit like having bees live in your head, but there they are."
gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/13/86)
Herndon correctly attributes C's "double-precision only" design to PDP-11 FP11 characteristics (although I think it was also felt that single-precision had too few bits to be very useful anyway), but he is mistaken in many of the details. The kernel could both read and write the status register; 6th Edition UNIX as distributed did not properly handle asynchronous FP11s, although it did make an attempt to save and restore FP11 state during user process context switching. (Note that the FP11 needed to be put into double mode during register save/restore.) One of the things I did to the kernel at Geotronics was to fix FP11 handling and install it in the non-I&D version; it wasn't very difficult. Allowing both single- and double-precision operation would certainly complicate the code generator, since the FP11 used a "mode" setting rather than separate instructions. Thus, a SETD at the beginning of the code would suffice to lock in double-precision operation; it also would cause a trap on a non-FP11 machine, so there were special arrangements to ignore the trap. The current conception is to permit either the double-only implementation of C or allow support for single-precision in expressions at the implementor's discretion.
brooks@lll-crg.ARpA (Eugene D. Brooks III) (04/14/86)
> As far as I know (admittedly, not far) there is no longer any >good reason for the current schizophrenia about single/double >precision arithmetic, other than historical precedent. Does >anyone know any other good reasons, such as design faults in >the VAX FPA? The reason for keeping the conversion in is purely historical. Its called those old dusty decks (sorry, files). The way that the proposed ANSI standard deals with the problem, introduce function prototypes, seems like a reasonable way to provide efficiency for those who need it while at the same time not breaking old code.
rfm@frog.UUCP (Bob Mabee, Software) (04/22/86)
In article <139200025@uiucdcsb> kenny@uiucdcsb.CS.UIUC.EDU writes: > When BCPL was built for the >635, it borrowed the existing Fortran library and hence had to adopt the >convention that all float's are promoted to double's for parameter passing. When DMR put an obsolete version of BCPL on the GE 645, it had no support for floating-point operations. We added floating-point operators and constants during the port from CTSS to the 360. Later I wrote a new code generator for the GE 645 (the first BCPL to generate binary directly), and added the floating-point operators here too, and transcendentals written in BCPL. Other functions would have come from the PL/I Multics environment, which did support single precision. In any case, BCPL is typeless and would not have known to convert number formats on function calls.