C++ complex matters arising
The Good News
C++'s complex
class greatly simplifies the use of complex
numbers and is well integrated into other parts of the standard library.
Once complex numbers are created they can be used in most situations
much as simple integers can.
The type of the real and imaginary parts is under user control and makes use
of template notation. Here's a little example
#include <iostream> #include <complex> using namespace std; int main() { complex<double> c1(0.0,1.0), c2; // complex numbers with double components c2=pow(c1,2.0); cout << "The square of " << c1 << " is " << c2 << endl; }
Run this and you'll see that i squared just about equals -1. So far so good. Let's try to assign values to these complex numbers. How about
c2=2;
No problem - printing c2
out gives (2,0)
which is fair enough.
The Bad News
Using <complex>
isn't quite as simple as it first looks, and
even the 3rd edition of Deitel & Deitel's book doesn't mention it.
There are some traps for the unwary that aren't all specific to complex
numbers but users are likely to meet them first in this context.
Assignment
Suppose you try to set a complex number using
c2=(3,7);
This is legal, but printing c2
out gives (7,0)
.
Surprized? Were you expecting (3,7)
? In fact,
c2=(3,7)
is equivalent to c2=3,7
. C++'s ",
" operator suppresses the value of the first operand in favour of the second, so c2=3,7
is equivalent to c2=7
.
However, you can input a complex number as "(3,7)
" when
reading from a file - for example with the following code
... complex<double> c1; // complex numbers with double components cout << "Type in a complex number: "; cin >> c1; cout << "You typed " << c1 << endl; ...
Mixing types
There's unexpected behaviour (with my compiler anyway) when mixing types. The following compiles
#include <complex> using namespace std; int main() { complex<int> c_int(2,3); c_int= c_int*2; }
but this doesn't
#include <complex> using namespace std; int main() { complex<double> c_double(2,3); c_double= c_double*2; }
though this does
#include <complex> using namespace std; int main() { complex<double> c_double(2,3); complex<int> c_int(2,3); c_double*=2; c_double=c_int; }
Also there are differences between what's allowed by constructors and assignments as illustrated by this code (from Stroustrup's errata to his 6th edition).
#include <complex> using namespace std; void f(complex< float> cf, complex< double> cd, complex< long double> cld, complex< int> ci){ complex<double> c1 = cf; // fine complex<double> c2 = cd; // fine complex<double> c3 = cld; // error: possible truncation complex<double> c4(cld); // ok: explicit conversion complex<double> c5 = ci; // error: no conversion c1 = cld; // ok, but beware: possible truncation c1 = cf; // ok c1 = ci; // ok } int main() { complex<int> c_int; complex<float> c_float; complex<double> c_double; complex<long double> c_longdouble; f(c_float, c_double, c_longdouble, c_int ); }
According to Matt Austern "The C++ Standard, section 26.2, paragraph 2, says 'The effect of instantiating the template complex for any type other than float, double, or long double is unspecified.'" which explains some of the above problems.
>>
If you want to create a list of integers, you just do
list<int> L;
but if you try to create a list of complex numbers with
list<complex<int>> L;
the compiler will moan. The problem is that it treats >>
as the bit-shift operator - you need to add a space between the >
characters.