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