Complex question

J

jacob navia

hi

I am trying to use the complex data type.

Consider this code, taken from the cclib library:

struct complex csqrt(Cpx z)
{ double r;
r=sqrt(z.re*z.re+z.im*z.im);
r=sqrt(ldexp(r+fabs(z.re),-1));
if(r==0.) z.re=z.im=0.;
else{
if(z.re>=0.){ z.re=r; z.im=ldexp(z.im/r,-1);}
else{ z.re=ldexp(fabs(z.im)/r,-1);
if(z.im>=0.) z.im=r; else z.im= -r;
}
}
return z;
}

Now, this works in lcc-win easily because lcc-win
allows access to the real and imaginary parts of the complex
data type easily, using
z.re (real part)
and
ze.im

for the imaginary part.

I do not see how can be this written in standard C.
Has anyone an idea?

Thanks
 
U

user923005

hi

I am trying to use the complex data type.

Consider this code, taken from the cclib library:

struct complex csqrt(Cpx z)
{ double r;
   r=sqrt(z.re*z.re+z.im*z.im);
   r=sqrt(ldexp(r+fabs(z.re),-1));
   if(r==0.) z.re=z.im=0.;
   else{
     if(z.re>=0.){ z.re=r; z.im=ldexp(z.im/r,-1);}
     else{ z.re=ldexp(fabs(z.im)/r,-1);
       if(z.im>=0.) z.im=r; else z.im= -r;
      }
    }
   return z;

}

Now, this works in lcc-win easily because lcc-win
allows access to the real and imaginary parts of the complex
data type easily, using
z.re (real part)
and
ze.im

for the imaginary part.

I do not see how can be this written in standard C.
Has anyone an idea?

To get the imaginary part:

#include <complex.h>
double cimag(double complex z);
float cimagf(float complex z);
long double cimagl(long double complex z);

But then again, to get the square root, you would just call the
function:

#include <complex.h>
double complex csqrt(double complex z);
float complex csqrtf(float complex z);
long double complex csqrtl(long double complex z);

So I guess you do not have the header complex.h?
In such a case, maybe this is helpful:
http://www.moshier.net/#Complex_variables
 
J

jacob navia

user923005 said:
To get the imaginary part:

#include <complex.h>
double cimag(double complex z);
float cimagf(float complex z);
long double cimagl(long double complex z);

I have been told that those functions are NOT lvalues,
i.e. you can't write

creal(z) = r;

In lcc-win it works since lcc-win defines
#define creal(z) z.re

But I was told in comp.std.c that those are NOT lvalues. This is
the whole problem. There is apparently no way to assign to the
real part or the imaginary part of a complex number.

But then again, to get the square root, you would just call the
function:

#include <complex.h>
double complex csqrt(double complex z);
float complex csqrtf(float complex z);
long double complex csqrtl(long double complex z);

Maybe, but if you want to calculate the complex square root in
the way it is calculated above what do you do?

The point I am trying to make is that the code above is not
possible in C99.
So I guess you do not have the header complex.h?
In such a case, maybe this is helpful:
http://www.moshier.net/#Complex_variables

You are guessing wrong.

Of course lcc-win offers complex.h. But then, precisely,
how do you write the above code USING complex.h ???
 
U

user923005

I have been told that those functions are NOT lvalues,
i.e. you can't write

creal(z) = r;

In lcc-win it works since lcc-win defines
#define creal(z) z.re

But I was told in comp.std.c that those are NOT lvalues. This is
the whole problem. There is apparently no way to assign to the
real part or the imaginary part of a complex number.

13 Each complex type has the same representation and alignment
requirements as an array type containing exactly two elements of the
corresponding real type; the first element is equal to the real part,
and the second element to the imaginary part, of the complex number.

