chris.umcp-cs@Udel-Relay@sri-unix (09/18/82)
From: Chris Torek <chris.umcp-cs@Udel-Relay>
Date: 14 Sep 82 4:07:30-EDT (Tue)
Whitesmith's C for 8080s has an interesting compromise. If you use
float x, y; x = y + .01;
they convert y to double, add .01 (double), and convert the result to
float and stuff it in x. But if you use
float x, y; x = .01; x += y;
they do the operation in single precision! This works for 'char' too.
Anyway, it seems to me that the rules for arithmetic could be revised
as follows:
1. Before function calls, all chars/floats are widened to ints/doubles.
There is no such thing as a float or char function (though of course
there ARE float *, char *).
2. There are such things as float constants. FP constants are double
until the entire expression is known to be at most float, excluding
any FP constants.
3. Operations are done in the highest precision of all the operands,
INCLUDING THE LVALUE on the left of the asgop.
Examples:
char c1, c2, c3;
int i1;
float f1;
double foo();
c1 = 'x' + 'z'; /* compile time, CHAR */
c2 = c1 + c3; /* done in CHAR */
c3 = c1 + bar('y'); /* done in INT */
i1 = <anything>; /* INT of course */
f1 = 3.14159265358979; /* FLOAT, though constant is DOUBLE */
f1 *= 6; /* FLOAT */
f1 *= (double) .3; /* still FLOAT */
f1 *= foo(); /* DOUBLE */
The reason for #3 above is:
char c1, c2; int i;
i = c1 + c2; /* don't want to add these as
CHAR because result is INT */
If c1+c2 were evaluated as CHAR, '~'+'~' would yeild a negative
result due to sign extension. (It yeilds 252 in existing C.)
Doing something like
int i; char c1, c2;
i = c = c1 + c2; /* i = (int)(char) <foo> done here */
WOULD yeild a negative result.
There is an easy way around all of this, though, which no one
seems to have mentioned: use pointers EVERYWHERE! No longer
do you use "double cos();"; intstead you have
cos0 (op, res) float *op, *res; {return;}
cos1 (op, res) float *op; double *res; {return;}
cos2 (op, res) double *op; float *res; {return;}
cos3 (op, res) double *op, *res; {return;}
(just like FORTRAN!). Yes this is grungy but it will work
in all existing C compilers and it is portable, and not really
all that hard. If you really want efficiency it's probably better
to pass pointers (which are nice handy machine word size) than
big hairy 8 byte floating point numbers. (Of course, you
need to write a whole new math library...)ark (09/19/82)
The trouble with saying that an expression is float unless some wider context needs it as double is that then when you see a + b and a and b are both float, you don't know the true meaning of +. It seems a bad idea in general to make the interpretation of an expression depend on its context.
mark (09/20/82)
Be especially careful of cases like this: char foo(); char a, b; double x, y; x = y * foo(a, b+1); Some of the previous proposals would note that the assignment is done in double, and so would calculate foo(a, b+1) in double. Not only is it wasteful (and inaccurate) to calculate b+1 in double, but since foo is separately compiled and probably expects integer arguments, passing it doubles and expecting a double back simply won't work. You can't just look for the widest part of an expression, you have to consider the pieces of it separately. Another language that has to do this kind of thing, depending on context, is Ada. There was a long controversy as people proposed cubic and quadratic algorithms to figure out the types necessary for expression evaluation. Finally somebody came up with a clever linear algorithm, but the moral is clear: C is supposed to be simple, and this kind of complexity does not belong in the language. If someone would (and could) guarantee to implement float a, b, c; a = b + c; with single precision arithmetic, it would be possible to break down hairier expressions into exactly what the author intends, without lots of complex rules about context. Mark Horton