From: utzoo!decvax!cca!chris.umcp-cs@Udel-Relay@sri-unix Newsgroups: net.unix-wizards Title: Floating Point and Other Such Mysteries Article-I.D.: sri-unix.3338 Posted: Sat Sep 18 00:54:18 1982 Received: Wed Sep 22 10:33:00 1982 From: Chris TorekDate: 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 = ; /* 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) 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...)