6.3.1.6 Complex types
1 When a value of complex type is converted to another complex type,
both the real and imaginary parts follow the conversion rules for the
corresponding real types.
6.3.1.7 Real and complex
1 When a value of real type is converted to a complex type, the real
part of the complex result value is determined by the rules of
conversion to the corresponding real type and the imaginary part of
the complex result value is a positive zero or an unsigned zero.
2 When a value of complex type is converted to a real type, the
imaginary part of the complex value is discarded and the value of the
real part is converted according to the conversion rules for the
corresponding real type.

24 EXAMPLE 1 Provided that <complex.h> has been #included, the
declarations
int i = 3.5;
complex c = 5 + 3 * I;
define and initialize i with the value 3 and c with the value 5. 0 +
i3. 0.

In the examples in ANNEX G, they seem to deconstruct complex values
into floating point components, do some math, and then reconstitute
the final answer. For example:
8 EXAMPLE 2 Division of two double _Complex operands could be
implemented as follows.
#include <math.h>
#include <complex.h>
/* Dividez / w ... */
double complex _Cdivd(double complex z, double complex w)
{
#pragma STDC FP_CONTRACT OFF
double a,
b,
c,
d,
logbw,
denom,
x,
y;
int ilogbw = 0;
a = creal(z);
b = cimag(z);
c = creal(w);
d = cimag(w);
logbw = logb(fmax(fabs(c), fabs(d)));
if (isfinite(logbw)) {
ilogbw = (int) logbw;
c = scalbn(c, -ilogbw);
d = scalbn(d, -ilogbw);
}
denom = c * c + d * d;
x = scalbn((a * c + b * d) / denom, -ilogbw);
y = scalbn((b * c - a * d) / denom, -ilogbw);
/* Recover infinities and zeros that computed as NaN+iNaN; */
/* the only cases are non-zero/zero, infinite/finite, and finite/
infinite, ... */
if (isnan(x) && isnan(y)) {
if ((denom == 0.0) &&
(!isnan(a) || !isnan(b))) {
x = copysign(INFINITY, c) * a;
y = copysign(INFINITY, c) * b;
} else if ((isinf(a) || isinf(b)) &&
isfinite(c) && isfinite(d)) {
a = copysign(isinf(a) ? 1.0 : 0.0, a);
b = copysign(isinf(b) ? 1.0 : 0.0, b);
x = INFINITY * (a * c + b * d);
y = INFINITY * (b * c - a * d);
} else if (isinf(logbw) &&
isfinite(a) && isfinite(b)) {
c = copysign(isinf(c) ? 1.0 : 0.0, c);
d = copysign(isinf(d) ? 1.0 : 0.0, d);
x = 0.0 * (a * c + b * d);
y = 0.0 * (b * c - a * d);
}
}
return x + I * y;
}
[snip]
 
J

jacob navia

user923005 said:
In the examples in ANNEX G, they seem to deconstruct complex values
into floating point components, do some math, and then reconstitute
the final answer.

Aaaahh, OK, then

z.re=r; z.im=ldexp(z.im/r,-1);

would be

z = r + ldexp(cimag(z)/r,-1)*I;

isn't it?

Thanks... That seems feasible
 
U

user923005

hi

I am trying to use the complex data type.

Consider this code, taken from the cclib library:

struct complex csqrt(Cpx z)
{ double r;
   r=sqrt(z.re*z.re+z.im*z.im);
   r=sqrt(ldexp(r+fabs(z.re),-1));
   if(r==0.) z.re=z.im=0.;
   else{
     if(z.re>=0.){ z.re=r; z.im=ldexp(z.im/r,-1);}
     else{ z.re=ldexp(fabs(z.im)/r,-1);
       if(z.im>=0.) z.im=r; else z.im= -r;
      }
    }
   return z;

}

Now, this works in lcc-win easily because lcc-win
allows access to the real and imaginary parts of the complex
data type easily, using
z.re (real part)
and
ze.im

for the imaginary part.

I do not see how can be this written in standard C.
Has anyone an idea?

Just guessing, since I do not have a C99 compiler handy right now, but
I would say:

