Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: CMPLX vs a+bi values
Date: Wed, 27 Jan 2021 07:30:04 -0800
Organization: A noiseless patient Spider
Lines: 73
Message-ID: <86o8hal7nn.fsf@linuxsc.com>
References:
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: reader02.eternal-september.org; posting-host="a3a7a3546220eb2a4a7cfe4d4683198c"; logging-data="13758"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX198Tm5lkYT1n5YYvyTET/xDaoVXJ/tHuM4="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:BwtgRUAtjOrb7r1sowJwdLZEpuk= sha1:Yinr0dJQno7BmEHvPncnFG26kbI=
Xref: csiph.com comp.lang.c:158648
beej@beej.us (Beej) writes:
> Time for another esoteric question!
>
> ----------
>
> #include
>
> double complex a = CMPLX(1, 2);
> double complex b = 1 + 2*I;
>
> ----------
>
> They compare equal, of course. [..discussion of possible
> differences..]
Normally I would prefer to avoid either form. If what you care
about is complex values in ordinary code (ie, in statements or
initializers for non-static locals), you can use something
like this:
typedef double _Complex Z;
typedef union { double xy[2]; Z z; } Union_xy_Z;
#define COMPLEX(x,y) ( (Union_xy_Z){ .xy[0]=(x), .xy[1]=(y) }.z )
Z
minus_one_example_a(){
Z i = COMPLEX( 0, 1 );
return i*i;
}
This COMPLEX macro does not need any header, and works in both
C99 and C11 (provided of course _Complex is supported). It does
have a drawback, in that it cannot be used in initializers at the
top level (what the C standard calls "external definitions").
However, we can define a macro that gives a value of a pointer to
a complex:
#define A_COMPLEX(x,y) ( (Z*) &COMPLEX( x, y ) )
static const Z *const pI = A_COMPLEX( 0, 1 );
Z
minus_one_example_b(){
return *pI * *pI;
}
Note that the variable 'pI' need not be declared 'const' (for
either or both of the two 'const' modifiers in the declaration).
The A_COMPLEX macro works for external definitions, but because
of how compound literals are defined A_COMPLEX does not work for
'static' declarations inside a function. So if we really need a
function-local static, an explicit intermediate object can be
used to do that:
Z
minus_one_example_c(){
static Union_xy_Z xy_I = {{ 0, 1 }};
Z *const pI = & xy_I.z;
return *pI * *pI;
}
The expression '*pI' can be used to update as well as read the
function-local static object xy_I.z.
All the above is required by the C standard to work in C.
Furthermore, because the two components of a complex are stored
directly, rather than being combined using multiplication or
addition, losing the sign of a (floating) negative zero shouldn't
ever happen.