[net.lang.c] Float Double Parameters

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.