Topic: complex question


Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sat, 29 Jan 1994 14:54:07 GMT
Raw View
In article <2hh362$916@ugle.unit.no> jr@efi.sintef.no (Jarand Roeynstrand) writes:
>|>  complex * double
>|>
>|> but there is a major difference now: as part of the Standard Library
>|> the compiler knows all about complex numbers, and can perform
>|> optimal calculations. In particular, the calculations:
>|>
>|>  double r; complex l;
>|>  complex answer = l * r;
>
>Is this correct? I am quite sure that C know nothing about it's standard
>library,

 You're wrong. What you mean is you have a dumb compiler.
My compiler knows about the Standard C library. It inlines
memcpy, for example.

 I'd hazzard a guess that Cray have a C compiler that
knows about numerical things.

>and would expect C++ behave in the same way. In contrast to
>e.g. FORTRAN, where the compiler is required to recognice (sp? this message
>come from a non-english speaking country) the languages standard functions.

 C compilers are "required to recognize" the Standard C library.
They're free to do that by just reading in header files and linking
object code in, just like a user defined library. But they're
not required to use this technique.

>
>It is a strengtyh of a language that the standard functiones may be replaced
>if that is required, but it prevents the use of optimizations as the ones
>mentioned in other parts of your message.

 The standard library components MAY NOT BE REPLACED.
(Unless explicitly specified: in C++ global operator new()
may be replaced by the user provided certain constraints
are met).
If you use your own "malloc", you may or may not have a C compiler
anymore. "malloc" is reserved for the implementor.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA




Author: olsen@verdix.com (David Olsen)
Date: 21 Jan 94 06:45:52 GMT
Raw View
In article <2hh362$916@ugle.unit.no> jr@efi.sintef.no (Jarand Roeynstrand) writes:
>
>I am quite sure that C know nothing about it's standard
>library, and would expect C++ behave in the same way. In contrast to
>e.g. FORTRAN, where the compiler is required to recognize
>the languages standard functions.

In C, the compiler is allowed to know about the stardard library.  The
standard header files do not have to be real files, but can be built
into the compiler.  Very few compilers (at least in the UNIX and DOS
worlds) are built this way, however.  I would expect C++ to behave the
same way.

>It is a strength of a language that the standard functions may be replaced
>if that is required, but it prevents the use of optimizations as the ones
>mentioned in other parts of your message.

It is nice that many C implementations allow replacement of standard
functions, but it is not required.

--
David Olsen
olsen@verdix.com




Author: jr@efi.sintef.no (Jarand Roeynstrand)
Date: 18 Jan 1994 16:36:18 GMT
Raw View
In article <CJnq3H.9LK@ucc.su.OZ.AU>, maxtal@physics.su.OZ.AU (John Max Skaller) writes:
|> In article <vantong.758319307@dutnak2> vantong@dutnak2.tn.tudelft.nl (Bart van Tongeren) writes:
|> >
|> >The complex class in the complex math library that is distributed with
|> >SUN C++ (cfront) is IMO not implemented as it should be. My main
|> >problem is that there are no operators defined for (complex,double)
|> >and (double,complex) operands:
|>
|>
|> >The current implementation will quietly convert any double operands to
|> >temporary complex objects. This leads to an unnecessary performance
|> >loss, even if the subsequent computations would test if the imaginary
|> >part of either operand equals zero.
|>
|>  Complex is now part of the Standard Library. The library
|> does NOT define the extra operations you want such as
|>
|>  complex * double
|>
|> but there is a major difference now: as part of the Standard Library
|> the compiler knows all about complex numbers, and can perform
|> optimal calculations. In particular, the calculations:
|>
|>  double r; complex l;
|>  complex answer = l * r;

Is this correct? I am quite sure that C know nothing about it's standard
library, and would expect C++ behave in the same way. In contrast to
e.g. FORTRAN, where the compiler is required to recognice (sp? this message
come from a non-english speaking country) the languages standard functions.

It is a strengtyh of a language that the standard functiones may be replaced
if that is required, but it prevents the use of optimizations as the ones
mentioned in other parts of your message.

Could some of the gurus confirm this?

|> --
|>         JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
|>  Maxtal Pty Ltd,      CSERVE:10236.1703
|>         6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
|>         NSW 2131, AUSTRALIA