#include <complex.h>
double complex my_csqrt(double complex z)
{
double r;
r = sqrt(creal(z) * creal(z) + (cimag(z) * cimag(z)) * I;
r = sqrt(ldexp(r + fabs(creal(z)), -1));
if (r == 0.)
z= 0.0 + 0.0 * I;
else {
if (creal(z) >= 0.) {
z = r + ldexp(cimag(z) / r, -1) * I;
} else {
z = ldexp(fabs(cimag(z)) / r, -1) + cimag(z) >= 0 ? r *
I : -r * I;
}
}
return z;
}
 
A

Army1987

jacob said:
But I was told in comp.std.c that those are NOT lvalues. This is
the whole problem. There is apparently no way to assign to the
real part or the imaginary part of a complex number.

z = creal(z) + I * new_imag_part;
z = new_real_part + I * cimag(z);
 
M

Martin Ambuhl

jacob said:
hi

I am trying to use the complex data type.

Consider this code, taken from the cclib library:

struct complex csqrt(Cpx z)
{ double r;
r=sqrt(z.re*z.re+z.im*z.im);
r=sqrt(ldexp(r+fabs(z.re),-1));
if(r==0.) z.re=z.im=0.;
else{
if(z.re>=0.){ z.re=r; z.im=ldexp(z.im/r,-1);}
else{ z.re=ldexp(fabs(z.im)/r,-1);
if(z.im>=0.) z.im=r; else z.im= -r;
}
}
return z;
}

Now, this works in lcc-win easily because lcc-win
allows access to the real and imaginary parts of the complex
data type easily, using
z.re (real part)
and
ze.im

for the imaginary part.

I do not see how can be this written in standard C.
Has anyone an idea?

Your function works just fine in standard C. Check the following:
#include <math.h>
#include <stdio.h>

/* if you don't have <complex.h>, remove or comment out the line below */
#define USE_COMPLEX_H

typedef struct cmplx
{
double re, im;
} Cpx;
/* 'cmplx' chosen for the name of the struct since 'complex' should be
<complex.h> */

Cpx Csqrt
/* renamed because csqrt should be in <complex.h> */
(Cpx z)
{
double r;
r = sqrt(z.re * z.re + z.im * z.im);
r = sqrt(ldexp(r + fabs(z.re), -1));
if (r == 0.)
z.re = z.im = 0.;
else {
if (z.re >= 0.) {
z.re = r;
z.im = ldexp(z.im / r, -1);
}
else {
z.re = ldexp(fabs(z.im) / r, -1);
if (z.im >= 0.)
z.im = r;
else
z.im = -r;
}
}
return z;
}

Cpx Csquare(Cpx z)
{
Cpx r;
r.re = z.re * z.re - z.im * z.im;
r.im = 2 * z.re * z.im;
return r;
}

#if defined(USE_COMPLEX_H)
#include <complex.h>

double complex Csqrt2(double complex z)
{
double r;
r = sqrt(creal(z) * creal(z) + cimag(z) * cimag(z));
r = sqrt(ldexp(r + fabs(creal(z)), -1));
if (r == 0.)
z = 0.;
else {
if (creal(z) >= 0.) {
z = r + ldexp(cimag(z) / r, -1) * I;
}
else {
z = ldexp(fabs(cimag(z)) / r,
-1) + (cimag(z) >= 0. ? r : -r) * I;
}
}
return z;
}
#endif

int main(void)
{
Cpx x, y, z;
#if defined(USE_COMPLEX_H)
double complex cx, cy, cz;
#endif
int i, j;
printf("Using the function Jacob Navia provided,\n"
"with a struct for complex types.\n\n");
for (i = -2; i < 3; i++)
for (j = -2; j < 3; j++) {
x.re = i;
x.im = j;
y = Csqrt(x);
z = Csquare(y);
printf("y = Csqrt(%g+%gi)) = %g+%gi, y*y=%g+%gi\n",
x.re, x.im, y.re, y.im, z.re, z.im);
}

#if defined(USE_COMPLEX_H)
printf("\nUsing the function Jacob Navia provided,\n"
"rewritten to use complex types.\n\n");
for (i = -2; i < 3; i++)
for (j = -2; j < 3; j++) {
cx = i + j * I;
cy = Csqrt2(cx);
cz = cy * cy;
printf("y = Csqrt2(%g+%gi)) = %g+%gi, y*y=%g+%gi\n",
creal(cx), cimag(cx),
creal(cy), cimag(cy),
creal(cz), cimag(cz));
}

#endif

return 0;
}

[Output]

Using the function Jacob Navia provided,
with a struct for complex types.

y = Csqrt(-2+-2i)) = 0.643594+-1.55377i, y*y=-2+-2i
y = Csqrt(-2+-1i)) = 0.343561+-1.45535i, y*y=-2+-1i
y = Csqrt(-2+0i)) = 0+1.41421i, y*y=-2+0i
y = Csqrt(-2+1i)) = 0.343561+1.45535i, y*y=-2+1i
y = Csqrt(-2+2i)) = 0.643594+1.55377i, y*y=-2+2i
y = Csqrt(-1+-2i)) = 0.786151+-1.27202i, y*y=-1+-2i
y = Csqrt(-1+-1i)) = 0.45509+-1.09868i, y*y=-1+-1i
y = Csqrt(-1+0i)) = 0+1i, y*y=-1+0i
y = Csqrt(-1+1i)) = 0.45509+1.09868i, y*y=-1+1i
y = Csqrt(-1+2i)) = 0.786151+1.27202i, y*y=-1+2i
y = Csqrt(0+-2i)) = 1+-1i, y*y=0+-2i
y = Csqrt(0+-1i)) = 0.707107+-0.707107i, y*y=1.5702e-16+-1i
y = Csqrt(0+0i)) = 0+0i, y*y=0+0i
y = Csqrt(0+1i)) = 0.707107+0.707107i, y*y=1.5702e-16+1i
y = Csqrt(0+2i)) = 1+1i, y*y=0+2i
y = Csqrt(1+-2i)) = 1.27202+-0.786151i, y*y=1+-2i
y = Csqrt(1+-1i)) = 1.09868+-0.45509i, y*y=1+-1i
y = Csqrt(1+0i)) = 1+0i, y*y=1+0i
y = Csqrt(1+1i)) = 1.09868+0.45509i, y*y=1+1i
y = Csqrt(1+2i)) = 1.27202+0.786151i, y*y=1+2i
y = Csqrt(2+-2i)) = 1.55377+-0.643594i, y*y=2+-2i
y = Csqrt(2+-1i)) = 1.45535+-0.343561i, y*y=2+-1i
y = Csqrt(2+0i)) = 1.41421+0i, y*y=2+0i
y = Csqrt(2+1i)) = 1.45535+0.343561i, y*y=2+1i
y = Csqrt(2+2i)) = 1.55377+0.643594i, y*y=2+2i

