edp@pyr.gatech.EDU (Eric D. Price) (09/26/88)
In article <8577@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >In article <23@datcon.UUCP> sar@datcon.co.uk (Simon A Reap) writes: >> z = square(x) + square(y); >>Does anyone know how to get round this problem? Please!! > > z = x*x + y*y; Hear hear. This latter construction is MUCH clearer and doesn't require wandering through the source module ... and possibly gobs of header files. -- Warren Tucker ...!{akgua,allegra,amd,hplabs,ihnp4,seismo,ut-ngp}!gatech!gitpyr!edp
karl@haddock.ima.isc.com (Karl Heuer) (09/27/88)
In article <8577@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn) writes: >In article <23@datcon.UUCP> sar@datcon.co.uk (Simon A Reap) writes: >> z = square(x) + square(y); >>Does anyone know how to get round this problem? Please!! > z = x*x + y*y; Doug's answer is certainly a better way to write the given example, but is not particularly enlightening if you want z = square(*p++) + square(getchar()); I dislike the original macro, but the fact remains that there is no good way to write this in C. (There are several bad ways, and we could argue over which is the least bad, but it really depends on the circumstances.) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
swilson%thetone@Sun.COM (Scott Wilson) (09/27/88)
In article <8078@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: >In article <8577@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn) writes: >>In article <23@datcon.UUCP> sar@datcon.co.uk (Simon A Reap) writes: >>> z = square(x) + square(y); >>>Does anyone know how to get round this problem? Please!! >> z = x*x + y*y; > >Doug's answer is certainly a better way to write the given example, but is not >particularly enlightening if you want > z = square(*p++) + square(getchar()); > >I dislike the original macro, but the fact remains that there is no good way >to write this in C. (There are several bad ways, and we could argue over >which is the least bad, but it really depends on the circumstances.) Maybe I'm missing the point, but why does a good old fashion function seem to be out of the question. Or better yet, why not do it like getc/fgetc and define a macro for square and have a function fsquare when side effects are questionable. And just to make it complete have another function fdsquare to square doubles. This way you use square when there is no doubt and the functions when there is. Does this sound reasonable? -- Scott Wilson arpa: swilson@sun.com Sun Microsystems uucp: ...!sun!swilson Mt. View, CA
mcdonald@uxe.cso.uiuc.edu (09/27/88)
>>In article <23@datcon.UUCP> sar@datcon.co.uk (Simon A Reap) writes: >>> z = square(x) + square(y); >Maybe I'm missing the point, but why does a good old fashion function seem >to be out of the question. I certainly hope you aren't a programmer. The answer is blatently obvious: calling overhead. Why in the would would anyone ever even consider writing a function call to perform a single multiplication? The only possible reason is the IBM mentality: "let's write code so bad that it runs so slow that the sucker's will have to buy faster iron!". Actually, one is reduced to using temporaries: temp1 = fun1(); temp2 = fun2(); z = temp1*temp1 + temp2+temp2; and hoping the optimizer removes them.
firth@sei.cmu.edu (Robert Firth) (09/27/88)
In article <70279@sun.uucp> swilson@sun.UUCP (Scott Wilson) writes: In article <8078@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: In article <8577@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn) writes: In article <23@datcon.UUCP> sar@datcon.co.uk (Simon A Reap) writes: [several ways to define "square(x)" in C that don't quite work] Full circle, I think. We're about back where we started with the position that the only effective solution is an exponentiation operator, and let the compiler do the grunt work.
jlh@loral.UUCP (Physically Pffft) (09/27/88)
I was sure someone else would mention this so I didn't keep a copy of the
original article to quote. In general, someone is making a macro
to do z = x*x + y*y, but using a variable 'temp' to do it. I was under the
impression this was a Very Bad Idea for 2 reasons. Lets assume Mr C Wizard
has left the company 6 months ago and now it's up to Miss Molly to change
the code. First, she could use this power macro in a function that didn't
have the variable temp defined. No problem, the compiler spits out the
undefined variable. On the other hand, suppose she wants to put this macro
into a loop. She says to herself 'self, here's a variable temp that ain't used
here'. So we get
for(temp = 0; temp < wanna_quit; temp++){
z = power(x,y);
some_other_stuff;
}
Well boys and girls, lets just hope this blows up in a way thats immediatly
obvious. As a third scenario, combine the first two scenarios. Poor Miss
Molly adds the power macro to a function that already has temp defined
and is definately needed. And lets say it's used in such a way that
her changes work fine and dandy, after all, she doesn't use temp in any
of her changes, but changes the original code in some insidious way.
Again, lets hope the result of changing temp is immediatly obvious.
The moral? Well, if you have to use a temp variable in a macro then
PASS the bloody thing.
#define power(x,y, tmp) (tmp = x*x + y*y, x = tmp)
result = power(x, y, temp);
This ensures that the poor overworked sucker who ends up maintaining your
code knows damn well that your macro requires a temp variable to work right.
Jim
--
Jim Harkins
Loral Instrumentation, San Diego
{ucbvax, ittvax!dcdwest, akgua, decvax, ihnp4}!ucsd!sdcc6!loral!jlh
scs@athena.mit.edu (Steve Summit) (09/28/88)
In article <225800075@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes: >>>In article <23@datcon.UUCP> sar@datcon.co.uk (Simon A Reap) writes: >>>> z = square(x) + square(y); > >>Maybe I'm missing the point, but why does a good old fashion function seem >>to be out of the question. > >I certainly hope you aren't a programmer. The answer is blatently >obvious: calling overhead. Why in the would would anyone ever even >consider writing a function call to perform a single multiplication? I certainly hope you aren't a programmer! :-) A very few of us (it seems) believe that efficiency is not the most important thing in the world, and that code cleanliness, ease of maintenance, the principle of least surprise, etc., are. We would write a function call to perform a single multiplication precisely because the hacker's solution (use a macro) has so many potential unpleasant surprises, as indicated by this discussion. If (and only if) after-the-fact profiling revealed that the function call overhead was the cause of noticeable and undesirable inefficiency, would we replace it with something quicker, probably the explicit x*x Doug recommended, introducing an explicit temporary (i.e. not trying to get the preprocessor to do it for us) if x was a complicated expression or involved side effects. I know there are many people who think that efficiency _i_s the most important thing in the world. (Someone called Andrew Koenig's, I believe, attitude "execrable" for advocating cleanliness over efficiency.) It boils down to a question of priorities. Some find it intolerable if something simple like squaring involves function call overhead. I find it intolerable if what appears to be a function call fails mysteriously because it happens to be implemented as a macro. Steve Summit scs@adam.pika.mit.edu
firth@sei.cmu.edu (Robert Firth) (09/28/88)
In article <23@datcon.UUCP> sar@datcon.co.uk (Simon A Reap) writes: [ suggesting the form z = square(x) + square(y)] >Maybe I'm missing the point, but why does a good old fashion function seem >to be out of the question. In article <225800075@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes: >I certainly hope you aren't a programmer. The answer is blatently >obvious: calling overhead. Why in the would would anyone ever even >consider writing a function call to perform a single multiplication? This prompted me to collect some data. The machine is a MicroVax II running Ultrix, and the times are user time. (a) time for a simple inline single-precision multiplication of a static variable, ie "x := x*x": 5.74 usec (b) time for a simple call to an Assembler code "square" routine, with single-precision operands, operation, and result: 11.23 usec So the overhead is about 100%. Pretty bad. But how about this? (c) time for a simple inline 'C' multiplication with single-precision operands and result, but a double-precision operation 11.50 usec The question is, why would anyone ever even consider writing a function call? Answer: it is not only safer than the C code, it's faster. Unless you're lucky enough to have a newer compiler that junks the bogus floating point semantics.
swilson%thetone@Sun.COM (Scott Wilson) (09/29/88)
>>Maybe I'm missing the point, but why does a good old fashion function seem >>to be out of the question. > >I certainly hope you aren't a programmer. The answer is blatently >obvious: calling overhead. Actually I am a programmer, but please don't tell Sun what an idiot I am or they'll want their money back :-). If you look at what I wrote, I said "out of the question" not "less efficient". I am very aware of calling overhead and why it can be bad. What I was responding to was the attitude that there just isn't any good way to square a number in C. The solution I suggested was to use a macro when there were no possible ill side effects and use a function when there were (just like getc and fgetc). So what is wrong with that? Through the years I've learned one important thing: correctness first, efficiency later. There's nothing terribly exciting about a program that works incorrectly and does it very quickly at the same time. -- Scott Wilson arpa: swilson@sun.com Sun Microsystems uucp: ...!sun!swilson Mt. View, CA
djones@megatest.UUCP (Dave Jones) (09/29/88)
>>In article <23@datcon.UUCP> sar@datcon.co.uk (Simon A Reap) writes: >> z = square(x) + square(y); > >Maybe I'm missing the point, but why does a good old fashion function seem >to be out of the question. > It is not out of the question by any means. It is just that on some implementations, especially those with hardware integer multiply, and for some applications, the function call overhead may add significantly to the execution time. As has already been pointed out, the "morally correct" way to do it is, z = x*x + y*y; avoiding both the SLM* and the function call. *SLM /ess el em/ n. (comp. acrnm.) Silly little macro. P.s. I attempted to post the following directly to Mr. Reap, but I could not find a path. Dear Mr. Reap, I hope you are not too put off by any response to your question which you may have seen. Most of the programmers here in the U.S. are quite polite and helpful. A few are not, and the net attracts them. I suspect that most of these fellows have yet to hold down a full time programming job producing real products which must compete in the marketplace. That almost invariably cures such arrogance. After two or three years, they generally discover, that (1) they are not as good as they thought they were, (2) they are not as good as most of the people who have been doing it longer, and (3) in this business, it is very easy to look like a jerk. Please, don't ask me how I know. Best wishes, Dave
nevin1@ihlpb.ATT.COM (Liber) (09/29/88)
In article <7173@aw.sei.cmu.edu> firth@bd.sei.cmu.edu (Robert Firth) writes: >>[several ways to define "square(x)" in C that don't quite work] >Full circle, I think. We're about back where we started with the >position that the only effective solution is an exponentiation >operator, and let the compiler do the grunt work. In other words, there is no solution within the framework of C. There are a number of large number of functions that I would rather have as macros (especially when I have the same operation for different argument types), but can't because I'm not allowed to (in general) assume that parameters passed will behave as simple variables w/o side effects. Just fixing the problem by changing square(x) to an operator (no, I DON'T want to start up that discussion again!) doesn't help with the more general problem, and is, in effect, just another kludge to C. What is really wanted is to be able to declare macros so that it would have the same semantics as an inlined function would (somewhat like C++ inlining, except that type checking would not be done on the arguments. Then again, maybe type checking ought to be done on the arguments...). When do the proposals for dpANS C II start? :-) -- _ __ NEVIN J. LIBER ..!att!ihlpb!nevin1 (312) 979-4751 IH 4F-410 ' ) ) "I catch him with a left hook. He eels over. It was a fluke, but there / / _ , __o ____ he was, lying on the deck, flat as a mackerel - kelpless!" / (_</_\/ <__/ / <_ These are NOT AT&T's opinions; let them make their own.
nevin1@ihlpb.ATT.COM (Liber) (09/29/88)
In article <7213@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes: >A very few of us (it seems) believe that efficiency is not the >most important thing in the world, Must be some who programs in the academic environment, not the commercial environment. :-) >and that code cleanliness, >ease of maintenance, the principle of least surprise, etc., are. But I want BOTH! Unfortunately, in this instance, C macros are not powerful enough to give me both. (I'm wishing more and more that C allowed a way of allowing macros to act like functions with respect to passing parameters -- not quite inline functions, but close.) >We would write a function call to perform a single multiplication >precisely because the hacker's solution (use a macro) has so many >potential unpleasant surprises, as indicated by this discussion. If readability is of that much concern, why not use a language more suited for the job? The fact is that one of the reasons C is chosen is because of its efficiency over other languages. >If (and only if) after-the-fact profiling revealed that the >function call overhead was the cause of noticeable and >undesirable inefficiency, would we replace it with something >quicker, Effectively, you would do a tweak. Personally, I do not believe that efficiency can be tweaked in to a program; it has to be designed in from the beginning. Assuming infinitely fast CPUs and infinite memory are assumptions that we can no longer afford to make. Tweaking should be saved for fixing the *unforseen* bottlenecks. >introducing >an explicit temporary (i.e. not trying to get the preprocessor to >do it for us) if x was a complicated expression or involved side >effects. Well, if x really is a complicated expression, then the code probably isn't all that clean anyway. As long as you always have clean code, you shouldn't have problems with macros. It's when you want to make your macros safe from unclean code that you run into problems. >I find it intolerable >if what appears to be a function call fails mysteriously because >it happens to be implemented as a macro. Then macros shouldn't look like function calls! Since C does not self-document this fact at every macro invocation, you need to set up a convention that distinguishes macros from functions (ie, all macros that are not guaranteed to to behave as a function call are denoted in all caps). I am not trying to say that I think efficient code is more important than readable code. Personally, I would like clean, self-documenting code that is efficient (the best of all worlds). In many situations, however, a tradeoff needs to be made, and this tradeoff should not be resolved by blanket statements such as "Efficiency is better than readability" (or vice-versa). What we have found with C macros is that they are not good for all the situations we want to use them for. They are inadequate replacements for function calls; the question is: is it worth modifying them to make them more useful? IMHO, I think that this would be a good thing (for ANSI C II :-)). -- _ __ NEVIN J. LIBER ..!att!ihlpb!nevin1 (312) 979-4751 IH 4F-410 ' ) ) "I catch him with a left hook. He eels over. It was a fluke, but there / / _ , __o ____ he was, lying on the deck, flat as a mackerel - kelpless!" / (_</_\/ <__/ / <_ These are NOT AT&T's opinions; let them make their own.
cik@l.cc.purdue.edu (Herman Rubin) (09/29/88)
In article <1851@loral.UUCP>, jlh@loral.UUCP (Physically Pffft) writes: < I was sure someone else would mention this so I didn't keep a copy of the < original article to quote. In general, someone is making a macro < to do z = x*x + y*y, but using a variable 'temp' to do it. I was under the < impression this was a Very Bad Idea for 2 reasons. Lets assume Mr C Wizard < has left the company 6 months ago and now it's up to Miss Molly to change < the code. First, she could use this power macro in a function that didn't < have the variable temp defined. No problem, the compiler spits out the < undefined variable. On the other hand, suppose she wants to put this macro < into a loop. She says to herself 'self, here's a variable temp that ain't used < here'. So we get < > for(temp = 0; temp < wanna_quit; temp++){ > z = power(x,y); > some_other_stuff; > } > > Well boys and girls, lets just hope this blows up in a way thats immediatly > obvious. As a third scenario, combine the first two scenarios. Poor Miss > Molly adds the power macro to a function that already has temp defined > and is definately needed. And lets say it's used in such a way that > her changes work fine and dandy, after all, she doesn't use temp in any > of her changes, but changes the original code in some insidious way. > Again, lets hope the result of changing temp is immediatly obvious. > > The moral? Well, if you have to use a temp variable in a macro then > PASS the bloody thing. > > #define power(x,y, tmp) (tmp = x*x + y*y, x = tmp) > > result = power(x, y, temp); > > This ensures that the poor overworked sucker who ends up maintaining your > code knows damn well that your macro requires a temp variable to work right. No, this doesn't necessarily work either. Suppose that this code is part of something else (a very likely situation) which uses a variable temp. Then the value of that variable is clobbered. What is needed is something like #define fc(x,y) (LOCAL tmp1,tmp2; tmp1=x; tmp2=y; fc(x,y)=tmp1*tmp1+tmp2*tmp2) which should be interpreted correctly even if x or y happens to be tmp1 or tmp2. That is, the LOCAL designation should provide a tag which separates the local variables from the rest, and disambiguates name collision. The user should not have to worry about whether the local designations in a block, or in a #define, etc. conflict with global. I believe that this also addresses the problem of code maintenance by someone other than the code writer. I do not know to what extent compiler implementations do this, but I doubt that a #define is treated other than a macro expansion, and I do not see how the problem can be avoided without something like this. -- Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907 Phone: (317)494-6054 hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)
bill@proxftl.UUCP (T. William Wells) (09/29/88)
In article <1851@loral.UUCP> jlh@loral.UUCP (Physically Phffft) writes:
: [A long section explaining a bug easily caused by temps used in macros]
:
: The moral? Well, if you have to use a temp variable in a macro then
: PASS the bloody thing.
:
: #define power(x,y, tmp) (tmp = x*x + y*y, x = tmp)
:
: result = power(x, y, temp);
:
: This ensures that the poor overworked sucker who ends up maintaining your
: code knows damn well that your macro requires a temp variable to work right.
We have a coding standard that makes globals always distinct from
locals: globals *always* start with a capital letter; locals,
never. Given this, we can handle this problem with
int Square_temp; /* Macro only works for ints, oh well. */
#define square(x) (Square_temp = (x), Square_temp * Square_temp)
I would never do this (not without a compelling reason, anyway),
but should someone do so here, at least they'd not get bitten by
the local-global problem.
---
Bill
You can still reach me at proxftl!bill
But I'd rather you send to proxftl!twwells!bill
charette@edsews.EDS.COM (Mark A. Charette) (09/29/88)
In article <70616@sun.uucp>, swilson%thetone@Sun.COM (Scott Wilson) writes: > learned one important thing: correctness first, efficiency later. There's > nothing terribly exciting about a program that works incorrectly and > does it very quickly at the same time. > > -- > Scott Wilson arpa: swilson@sun.com > Sun Microsystems uucp: ...!sun!swilson > Mt. View, CA I'm not so sure about that. I've written a few incorrect programs that ran fast and were TERRIBLY exciting. ;') -- Mark Charette "Unmitigated seriousness is always out of Electronic Data Systems place in human affairs." - G. Santayana 750 Tower Drive Voice: (313)265-7006 Troy, MI 48007-7019 charette@edsews.eds.com uunet!edsews!charette
peter@ficc.uu.net (Peter da Silva) (10/01/88)
In article <8813@ihlpb.ATT.COM>, nevin1@ihlpb.ATT.COM (Liber) writes: > What is really wanted is to be able to declare macros so that it would have > the same semantics as an inlined function would (somewhat like C++ > inlining, except that type checking would not be done on the arguments. I don't know how C++ inlining works but one of the long-standing things on my wishlist is: inline putc(c, fp) char c; FILE *fp; { if(--fp->_cnt >= 0) *fp->ptr++ = c; else _flsbuf(c, fp); } -- Peter da Silva `-_-' Ferranti International Controls Corporation. "Have you hugged U your wolf today?" peter@ficc.uu.net
gateley@mips.csc.ti.com (John Gateley) (10/02/88)
In article <956@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes: >What is needed is something like >#define fc(x,y) (LOCAL tmp1,tmp2; tmp1=x; tmp2=y; fc(x,y)=tmp1*tmp1+tmp2*tmp2) >which should be interpreted correctly even if x or y happens to be tmp1 or tmp2. >I do not know to what extent compiler implementations do this, but I doubt >that a #define is treated other than a macro expansion, and I do not see >how the problem can be avoided without something like this. The ONLY place I have heard of this being done for macros is in the programming language Scheme: using Eugene Kohlbecker's et al. beta-expansion macro expander, or more recently Johnathon Rees's syntactic closures. I think you are out of luck with C. What might help is a generate symbol operation. This should give you a brand new symbol each time it is called. You might be able to fake it in C somehow. John Gateley gateley@mips.csc.ti.com
gwyn@smoke.ARPA (Doug Gwyn ) (10/03/88)
In article <8078@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: > z = square(*p++) + square(getchar()); >I dislike the original macro, but the fact remains that there is no good way >to write this in C. One wonders whether this is much of a problem. (Note that the example is silly.) There have been many occasions when I've needed the sum of two squares, but I've never felt the need for the ability to define a "square" macro in order to compute that.
gwyn@smoke.ARPA (Doug Gwyn ) (10/03/88)
In article <7191@aw.sei.cmu.edu> firth@bd.sei.cmu.edu (Robert Firth) writes: >The question is, why would anyone ever even consider writing a function >call? Answer: it is not only safer than the C code, it's faster. Not necessarily, but it can be. Also, I know of at least one compiler that will expand a function in-line whenever it would be efficient to do so (and when C permits it).
rob@kaa.eng.ohio-state.edu (Rob Carriere) (10/04/88)
In article <8590@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >One wonders whether [the inability to define a square macro] is much of a >problem. How about the following, deep in some inner loop: foo = square( sin( x )) + 1.7; I *don't* want to write: foo = sin( x )*sin( x ) + 1.7; and temp = sin( x ); foo = temp*temp + 1.7; is clearly less legible. Rob Carriere
djones@megatest.UUCP (Dave Jones) (10/04/88)
From article <701@accelerator.eng.ohio-state.edu), by rob@kaa.eng.ohio-state.edu (Rob Carriere):
)
) How about the following, deep in some inner loop:
)
) foo = square( sin( x )) + 1.7;
)
) I *don't* want to write:
)
) foo = sin( x )*sin( x ) + 1.7;
)
) and
)
) temp = sin( x );
) foo = temp*temp + 1.7;
)
) is clearly less legible.
^^^^^^^ ^^^^ ^^^^^^^
To me it is clearly much more legible, becuase I don't have to worry
about whether "square" has side-effects! I would write it like this:
{ register double sin_x = sin(x);
foo = (sin_x * sin_x) + 1.7;
}
Always restrict the scope of variables as strictly as possible.
In the above, the reader (and the compiler!) knows that the variable
sin_x is never used except on those two lines.
(If the compiler were smart enough to know that sin() has no side-effects,
it could transform " foo = sin(x)*sin(x) + 1.7 " into the code I
prefer by means of "common subexpression removal".)
english@stromboli.usc.edu (Joe English) (10/04/88)
In article <701@accelerator.eng.ohio-state.edu> rob@kaa.eng.ohio-state.edu (Rob Carriere) writes: >In article <8590@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >>One wonders whether [the inability to define a square macro] is much of a >>problem. > >How about the following, deep in some inner loop: >foo = square( sin( x )) + 1.7; >I *don't* want to write: >foo = sin( x )*sin( x ) + 1.7; > Why not? Unless you're using square() for legibility, the macro expansion is going to be sin(x) * sin(x) anyway. As long as I'm posting, I might as well throw in my two cents' worth, too: I never, ever write a macro whose behaviour is not identical to a function call (or to a constant), simply because of the dangers of side-effects being performed twice. If I want the "right" syntax, I write it as a function, and if I need optimization, I expand it manually. Tightly optimized code is not always pretty, nor does it have to be. The best solution I've found when writing code optimized to the point of obfuscation is to precede it with a comment: /* WARNING: THE FOLLOWING CODE LOOKS AWFUL! DFWI! */ It doesn't enhance the readability, but it at least reminds me to be careful when modifying it. -- /|/| "What do you look for in a quote?" -----< | | --Jay Hinkelman O \|\| english%lipari@oberon.usc.edu
edp@pyr.gatech.EDU (Warren Tucker) (10/05/88)
In article <701@accelerator.eng.ohio-state.edu> rob@kaa.eng.ohio-state.edu (Rob Carriere) writes: >How about the following, deep in some inner loop: >foo = square( sin( x )) + 1.7; >I *don't* want to write: >foo = sin( x )*sin( x ) + 1.7; >and >temp = sin( x ); >foo = temp*temp + 1.7; >is clearly less legible. > >Rob Carriere It may be less legible to use 'temp' but sin(x)*sin(x) calculates the sine of x twice. -- Warren Tucker ...!{akgua,allegra,amd,hplabs,ihnp4,seismo,ut-ngp}!gatech!gitpyr!edp
gwyn@smoke.ARPA (Doug Gwyn ) (10/05/88)
In article <701@accelerator.eng.ohio-state.edu> rob@kaa.eng.ohio-state.edu (Rob Carriere) writes: >In article <8590@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >>One wonders whether [the inability to define a square macro] is much of a >>problem. >How about the following, deep in some inner loop: >foo = square( sin( x )) + 1.7; Another silly example. I can't imagine a real algorithm that would want this computation in it. >temp = sin( x ); >foo = temp*temp + 1.7; >is clearly less legible. Most programmers wouldn't have any trouble with foo = sin(x); foo = foo*foo + 1.7; I agree that an exponentiation operator would be handy, but a "square" macro doesn't seem to help readability.
rpw3@amdcad.AMD.COM (Rob Warnock) (10/05/88)
The first "implementation language" I ever used (*not* counting FORTRAN!) was BLISS-10 (circa 1971 on a PDP-10). BLISS is an "expression language", meaning that almost every construct has a value. If you have trouble with this, imagine if the ";" had the same semantics as C's "," operator. So the value of a "block" (a BEGIN-END pair, like C's {} pairs) was the value of the last expression (C's "statement") in it. Since blocks can have declarations of local variables, this macro problem we've seen so much comment on was trivial (shown using C-like syntax, not real BLISS): #define square(x) (int sqr_tmp, sqr_tmp = (x), sqr_tmp * sqr_tmp ) ... foo = square(x++); /* x**2, with only one increment of x */ foo = square(square(x++)); /* x**4, with only one increment of x */ The "sqr_tmp" is local to the body of the macro, and, as in C, inner declarations override outer ones. What was really nice about BLISS was that all of IF, CASE, WHILE, etc., had values, too. (The value of a loop was "-1" if the loop terminated "normally", and the argument of a "LEAVE" [like C's "break"] if that was used instead.) It is irritating in C that you can't have declarations on the left-hand side of a "," operator... Rob Warnock Systems Architecture Consultant UUCP: {amdcad,fortune,sun}!redwood!rpw3 ATTmail: !rpw3 DDD: (415)572-2607 USPS: 627 26th Ave, San Mateo, CA 94403
steve@oakhill.UUCP (steve) (10/05/88)
<1401@devsys.oakhill.UUCP> <8629@smoke.ARPA> In case you don't remember, I was the one who first brought up the use of temp in this discussion. At that point in time the discussion was the technique on writing macros, not the technique on writing the macro square. Most comments on why square is not sane to write this way miss the point of the original discussion. Square was just a trivial example. A similar macro I have used have involved setting bit fields, where the variable holding the bit also is needed later in the bit field calculation. Using a macro to do this covers up a messy equation, and makes it more obvious what going on. Now lets get back to the original discussion. As I pointed out at that time, the use of temp was not optimal. The two big draw backs are : 1) It is inefficient. Thus should be used only in the case where a change in a variable in the equation is likely and will change the result (square(x++)), or where the variable could be an expression that is costly to calculate (square((cos(x)/sin(x))). 2) the use of a temp which must be supplied. The second I have gotten around by suppling the temp as a parameter to the macro (as someone has mentioned and I was remiss in not mentioning. (I figured everyone would see this problem, and be able to program around it their own way) The major point of my posting was two-fold. First to warn people they need to think before they macro-ed. And also to point out that the proposed solution had drawbacks. I conclude with the statement I concluded my last posting with : > Use your best judgement - macros are dangerous thing if not used carefully > That is why C compilers have a -P option. enough from this mooncalf - Steven ---------------------------------------------------------------------------- These opinions aren't necessarily Motorola's or Remora's - but I'd like to think we share some common views. ---------------------------------------------------------------------------- Steven R Weintraub cs.utexas.edu!oakhill!devsys!steve Motorola Inc. Austin, Texas (512) 440-3023 (office) (512) 453-6953 (home) ----------------------------------------------------------------------------
rob@phao.eng.ohio-state.edu (Rob Carriere) (10/05/88)
In article <855@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: >From article <701@accelerator.eng.ohio-state.edu), by rob@kaa.eng.ohio-state.edu (Rob Carriere): >)[...] >) temp = sin( x ); >) foo = temp*temp + 1.7; >) >) is clearly less legible. > ^^^^^^^ ^^^^ ^^^^^^^ > >To me it is clearly much more legible, becuase I don't have to worry >about whether "square" has side-effects! I should have stated the assumption that ``square'' was some well-defined system function/macro/whatever (don't leave your math library without one!). Otherwise, you sure have a good point. >Always restrict the scope of variables as strictly as possible. Amen. >(If the compiler were smart enough to know that sin() has no side-effects, > it could transform " foo = sin(x)*sin(x) + 1.7 " into the code I > prefer by means of "common subexpression removal".) Yes, but I can't rely on the compiler being smart, unless I like nasty surprises. Also, while I can check ``sin(x) is the same as sin(x)'' readily enough, it rapidly gets worse with more complicated expressions. This is essentially the same thing the *= operator &friends solve for assignments. In the same vein, if the expression gets nasty enough that I need several temporaries, I may get to the point where I can't see the expression for the temporaries. Rob Carriere
rob@phao.eng.ohio-state.edu (Rob Carriere) (10/06/88)
In article <12546@oberon.USC.EDU> english@stromboli.usc.edu (Joe English) writes: >In article <701@accelerator.eng.ohio-state.edu> rob@kaa.eng.ohio-state.edu >(Rob Carriere) writes: >>I *don't* want to write [in some inner loop] >>foo = sin( x )*sin( x ) + 1.7; >Why not? Unless you're using square() for legibility, the macro >expansion is going to be sin(x) * sin(x) anyway. That was the point of the original discussion. Needlessly evaluating transcendental functions twice is generally frowned upon in numerical circles. Rob Carriere
djones@megatest.UUCP (Dave Jones) (10/06/88)
From article <1527@devsys.oakhill.UUCP>, by steve@oakhill.UUCP (steve): > <1401@devsys.oakhill.UUCP> <8629@smoke.ARPA> > > In case you don't remember, I was the one who first brought > up the use of temp in this discussion. At that point in time the > discussion was the technique on writing macros, not the technique on > writing the macro square. Most comments on why square is not > sane to write this way miss the point of the > original discussion. Square was just a trivial example... Fair enough. Things have gotten off the track a little. I posted a reply because I hate those silly little macros that send me poking through .h files for no good reason, and fool my debugger. Still, there are plenty of uses for macros, and YES!, even temps in macros. I have a memory allocation package that despenses memory packets of a predetermined size. It gets them wholesale from malloc, and then keeps them in a linked list. It can improve the speed of some kinds of programs very dramaticly, making some run hundreds of times faster than they would if they called the libc's malloc() for every heap-packet. (The malloc in Sun3 bsd 4.2, rel 3.4 libc gets slower and slower as heap usage increases, finally almost coming to a stop. I don't know why.) The stategy helps so much that the procedure call overhead for Heap_alloc() and Heap_free() can become significant. So, in addition to the regular proceudre versions (for debugging), the library provides two macros. Problem is, they need a temp-variable for handling the free-list. The solution is to define a "tmp" in the structure which defines the heap. /* ** RCSHeader = $Header: heap.h,v 1.1 88/08/24 22:21:50 langmgr Exp $ ** Copyright = Copyright (C) 1988 by Megatest Corporation All Rights Reserved ** TheAuthor = Dave Jones (djones at goofy) */ #ifndef HEAP_H_ #include "smalloc.h" typedef struct Heap_unit { struct Heap_unit* next; /* More memory allocated here... */ } Heap_Unit; typedef struct heap /* implements heap of packets of a fixed size */ { int packet_size; /* in units of sizeof(Heap_unit) */ int num_elements; /* number of packets to allocate in next block */ Heap_Unit* cache; /* queue of all blocks of packets */ Heap_Unit* next_free; /* free-list of packets */ Heap_Unit* tmp; /* temporary. used in alloc and free */ }Heap; extern Ptr Heap_underflow(); #define Heap_alloc(obj) \ ((obj)->next_free == 0 ? \ Heap_underflow(obj): \ (Ptr) ( (obj)->tmp = (obj)->next_free, \ (obj)->next_free = (obj)->next_free->next, \ (obj)->tmp \ ) \ ) #define Heap_free(obj,packet) \ ((void)( (obj)->tmp = (obj)->next_free, \ (obj)->next_free = (Heap_Unit*)packet, \ ((Heap_Unit*)packet)->next = (obj)->tmp \ ) \ ) /* allocate new heap */ extern Heap* Heap_new(/* size, init_size */) /* dispose of heap allocated with Heap_new() */ void Heap_dispose(/* obj */) /* Heap *obj; */ /* Initialize a heap (static or automatic, for example) */ Heap* Heap_init(/* obj, size, init_size */) /* register Heap* obj; */ /* Clean up a heap initialized by Heap_init() */ extern Heap* Heap_clean(/* obj */); /* register Heap* obj; */ #define HEAP_H_ #endif HEAP_H_
rob@kaa.eng.ohio-state.edu (Rob Carriere) (10/06/88)
In article <8629@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >In article <701@accelerator.eng.ohio-state.edu> rob@kaa.eng.ohio-state.edu >(Rob Carriere) writes: >>In article <8590@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >>>One wonders whether [the inability to define a square macro] is much of a >>>problem. >>How about the following, deep in some inner loop: >>foo = square( sin( x )) + 1.7; > >Another silly example. I can't imagine a real algorithm that would want >this computation in it. If you leave off the ``+1.7'' that was there for decoration anyway, try an FFT. >Most programmers wouldn't have any trouble with > foo = sin(x); > foo = foo*foo + 1.7; > >I agree that an exponentiation operator would be handy, >but a "square" macro doesn't seem to help readability. 1) If you have a text in front of you that says sin(x)^2 + 1.7 (LaTeX notation, not C), then there *is* a problem with the temporary: you have to go back and check it every time you read the statement. If the sin(x) gets more complicated, this just about destroys readability (I've had cases where it took pencil, paper and five minutes of algebra to verify that all the temporaries did what they were supposed to do -- not my definition of high readability) 2) I used the ``square'' macro, because that was the original example. I agree that what is needed is a way of doing small integer powers in general, but that just changes the problem to: why can't I write power( sin(x), 2 ) [1] or some such. Rob Carriere [1] not pow( sin(x), 2). I want something that will become 1 evalution of sin(x) and 1 multiply.
gwyn@smoke.ARPA (Doug Gwyn ) (10/06/88)
In article <716@accelerator.eng.ohio-state.edu>, rob@kaa.eng.ohio-state.edu (Rob Carriere) writes: > 2) I used the ``square'' macro, because that was the original example. > I agree that what is needed is a way of doing small integer powers > in general, but that just changes the problem to: why can't I write > power( sin(x), 2 ) [1] or some such. > [1] not pow( sin(x), 2). I want something that will become 1 > evalution of sin(x) and 1 multiply. Ah, now we get down to the real functional need. If you use a "static" function for this, a really good optimizing compiler can (a) turn the "pure" function into an in-line expansion and (b) use the constant 2 or whatever to unroll the loop. This is a round-about way of obtaining the effect that a Fortran compiler could also do at compile time for an instance of its ** operator. Many C compilers aren't that good but a couple seem to come close enough that maybe they would produce code as good as Fortran.
wes@obie.UUCP (Barnacle Wes) (10/07/88)
In article <8078@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: > z = square(*p++) + square(getchar()); > I dislike the original macro, but the fact remains that there is no good way > to write this in C. In article <8590@smoke.ARPA>, gwyn@smoke.ARPA (Doug Gwyn ) replies: | One wonders whether this is much of a problem. | (Note that the example is silly.) | | There have been many occasions when I've needed the sum of two squares, | but I've never felt the need for the ability to define a "square" macro | in order to compute that. This code fragment was taken from a function that calculates the true wind speed and heading based on the apparent wind speed and angle, and the speed and course of a sailboat. Note the last line: /* * Now return the true wind vector to normal coordinates. */ tw.heading = atan2(tw.ycomp, tw.xcomp); tw.speed = sqrt((tw.ycomp * tw.ycomp) + (tw.xcomp * tw.xcomp)); This seems the obvious way to perform such a calculation to me. If any of you net.c.programmers really can't stand this style, please tell me why! -- {hpda, uwmcsd1}!sp7040!obie!wes "How do you make the boat go when there's no wind?" -- Me --
gwyn@smoke.ARPA (Doug Gwyn ) (10/09/88)
In article <207@obie.UUCP> wes@obie.UUCP (Barnacle Wes) writes: > tw.heading = atan2(tw.ycomp, tw.xcomp); > tw.speed = sqrt((tw.ycomp * tw.ycomp) + (tw.xcomp * tw.xcomp)); A perfect opportunity to use the hypot() function. Unfortunately X3J11 chose not to standardize it, but if it doesn't exist on some system you can easily provide one that works no worse than the explicit code given above. (A good implementation of hypot is more accurate and robust.)
john13@garfield.MUN.EDU (John Russell) (10/11/88)
In article <1527@devsys.oakhill.UUCP> steve@oakhill.UUCP (steve) writes: ><1401@devsys.oakhill.UUCP> <8629@smoke.ARPA> >As I pointed out at that time, the use of temp was not optimal. The two >big draw backs are : > 1) It is inefficient. > 2) the use of a temp which must be supplied. How about this for an addition to C: a special keyword, similar to const, which declares that a function which is passed identical values will always return the same value, and that the function has no side effects. Example: consistent double cos(); #define square(x) ((x) * (x)) a = PI / 2.0; b = square(cos(a)); The compiler knows "a" does not change in the expanded expression, so it uses its own temp and only calls cos once. Is this feasible? Doesn't sound too hard... John -- "...and intuition, in a case such as this, is of crucial importance." -- William Gibson, _Count_Zero_
jhh@ihlpl.ATT.COM (Haller) (10/12/88)
In article <4920@garfield.MUN.EDU>, john13@garfield.MUN.EDU (John Russell) writes: > How about this for an addition to C: a special keyword, similar to const, > which declares that a function which is passed identical values will always > return the same value, and that the function has no side effects. The information to do this is already available, and a truely optimizing compilation system should do this. Note that I said compilation system, not compiler, where a makefile for a product would be the likely input. When compiling cos(), the compiler should be able to take note of there being no side effects, and take appropriate actions if cos is not re-defined within an application. In the example, consistent double cos(); #define square(x) ((x) * (x)) a = PI / 2.0; b = square(cos(a)); the compilation system should be able to detect that 'a' is set from a constant, call cos(a) at compile time, perform the square are compile time, and reduce the fragment to a=1.57..; b=0.0;, all without the need for 'consistent'. This optimization may be beyond the capability of current C compilers, but we should not be introducing new keywords to solve problems that should be solved with compilation technology in the future. John Haller AT&T Bell Laboratories
firth@sei.cmu.edu (Robert Firth) (10/18/88)
In article <716@accelerator.eng.ohio-state.edu>, rob@kaa.eng.ohio-state.edu (Rob Carriere) writes:
[The need for a maintainable and efficient way to write things like
y := sin(x)^2 +1.7
]
I agree fully with Mr Carriere that most of the suggestions for hand
optimising this kind of thing are unworkable. Scientific programs
typically contain not simple statements like the above, but statements
that run over three or four lines, full of sin(x)^n, sin(x)^(n-1),
2*sin(x-d)*cos(y+d), and so on, and on, and on. These formulae have
been laboriously copied from a reference book or article, and they
are completely unmaintainable unless they follow as closely as possible
the original form. In my experience, even something as simple as
multiplying two polynomials and simplifying the result can take an
hour or more to check thoroughly.
Let the compiler do the work, please. As a corollary: use a language
sufficiently powerful that you can give the compiler enough information
to enable it to do the work.
(Aside: I stuffed the above expression into an Algol-60/Vax compiler,
and duly got
MOVF x,R0
BSBW sin
MULF2 R0,R0
ADDF3 #1.7,R0,y
)
alexis@reed.UUCP (Alexis Dimitriadis) (10/23/88)
Whoever claimed to NEVER write macros that do not behave just like functions (i.e., use their argument more than once, modify an argument, or reference local variables) has good reason for doing so. Still, features unique to macros are sometimes the most convenient way to get from here to there. Yes, there are pitfalls that should be scrupulously avoided. If my macro-with-arguments might not behave like a function, I make sure it does not _look_ like one: I spell its name in uppercase: #define MAX(x, y) (((x) > (y)) ? (x) : (y)) Am I naive in expecting any programmer to check the definition before using something named MAX() with a "dangerous" argument like ++i? Probably... BTW, I nevertheless feel that using a separately-defined local variable is BAD form. If I need an extra variable, I restrict its scope: #define SWAP(x,y) do{ long tmp = x; x = y; y = tmp; } while (0) You cannot do that with a function! (Of course, you cannot use the above in an expression...) Thank you for reading through my $0.02 worth; and forgive me if I just brought up something that got thrashed to death three months ago. Alexis Dimitriadis tektronix!reed!alexis