--
 Jarand Roynstrand   Phone:  +47-73 59 72 75 (EFI)
 EFI      +47-73 96 23 55 (Home)
 N-7034 Trondheim
 Norway     email: jr@efi.sintef.no









Author: kanze@us-es.sel.de (James Kanze)
Date: 13 Jan 1994 14:51:24 GMT
Raw View
In article <vantong.758319307@dutnak2> vantong@dutnak2.tn.tudelft.nl
(Bart van Tongeren) writes:

|> The complex class in the complex math library that is distributed with
|> SUN C++ (cfront) is IMO not implemented as it should be. My main
|> problem is that there are no operators defined for (complex,double)
|> and (double,complex) operands:

    [examples deleted...]

|> The current implementation will quietly convert any double operands to
|> temporary complex objects. This leads to an unnecessary performance
|> loss, even if the subsequent computations would test if the imaginary
|> part of either operand equals zero.

Have you verified the generated code.  The simple operators (+, -) are
probably inline, as is the constructor from double.  In this case, I
would expect the compiler to be able to optimize the temporary away.
(I'm not saying that it does, only that the necessary information is
there so that it could.)

|> I thought of defining a derived class dcomplex : public complex
|> to add the desired operators, but the re, im data members are private,
|> and thus not accessible by the derived dcomplex class.

You do not even have to derive.  You can write your own very simply,
ie:
 complex
 operator/( complex const& n , double d )
 {
  return complex( n.real() / d , n.imag() / d ) ;
 }

You don't even have to be a friend.  (Note that complex::real() and
complex::imag() are inline functions.)

|> Why was this complex library not designed more carefully? It is not
|> that much work, but very important for numerical applications. Or do I
|> overlook some reason why it is the way it is?

|> It's fine with me if complex is not going to be a build-in type (as it
|> might be in the second ANSI-C standard), but will these topics be
|> straightened out in the first ANSI C++ Standard?

It would seem to me that this is more a quality of implementation
issue than a standards issue.
--
James Kanze                             email: kanze@us-es.sel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                   -- Beratung in industrieller Datenverarbeitung




Author: vantong@dutnak2.tn.tudelft.nl (Bart van Tongeren)
Date: Wed, 19 Jan 1994 10:29:39 GMT
Raw View
In <KANZE.94Jan13155124@slsvhdt.us-es.sel.de> kanze@us-es.sel.de (James Kanze) writes:

[]In article <vantong.758319307@dutnak2> vantong@dutnak2.tn.tudelft.nl
[](Bart van Tongeren) writes:

[]|> The current implementation will quietly convert any double operands to
[]|> temporary complex objects. This leads to an unnecessary performance
[]|> loss, even if the subsequent computations would test if the imaginary
[]|> part of either operand equals zero.

[]Have you verified the generated code.  The simple operators (+, -) are
[]probably inline, as is the constructor from double.  In this case, I
[]would expect the compiler to be able to optimize the temporary away.
[](I'm not saying that it does, only that the necessary information is
[]there so that it could.)

The + and - ops and the constructor form double are defined inline, but
the double=>complex conversion is not optimzed away. This could be done
by a better compiler, which i don't have. The problem is more difficult
for the * and - operators. The (complex,complex) version of operator /
is too large too inline. In this case the compiler can not generate
optimal code for complex/double.

[]|> I thought of defining a derived class dcomplex : public complex
[]|> to add the desired operators, but the re, im data members are private,
[]|> and thus not accessible by the derived dcomplex class.

[]You do not even have to derive.  You can write your own very simply,
[]ie:
[] complex
[] operator/( complex const& n , double d )
[] {
[]  return complex( n.real() / d , n.imag() / d ) ;
[] }

[]You don't even have to be a friend.  (Note that complex::real() and
[]complex::imag() are inline functions.)

This is what i tried first. It is not good enough. Even if the compiler
could always inline this, it is not possible to write portable code.
How do I know if I have too provide this inline definitions. Some
compilers already have them, others don't. This needs standardization.

Apart from this, I also want complex::operator /= (double) etc, which
must be members of complex.

