Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!ut-sally!husc6!mit-eddie!uw-beaver!tektronix!reed!psu-cs!omepd!jimv From: jimv@omepd (Jim Valerio) Newsgroups: comp.lang.c Subject: Re: Optimizing Floating-Point Expression Evaluation Message-ID: <638@omepd> Date: Tue, 5-May-87 05:40:33 EDT Article-I.D.: omepd.638 Posted: Tue May 5 05:40:33 1987 Date-Received: Thu, 7-May-87 05:59:38 EDT References: <16646@sun.uucp> <4616@utcsri.UUCP> <589@omepd> <15296@onfcanim.UUCP> Reply-To: jimv@omepd.UUCP (Jim Valerio) Organization: Intel Corp., Hillsboro Lines: 88 Summary: macros are reasonable to use, but don't ignore order of evaluation In article <15296@onfcanim.UUCP> dave@onfcanim.UUCP (Dave Martindale) writes in defense of the use of macros in floating-point calculations, and gives an example of where the order of evaluation is potentially harmless. I believe that 3 different questions are at issue in the discussion here: (1) Are there valid reasons to do floating-point calculations in the context of a macro? (2) Are there situations where the order of evaluation of floating-point sub-expressions radically affects the computed result? (3) Should macros behave like functions rather than simple textual substitutions? I don't believe there's any argument about (1) and (2): the answer to both is clearly yes. In both cases one can construct special situations where the yes answers are not necessary. I believe that my attack on the `THING' macro (see <589@omepd>) fits in this latter category. In the same special sense, I question Dave's assertion that in the following code, #define SETUP 7.5 #define MV(ire) ((ire)*1000.0/140.0) y = MV(y*(100.0-SETUP) + SETUP); he "just want[s] the approximate answer". In particular, Dave says: >Any expression rearrangement or constant folding that speeds execution >is fine with me; I don't care about order of evaluation because the >roundoff errors will be smaller than I care about no matter what. >In fact, there are many calculations done in computer graphics where >only the first 12 or 16 bits of the mantissa are significant, and >roundoff need not be worried about. Now, I don't know how the result `y' is used here, or exactly what domain the source `y' is in, but it is trivial to construct an example where at NO bits of significance are left in the *mantissa*, all because of the few rounding errors in this expression. [In single precision IEEE floating-point, look at y = -0.0810810849, where the parenthesized expression yields -3.40597967e-06 and the constant folded expression (y * ((100.0 - 7.5)*1000.0/140.0)) + (7.5*1000.0/140.0) yields 0.] Of course, the absolute error here might (or might not) be perfectly acceptable, but to find out requires looking at every place the data is used. Folks, let me remind you: it is NOT TRUE that rounding errors can overwhelm a computation only if vast number of them accumulate. It is also NOT TRUE that a few rounding errors can overwhelm a computation only if accompanied by massive cancellation. And now back to: (3) Should macros behave like functions rather than simple textual substitutions? In some sense, it is pointless to debate this question since the language and common practice provide the simple answer that macros are simple textual substitutions. Should's will not change what is. Dave says: >Yes, the macro is written like a function call because >I want to *think* about it as a function call. But I don't want nor >expect it to be *evaluated* as if it were a function call, since no >macro is in fact evaluated like a function call. I guess I wish that the C preprocessor was more tightly integrated into the language so arguments to macros would have an implied precedence. Then I wouldn't need to introduce the extra parentheses that I wouldn't write if I were writing out the expression longhand. For example, if the macro substitution were done after the expression tree for an expression involving a macro was constructed, then #define islower(ch) ch >= 'a' && ch <= 'z' would work for islower(c) /* normally wouldn't put ()'s here */ and islower(c & 0x7f) /* islower def *wants* ()'s now */ (Please note that constant folding would then be done after the all the macro substitutions had been performed.) I honestly don't see any advantage, other than the historical simplification of a piecemeal implementation of a C compiler, to completely separating the C macro facilities from the compiler proper. The nagging necessity of protecting against side-effects in macros, and the compiler being forced in the interests of generating good code to generally presume the non-programmer-significance of parentheses, are two nits of using C that could have been avoided with a better integrated macro facility. -- Jim Valerio {verdix,intelca!mipos3}!omepd!jimv, jimv@omepd.intel.com