Using the function Jacob Navia provided,
rewritten to use __complex__ types.

y = Csqrt2(-2+-2i)) = 0.643594+-1.55377i, y*y=-2+-2i
y = Csqrt2(-2+-1i)) = 0.343561+-1.45535i, y*y=-2+-1i
y = Csqrt2(-2+0i)) = 0+1.41421i, y*y=-2+0i
y = Csqrt2(-2+1i)) = 0.343561+1.45535i, y*y=-2+1i
y = Csqrt2(-2+2i)) = 0.643594+1.55377i, y*y=-2+2i
y = Csqrt2(-1+-2i)) = 0.786151+-1.27202i, y*y=-1+-2i
y = Csqrt2(-1+-1i)) = 0.45509+-1.09868i, y*y=-1+-1i
y = Csqrt2(-1+0i)) = 0+1i, y*y=-1+0i
y = Csqrt2(-1+1i)) = 0.45509+1.09868i, y*y=-1+1i
y = Csqrt2(-1+2i)) = 0.786151+1.27202i, y*y=-1+2i
y = Csqrt2(0+-2i)) = 1+-1i, y*y=0+-2i
y = Csqrt2(0+-1i)) = 0.707107+-0.707107i, y*y=1.5702e-16+-1i
y = Csqrt2(0+0i)) = 0+0i, y*y=0+0i
y = Csqrt2(0+1i)) = 0.707107+0.707107i, y*y=1.5702e-16+1i
y = Csqrt2(0+2i)) = 1+1i, y*y=0+2i
y = Csqrt2(1+-2i)) = 1.27202+-0.786151i, y*y=1+-2i
y = Csqrt2(1+-1i)) = 1.09868+-0.45509i, y*y=1+-1i
y = Csqrt2(1+0i)) = 1+0i, y*y=1+0i
y = Csqrt2(1+1i)) = 1.09868+0.45509i, y*y=1+1i
y = Csqrt2(1+2i)) = 1.27202+0.786151i, y*y=1+2i
y = Csqrt2(2+-2i)) = 1.55377+-0.643594i, y*y=2+-2i
y = Csqrt2(2+-1i)) = 1.45535+-0.343561i, y*y=2+-1i
y = Csqrt2(2+0i)) = 1.41421+0i, y*y=2+0i
y = Csqrt2(2+1i)) = 1.45535+0.343561i, y*y=2+1i
y = Csqrt2(2+2i)) = 1.55377+0.643594i, y*y=2+2i
 