There are additional problems if you try (for example) to define a
float precision class fcomplex. Of course you will define fcomplex <=>
complex conversions.  But now there is a problem when you write:

 #include <complex.h>
 class fcomplex {
  float re, im;
 public: fcomplex() {}
  fcomplex(float r, float i=0): re(r), im(i) {}
  fcomplex(const complex& c): re(real(c)), im(imag(c)) {}
  operator complex() const { return complex(re,im); }
  fcomplex operator += (const fcomplex&);
  fcomplex operator += (double);
  // ... etc for - * / operators ...
 };
 fcomplex operator + (const fcomplex&, const fcomplex&);
 fcomplex operator + (const fcomplex&, double);
 fcomplex operator + (double, const fcomplex&);

 complex complextest() {
  complex c = 1;
  double d = 1;
  return d + c;   // ambiguous??
 }

This complextest will only succeed if operator+(double, const complex&)
is defined in <complex.h>. If not, then `d+c' is ambiguous:
 complex(d)+c or d+fcomplex(c) ??

I'm sure you can find many problems like this when the class complex
and its related operators is not properly standardized.

Finally I don't like arguments like "a smart compiler can optimize this
and that away". Many compilers just don't do it. And don't _have_ to do
it when the standard requires a complete set of operators.
One of the reasons I do C++ is performance, you know.

Bart.

--
* Bart van Tongeren ----- Delft University of Technology, Netherlands *
| -------------------- Applied Physics Department, Spin Imaging Group |
| email tong@si.tn.tudelft.nl  voice +31-15-784059  fax +31-15-624978 |
*---------------------------------------------------------------------*
--
* Bart van Tongeren ----- Delft University of Technology, Netherlands *
| -------------------- Applied Physics Department, Spin Imaging Group |
| email tong@si.tn.tudelft.nl  voice +31-15-784059  fax +31-15-624978 |
*---------------------------------------------------------------------*




Author: fmarin@conicit.ve (Felix Marin (UCV))
Date: Wed, 19 Jan 1994 02:17:29 GMT
Raw View
Bart van Tongeren (vantong@dutnak2.tn.tudelft.nl) wrote:

: In article 9LK@ucc.su.OZ.AU, maxtal@physics.su.OZ.AU (John Max Skaller) writes:
: |In article <vantong.758319307@dutnak2> vantong@dutnak2.tn.tudelft.nl (Bart van Tongeren) writes:
: |>
: |>The complex class in the complex math library that is distributed with
: |>SUN C++ (cfront) is IMO not implemented as it should be. My main
: |>problem is that there are no operators defined for (complex,double)
: |>and (double,complex) operands:
: |
: |
: |>The current implementation will quietly convert any double operands to
: |>temporary complex objects. This leads to an unnecessary performance
: |>loss, even if the subsequent computations would test if the imaginary
: |>part of either operand equals zero.
: |
: | Complex is now part of the Standard Library. The library
: |does NOT define the extra operations you want such as
: |
: | complex * double
: |
: |but there is a major difference now: as part of the Standard Library the
: |compiler knows all about complex numbers, and can perform optimal calculations.

: This is interesting. But I wonder what the advantages of this approach are
: compared to just defining the (complex,double) and (double,complex) operators.
: I spend some time to create my own dcomplex class, which does define these ops.
: It also provides conversions to/from class complex. Looks like this:

: class dcomplex
: {
:  double re, im;
: public:
:  dcomplex() {}
:  dcomplex(double r, double i = 0) : re(r), im(i) {}
:  dcomplex(const complex& c) : re(real(c)), im(imag(c)) {}
:  operator complex() const { return complex(re, im); }

:  dcomplex  operator - () const;
:  dcomplex  operator + () const;

: friend dcomplex  operator *  (const dcomplex& lhs, const dcomplex& rhs);
:  dcomplex& operator *= (const dcomplex& rhs);
:  dcomplex& operator *= (double rhs);
:  // etc for + - / versions
: };

: Careful coding and inlining (and avoiding ambiguities with class complex)
: of all operators requires some thought, but the results are well worth it:
:  #include <dcomplex.h>
:  dcomplex dc(1, 1);
:  double  d = 1.000001;
:  for (int i = 0 ; i < 1000000; i++) // 2 Mflops
:   dc *= d;
: This program takes 0.9 s on my Sparcstation1 (2Mflop), which indicates
: an optimal implementation. The same program using cfront's <complex.h>
: took at least 6.7 s, that is over 7 times slower!! It is a real Mflop
: destroyer :), ... , :(
: What might also interest you, is that the equivalent FORTRAN77 program,
: took 3.8 s, also 4 times slower than the well optimized C++ dcomplex!!
: (And of course I did use the right compiler options everywhere.)

: |In particular, the calculations:
: |
: | double r; complex l;
: | complex answer = l * r;
: |
: |require a conversion from double to complex to perform the
: |multiply, but the conversion can be optimised away and the operation
: |
: | complex * double
: |
: |performed directly because complex is now, for optimisation
: |purposes, treated just like a built in type. It is, in fact,
: |a built in type, that just happens to work like a class
: |as well. In particular, while existing implementations
: |are constrained to perform the operation above like:
: |
: | complex (*mulcd)(complex, complex)=&operator*(complex, complex);
: | complex answer = mulcd(l, complex(r));
: |
: |now such constraint exists for the standard library, since the
: |exact semantics are known to the compiler (the compiler being
: |able to read the Standard :-)

: Not necessarily if operator*(complex, double) is required to be defined as:
:  inline complex& complex::operator *= (double rhs) {
:   re *= rhs;
:   im *= rhs;
:   return *this;
:  }
: Now there is no double to complex conversion required.

: |>It's fine with me if complex is not going to be a build-in type (as it
: |>might be in the second ANSI-C standard), but will these topics be
: |>straightened out in the first ANSI C++ Standard?
: |
: | ISO/ANSI C++ will specify complex as a built-in type
: |described as a class. Its already in the Working Papers,
: |expect vendors supplying numerical markets to begin to ship
: |compilers with optimising support.
: |
: | Dont expect too much from Cfront: it is a bootstrapping
: |implementation whose prime aim is portability. High speed
: |native code compilers which have optimising support for the
: |Standard Library and actually work <grin> will emerge:
: |the PC market already has pre-cursors of this sort of product shipping.
: |(Despite architectural limitations of PCs)

: Cfront can be significantly improved by just supplying the complete
: set of operators. Time == money.

:                                - = * = -
: * Bart van Tongeren                                      Lorentzweg 1 *
: | Technical University of Delft                         2628 CJ Delft |
: | Applied Physics Department, Spin Imaging Group      The Netherlands |
: *---------------------------------------------------------------------*
: | email tong@si.tn.tudelft.nl  voice +31-15-784059  fax +31-15-624978 |
: *---------------------------------------------------------------------*


This is a personal comment. F. P. MARIN. e-mail: fmarin@dino.conicit.ve

Also, BORLANDC ++ does not implement the return by reference in real and
imag functions they have. So, we can not do something like:

real(z)=9.99;
imag(z)=0.9;

For this reason I create my own complex class. I overload ~ to manage the
complex conjugated:

conjugated_z=~z;

That is closer to the line above z we use in writing and it is easier to
use that conj function. Also, for this code it sets a warning:

complex z=9.0;
z/=8.99;

instead of performing " quietly " the 8.99 --> complex conversion. The /
operator is not precise enough so I implement another and popular one
which avoid over and under ( flows ).

This is a personal comment. F. P. MARIN. e-mail: fmarin@dino.conicit.ve




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sat, 15 Jan 1994 06:02:05 GMT
Raw View
In article <vantong.758319307@dutnak2> vantong@dutnak2.tn.tudelft.nl (Bart van Tongeren) writes:
>
>The complex class in the complex math library that is distributed with
>SUN C++ (cfront) is IMO not implemented as it should be. My main
>problem is that there are no operators defined for (complex,double)
>and (double,complex) operands:


>The current implementation will quietly convert any double operands to
>temporary complex objects. This leads to an unnecessary performance
>loss, even if the subsequent computations would test if the imaginary
>part of either operand equals zero.

 Complex is now part of the Standard Library. The library
does NOT define the extra operations you want such as

 complex * double

but there is a major difference now: as part of the Standard Library
the compiler knows all about complex numbers, and can perform
optimal calculations. In particular, the calculations:

 double r; complex l;
 complex answer = l * r;

require a conversion from double to complex to perform the
multiply, but the conversion can be optimised away and the operation

 complex * double

performed directly because complex is now, for optimisation
purposes, treated just like a built in type. It is, in fact,
a built in type, that just happens to work like a class
as well. In particular, while existing implementations
are constrained to perform the operation above like:

 complex (*mulcd)(complex, complex)=&operator*(complex, complex);
 complex answer = mulcd(l, complex(r));

now such constraint exists for the standard library, since the
exact semantics are known to the compiler (the compiler being
able to read the Standard :-)

>It's fine with me if complex is not going to be a build-in type (as it
>might be in the second ANSI-C standard), but will these topics be
>straightened out in the first ANSI C++ Standard?

 ISO/ANSI C++ will specify complex as a built-in type
described as a class. Its already in the Working Papers,
expect vendors supplying numerical markets to begin to ship
compilers with optimising support.

 Dont expect too much from Cfront: it is a bootstrapping
implementation whose prime aim is portability. High speed
native code compilers which have optimising support for the
Standard Library and actually work <grin> will emerge:
the PC market already has pre-cursors of this sort of product shipping.
(Despite architectural limitations of PCs)

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA




Author: vantong@dutnak2.tn.tudelft.nl (Bart van Tongeren)
Date: Mon, 17 Jan 1994 16:42:45 GMT
Raw View
In article 9LK@ucc.su.OZ.AU, maxtal@physics.su.OZ.AU (John Max Skaller) writes:
|In article <vantong.758319307@dutnak2> vantong@dutnak2.tn.tudelft.nl (Bart van Tongeren) writes:
|>
|>The complex class in the complex math library that is distributed with
|>SUN C++ (cfront) is IMO not implemented as it should be. My main
|>problem is that there are no operators defined for (complex,double)
|>and (double,complex) operands:
|
|
|>The current implementation will quietly convert any double operands to
|>temporary complex objects. This leads to an unnecessary performance
|>loss, even if the subsequent computations would test if the imaginary
|>part of either operand equals zero.
|
| Complex is now part of the Standard Library. The library
|does NOT define the extra operations you want such as
|
| complex * double
|
|but there is a major difference now: as part of the Standard Library the
|compiler knows all about complex numbers, and can perform optimal calculations.

This is interesting. But I wonder what the advantages of this approach are
compared to just defining the (complex,double) and (double,complex) operators.
I spend some time to create my own dcomplex class, which does define these ops.
It also provides conversions to/from class complex. Looks like this:

class dcomplex
{
 double re, im;
public:
 dcomplex() {}
 dcomplex(double r, double i = 0) : re(r), im(i) {}
 dcomplex(const complex& c) : re(real(c)), im(imag(c)) {}
 operator complex() const { return complex(re, im); }

 dcomplex  operator - () const;
 dcomplex  operator + () const;

friend dcomplex  operator *  (const dcomplex& lhs, const dcomplex& rhs);
 dcomplex& operator *= (const dcomplex& rhs);
 dcomplex& operator *= (double rhs);
 // etc for + - / versions
};

Careful coding and inlining (and avoiding ambiguities with class complex)
of all operators requires some thought, but the results are well worth it:
 #include <dcomplex.h>
 dcomplex dc(1, 1);
 double  d = 1.000001;
 for (int i = 0 ; i < 1000000; i++) // 2 Mflops
  dc *= d;
This program takes 0.9 s on my Sparcstation1 (2Mflop), which indicates
an optimal implementation. The same program using cfront's <complex.h>
took at least 6.7 s, that is over 7 times slower!! It is a real Mflop
destroyer :), ... , :(
What might also interest you, is that the equivalent FORTRAN77 program,
took 3.8 s, also 4 times slower than the well optimized C++ dcomplex!!
(And of course I did use the right compiler options everywhere.)

|In particular, the calculations:
|
| double r; complex l;
| complex answer = l * r;
|
|require a conversion from double to complex to perform the
|multiply, but the conversion can be optimised away and the operation
|
| complex * double
|
|performed directly because complex is now, for optimisation
|purposes, treated just like a built in type. It is, in fact,
|a built in type, that just happens to work like a class
|as well. In particular, while existing implementations
|are constrained to perform the operation above like:
|
| complex (*mulcd)(complex, complex)=&operator*(complex, complex);
| complex answer = mulcd(l, complex(r));
|
|now such constraint exists for the standard library, since the
|exact semantics are known to the compiler (the compiler being
|able to read the Standard :-)

Not necessarily if operator*(complex, double) is required to be defined as:
 inline complex& complex::operator *= (double rhs) {
  re *= rhs;
  im *= rhs;
  return *this;
 }
Now there is no double to complex conversion required.

|>It's fine with me if complex is not going to be a build-in type (as it
|>might be in the second ANSI-C standard), but will these topics be
|>straightened out in the first ANSI C++ Standard?
|
| ISO/ANSI C++ will specify complex as a built-in type
|described as a class. Its already in the Working Papers,
|expect vendors supplying numerical markets to begin to ship
|compilers with optimising support.
|
| Dont expect too much from Cfront: it is a bootstrapping
|implementation whose prime aim is portability. High speed
|native code compilers which have optimising support for the
|Standard Library and actually work <grin> will emerge:
|the PC market already has pre-cursors of this sort of product shipping.
|(Despite architectural limitations of PCs)

Cfront can be significantly improved by just supplying the complete
set of operators. Time == money.

                               - = * = -
* Bart van Tongeren                                      Lorentzweg 1 *
| Technical University of Delft                         2628 CJ Delft |
| Applied Physics Department, Spin Imaging Group      The Netherlands |
*---------------------------------------------------------------------*
| email tong@si.tn.tudelft.nl  voice +31-15-784059  fax +31-15-624978 |
*---------------------------------------------------------------------*




Author: vantong@dutnak2.tn.tudelft.nl (Bart van Tongeren)
Date: Tue, 11 Jan 1994 20:15:07 GMT
Raw View
The complex class in the complex math library that is distributed with
SUN C++ (cfront) is IMO not implemented as it should be. My main
problem is that there are no operators defined for (complex,double)
and (double,complex) operands:

How it is:

class complex
{
 double re, im;
public:
 complex() { re=0.0; im=0.0; }
 complex(double r, double i = 0.0) { re=r; im=i; }

 friend double real(const complex&);
 friend double imag(const complex&);

 // ...

 friend complex operator+(complex, complex);
 friend complex operator-(complex, complex);
 friend complex operator*(complex, complex);
 friend  complex operator/(complex, complex);

 void operator+=(complex);
 void operator-=(complex);
 void operator*=(complex);
 void operator/=(complex);
};

How I think it should be:

class complex
{
 double re, im;
public:
 complex()   { /* no initialization to zero */ }
 complex(double r, double i = 0.0) { re=r; im=i; }

 friend double real(const complex&) const;
 friend double imag(const complex&) const;

 // ...

 friend complex operator+(complex, complex);
 friend complex operator+(complex, double);
 friend complex operator+(double, complex);
 friend complex operator-(complex, complex);
 friend complex operator-(complex, double);
 friend complex operator-(double, complex);
 friend complex operator*(complex, complex);
 friend complex operator*(complex, double);
 friend complex operator*(double, complex);
 friend complex operator/(complex, complex);
 friend complex operator/(complex, double);
 friend complex operator/(double, complex);

 void operator+=(complex);
 void operator+=(double);
 void operator-=(complex);
 void operator-=(double);
 void operator*=(complex);
 void operator*=(double);
 void operator/=(complex);
 void operator/=(double);
};

The current implementation will quietly convert any double operands to
temporary complex objects. This leads to an unnecessary performance
loss, even if the subsequent computations would test if the imaginary
part of either operand equals zero.

Another annoyance is that Cfront's class complex is not const-correct.

I thought of defining a derived class dcomplex : public complex
to add the desired operators, but the re, im data members are private,
and thus not accessible by the derived dcomplex class.

It seems that the only way to do it is to define a (seperate) class
dcomplex.  This class can implement all desired operators.
It should also have conversions to/from class complex, using
dcomplex::dcomplex(const complex&) and dcomplex::operator complex().

Why was this complex library not designed more carefully? It is not
that much work, but very important for numerical applications. Or do I
overlook some reason why it is the way it is?

It's fine with me if complex is not going to be a build-in type (as it
might be in the second ANSI-C standard), but will these topics be
straightened out in the first ANSI C++ Standard?

                               - = * = -
|\/\/\/|       ______________________________________________________
|      |      / Bart van Tongeren                      Lorentzweg 1  \
| (o)(o)     / Technical University of Delft           2628 CJ  Delft \
@     _)  __/ Applied Physics, Spin Imaging Group      The Netherlands \
 | ,___| /__                                                           /
 |   /      \ tong@si.tn.tudelft.nl  voice +31-15-784059  fax +624978 /
/____\       \_______________________________________________________/