Re: Rounding off double precision
- From: "Gerry Ford" <gerry@xxxxxxxxxxxx>
- Date: Mon, 31 Mar 2008 00:19:26 -0700
"glen herrmannsfeldt" <gah@xxxxxxxxxxxxxxxx> wrote in message
news:n9idnTScSJC6423anZ2dnUVZ_qninZ2d@xxxxxxxxxxxxxx
Louis Krupp wrote:
(snip)
I think you mean MIN instead of ABS. ABS would be something like:
#define ABS(x) ((x) >= 0 ? (x) : -(x))
Unlike a FORTRAN statement function, which this vaguely resembles, macros
that use an argument in more than one place do weird things when passed
an expression with side effects, e.g., ABS(x++).
Yes, both are often written as macros in C. I was thinking
about both and wrote something in between.
The side effects are something to remember, but it doesn't
take too long as long as you know it is a macro.
You have peeked (sp) my interest here.
PRE00-A. Prefer inline functions to macros
The claim that 'macros are dangerous' can, to a certain extent, be
justified, in much the same way that the claim 'crossing the road is
dangerous' can be justified. Crossing the road is dangerous, even to the
experienced road user, if done carelessly. Likewise, using macros can be
problematic. SECCODE quotes the classic i++ abuse of a macro call, and
suggests that inline functions can eliminate this problem.
This is certainly true where inline functions are available. It is true
that C99 guarantees that inline functions are available, but nowhere is
there any guarantee that a C99 implementation is available! Yes, within
the terms of reference of SECCODE, the suggestion to use inline functions
has obvious merit. But for those of us without access to inline functions,
it is impractical. SECCODE itself recognises this, by pointing out
portability concerns.
For the experienced C programmer, the use of UPPER CASE for macro names is
generally sufficient to act as a warning that macro arguments with side
effects should be avoided.
In the first code fragment, we see a #define that is clearly local to a
function (because the fragment contains executable code). This is
generally considered to be unwise. I can see why the fragment is written
that way, of course - it's to save space! But in a document which purports
to provide a guide to best practice, it's still a curious way to write
code.
The expansion given in the second code fragment is (trivially) incorrect.
Strictly, it should be:
int a = 81 / ((++i) * (++i) * (++i));
The SECCODE version of the expansion omits the extra parentheses that its
previous definition requires.
The third code fragment, which demonstrates the inline version of the code,
is poorly written. When we're cubing a value, even a moderate input can
result in overflow. For example, on 16-bit-int systems, i = 32 will
produce overflow in the call to cube. On 32-bit-int systems, i = 1291
(hardly excessive) will produce overflow. Precisely how one would solve
this problem depends on one's requirements. If it is known that excessive
inputs will never occur, an assertion is appropriate. If they may well
occur, it must be decided whether they constitute an error. If so, the
function needs a way to report that error. Otherwise, an alternative
strategy (e.g. bignums) must be considered. In any event, the function as
written is insecure, because it can produce undefined behaviour.
The fourth fragment illustrates that a clash between a macro parameter name
and a file scope object name can cause incorrect results. It seems to me,
however, that this is not so much a reason not to use macros as a reason
not to use file scope objects!
In the 'SWAP' example, the hoary old XOR trick is used to swap two values.
This is a really bad idea, for two reasons: firstly, it only works on
integer types: SWAP(mydoubleA, mydoubleB) will fail to compile. Secondly,
if you do this: SWAP(myintA, myintA), you don't get a swap - you get 0!
The example, then, is a poor one. Whilst the suggested replacement
sidesteps the first problem neatly (because it suggests a function that
takes int *, so nobody can reasonably expect it to swap doubles), it fails
to address the second problem. Far better to use a temp:
void swap(int *pa, int *pb)
{
int tmp = *pa;
*pa = *pb;
*pb = tmp;
}
This is guaranteed to work, provided only that pa and pb point to valid int
objects.
The example where the interaction of two macros and a file scope object
produce incorrect results is rather contrived. It's an argument against
using macros to adjust file scope object values. It's an argument against
file scope object values themselves. It's an argument against tight
coupling. But it's not an argument against macros.
The claim that the execution of functions cannot be interleaved 'so
problematic orderings are not possible' ignores the fact that the order of
evaluation of multiple functions called in the same statement is not
specified. Whilst this doesn't cause a problem in the example given, it
can certainly cause problems in cases where the called functions have
related side effects (e.g. updating the same object, writing to the same
stream, or whatever). Although y = f(x) + g(x); is harmless in the example
given, it is not a recipe for success.
Lest the wrong impression be garnered from the above, let me reiterate that
the danger of side effects being unwittingly duplicated by macros is
significant, and the careful programmer should ensure that (a) macros
don't evaluate arguments more than once if at all possible; (b) macro
names are written in UPPER CASE to draw attention to them; (c) macros are
only used if there is no sensible alternative that meets the project
requirements.
#end excerpt from clc
I think what you are both saying about macros could be surmised in a
paragraph.
--
"I am waiting for them to prove that God is really American."
~~ Lawrence Ferlinghetti
.
- References:
- Rounding off double precision
- From: Bamm
- Re: Rounding off double precision
- From: Bamm
- Re: Rounding off double precision
- From: Richard Maine
- Re: Rounding off double precision
- From: Bamm
- Re: Rounding off double precision
- From: e p chandler
- Re: Rounding off double precision
- From: Bamm
- Re: Rounding off double precision
- From: glen herrmannsfeldt
- Re: Rounding off double precision
- From: Charles Coldwell
- Re: Rounding off double precision
- From: glen herrmannsfeldt
- Re: Rounding off double precision
- From: Louis Krupp
- Re: Rounding off double precision
- From: glen herrmannsfeldt
- Rounding off double precision
- Prev by Date: Re: Rounding off double precision
- Next by Date: Re: data with metadata
- Previous by thread: Re: Rounding off double precision
- Next by thread: Re: Rounding off double precision
- Index(es):
Relevant Pages
|
|