J

jacob navia

Army1987 said:
z = creal(z) + I * new_imag_part;
z = new_real_part + I * cimag(z);

Well in the chapter "Awful syntax anyone?" that would
take the first prize...

Or maybe that's too harsh.

fn = (int *(*)(int))foo;

is maybe better

:)

I think I will keep my "extensions"

z.im = new_imag_part;

Easy isn't it?

Why do we have creal()z) (a "getter" function) and not
setreal(z) (the "setter" part)?
 
P

Pierre Asselin

jacob navia said:
In lcc-win it works since lcc-win defines
#define creal(z) z.re

Nitpick: you need
#define creal(z) ((z).re)

to avoid bad interactions with operators when z is an expression
and creal(z) is part of a larger expression.

(this apart from whether creal() can be implemented as a macro,
and whether the standard should provide direct accessors to the
members of a complex.)
 
L

Laurent Deniau

Well in the chapter "Awful syntax anyone?" that would
take the first prize...

Or maybe that's too harsh.

fn = (int *(*)(int))foo;

is maybe better

:)

I think I will keep my "extensions"

z.im = new_imag_part;

Easy isn't it?

Why do we have creal()z) (a "getter" function) and not
setreal(z) (the "setter" part)?

note that example 1 from 6.7.8-24 (assumes complex.h included):

complex c = 5 + 3 * I;

gives two erroneous warning with gcc-4.1.2 -std=c99 -pedantic:

warning: ISO C does not support plain 'complex' meaning 'double
complex'
warning: imaginary constants are a GCC extension

so complex numbers are not yet widely compliant. While this is known
for gcc, I don't now for other widely used compilers (Comeau seems to
be compliant). These half-way implementation are dangerous since only
60-90% compliance are often provided -- enough to think that it works
and enough to give headaches to scientific programmers. 0% or 100%
might have been better.

About the setters, what about?

#define creal(z) ((double*)&(z))[0]
#define cimag(z) ((double*)&(z))[1]

a+, ld.
 
A

Army1987

jacob said:
Well in the chapter "Awful syntax anyone?" that would
take the first prize...

Or maybe that's too harsh.

fn = (int *(*)(int))foo;

is maybe better
Afwulness is in the eye of the beholder.
I think I will keep my "extensions"

z.im = new_imag_part;

Easy isn't it?
I think that you're allowed to do that, as that couldn't break any strictly
conforming program.
Why do we have creal()z) (a "getter" function) and not setreal(z) (the
"setter" part)?
Yes, maybe that'be useful. (Of course that'd not be setreal(z)...)
 
A

Army1987

Pierre said:
Nitpick: you need
#define creal(z) ((z).re)

to avoid bad interactions with operators when z is an expression
and creal(z) is part of a larger expression.

(this apart from whether creal() can be implemented as a macro,
and whether the standard should provide direct accessors to the
members of a complex.)
Any function can be implemented as a macro, but it ought to be
#define creal(z) (((double _Complex)(z)).re)
as it should have the right type regardless of the type of z.
 
P

Philip Potter

Army1987 said:
I think that you're allowed to do that, as that couldn't break any strictly
conforming program.

Not breaking strictly conforming programs is only one requirement of a
conforming implementation. Jacob's extension violates a constraint,
according to n1256 6.5.2.3p1. He's only allowed to do it provided he
issues a diagnostic in conforming mode.
Yes, maybe that'be useful. (Of course that'd not be setreal(z)...)

I can see the argument for it, though it's purely syntactic since

setreal(&z,real); /* or z = setreal(z,real); */

would be equivalent to

z = real + cimag(z)*I;

In fact I prefer the current version of doing things, because C's syntax
does not lend itself to setter functions (ie z.setreal(real) or
setreal(z,real) would not be possible.)
 
K

Keith Thompson

Laurent Deniau said:
note that example 1 from 6.7.8-24 (assumes complex.h included):

complex c = 5 + 3 * I;

gives two erroneous warning with gcc-4.1.2 -std=c99 -pedantic:

warning: ISO C does not support plain 'complex' meaning 'double
complex'
warning: imaginary constants are a GCC extension

The first warning is perfectly correct; ``complex'' doesn't mean
``double complex''. This error in the standard was corrected in
one of the Technical Corrigenda; n1256 has:

double complex c = 5 + 3 * I;

(The "imaginary constants are a GCC extension" message does appear to
be erroneous.)
 
J

jacob navia

Philip said:
Not breaking strictly conforming programs is only one requirement of a
conforming implementation. Jacob's extension violates a constraint,
according to n1256 6.5.2.3p1. He's only allowed to do it provided he
issues a diagnostic in conforming mode.


I can see the argument for it, though it's purely syntactic since

setreal(&z,real); /* or z = setreal(z,real); */

would be equivalent to

z = real + cimag(z)*I;

In fact I prefer the current version of doing things, because C's syntax
does not lend itself to setter functions (ie z.setreal(real) or
setreal(z,real) would not be possible.)

But why z.real and z.imaginary would be forbidden?

It is clear that complex are built from float/double/long double PAIRS.
Why couldn't we agree in the name of those elemnts of the pairs
and be done with it?

Writing

z.real = 5.887;

is Much clearer than

z = creal(z) + 5.887*I;

Besides, it requires a lot LESS implementation effort
than to recognize the first thing as its equivalent.

For a compiler is harder to recognize ALL the possible forms of the
first statement as equivalent

z = 5.887*I+creal(z);
z = (6.887-1.0)*I+creal(z);

etc etc etc!
 
K

Keith Thompson

jacob navia said:
But why z.real and z.imaginary would be forbidden?

The appropriate question when considering adding a feature to the
language is not why it should be forbidden, but why it should be
added.
It is clear that complex are built from float/double/long double PAIRS.
Why couldn't we agree in the name of those elemnts of the pairs
and be done with it?

Writing

z.real = 5.887;

is Much clearer than

z = creal(z) + 5.887*I;

Besides, it requires a lot LESS implementation effort
than to recognize the first thing as its equivalent.
[...]

It certainly *could* have been defined that way, and I wouldn't
particularly object if it were.

But note that using the "foo.member", syntax where foo is something
other than a struct or union, would be unprecedented in standard C.
The complex types are arithmetic types, with a full set of arithmetic
operators defined for them. It's simpler from a language design point
of view to define functions to extract the real and imaginary
components of a complex value, rather than to invent a new mechanism
(that looks very much like struct member access, but isn't really) to
access those components. And since they're functions, their results
are not lvalues (no function can return an lvalue result).

I suppose an alternative would have been to define functions that
return *pointers* to the real and imaginary components:

double complex z = 1.0 + I;
*(crealp(z)) = 1.5; /* now z == 1.5 + I */

But it doesn't make sense to apply this to a *value* of complex type,
and there's no mechanism for restricting a function argument to be an
lvalue, so the parameter needs to be a pointer to complex:

*(crealp(&z)) = 1.5;

IMHO that's too messy to seriously consider adding to the standard.
(But since the standard mandates the representation of complex types,
it could be written in standard C.)

Another possibility might be to add two new keywords, say, _Real and
_Imag, which are the names of new arithmetic operators. The language
could define them to yield an lvalue if and only if the argument is an
lvalue. Presumably they'd have the same precedence as sizeof, and
perhaps <complex.h> could define "real" and "imag" as macros that
expand to them. Then you could write:

real z = 1.5;

I'm not saying I like the idea, just that it's another alternative.

Going back to your proposed z.real and z.imaginary (or z.imag?)
syntax, there are still a number of things to consider. It makes
complex numbers act *sort of* like structures, but not quite. Can
offsetof() be applied to a complex number? Do the requirements for
struct pointers apply to complex pointers? If so, might this conflict
with the existing representation and alignment requirements for
complex types (C99 6.2.5p13)? What namespace are "real" and "imag"
in? Are they keywords or member names? Do we want to use the same
mechanism for other things, such as extracting the sign bit from an
signed integer, or the exponent from a floating-point value? Can
".real" and ".imag" be applied to an arbitrary expression of complex
type, such as ``(z0 + z1).imag''?

I don't think any of these questions are necessarily difficult to
answer, but they'd *all* have to be answered clearly before such a
feature could be added to the standard, along with any other relevant
questions that I haven't thought of.

The authors of the C99 standard either felt it wasn't worth the effort
and complexity to add this feature, or simply didn't think of it.
Yes, it would be convenient, and I actually like the idea, but if
every convenient feature were added to the standard it would be even
more unwieldy than it already is.
 
P

Pierre Asselin

Army1987 said:
Any function can be implemented as a macro, but it ought to be
#define creal(z) (((double _Complex)(z)).re)
as it should have the right type regardless of the type of z.

But then you lose the lvalue-preserving property. It looks like
there is no way to do what Jacob wanted without breaking the
conformance of creal(). Too bad.

Come to think of it, how is it done in Fortran ? The same way
as in C99, I think.
complex z
z= cmplx(new_real_val, imag(z))
z= cmplx(real(z), new_imag_val)

No direct accessors there either. To change one of the components
you have to synthesize a new complex number.
 
U

user923005

But then you lose the lvalue-preserving property.  It looks like
there is no way to do what Jacob wanted without breaking the
conformance of creal().  Too bad.

Come to think of it, how is it done in Fortran ?  The same way
as in C99, I think.
    complex z
    z= cmplx(new_real_val, imag(z))
    z= cmplx(real(z), new_imag_val)

No direct accessors there either.  To change one of the components
you have to synthesize a new complex number.  

Actually, it seems kind of idiotic, but I guess it is to protect us
from the implementation.

It could be implemented (for instance) as:

complex {
double parts[2];
};

or
complex {
double re;
double im;
};

or whatever underneath the covers, since that bit is not specified
clearly.
 
M

Martin Ambuhl

user923005 said:
It could be implemented (for instance) as:

complex {
double parts[2];
};

or
complex {
double re;
double im;
};

or whatever underneath the covers, since that bit is not specified
clearly.

Of course it might be implemented as the standard specifies:
"Each complex type has the same representation and alignment
requirements as an array type containing exactly two elements of the
corresponding real type; the first element is equal to the real part,
and the second element to the imaginary part, of the complex
number."
When you think about that, then I'm sure you will realize that there are
a number of ways to accomplish what you want.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top