Complex Numbers¶
Math makes folks uncomfortable! Well, trust me, you will wish you had paid more attention in your math classes the more you stay with Computer Science.
Let’s explore Complex Numbers and see how to set them up in C++. In doing this we will see how to extend your classes so you can use the normal mathematical operators to combine them (assuming that makes sense!).
Square Root of -1¶
You were probably told you cannot take the square root of a negative number. You can, it just produces something called an imaginary number:
A complex number is made up of a “real” part, and an “imaginary” part:
We use the “i” to indicate the “imaginary” part. The first part is the “real” part.
Subtraction¶
Subtraction works the same way:
The usual rules apply if you get a negative number for the imaginary part!
Multiplication¶
Multiplication is a bit tougher, because we have to consider two cases:
Remember that ii = -1
This simplifies to :
There is another form of multiplication to consider. When we multiply a complex number by a scalar (constant) we get this:
Division¶
This one gets messy!
First, let’s deal with “i” in the denominator:
With that out of the way, let’s try to figure out division of complex numbers:
What are we going to do with this?
Complex Conjugates¶
Before we get to that, let’s look at something called a “complex conjugate” of a complex number.
The complex conjugate of a complex number is identical to that number with the sign on the imaginary part reversed. Showing the complex conjugate in math books is often done by placing a bar over the number:
What makes this useful is this:
Well, if we multiply the top and bottom by the “complex conjugate” of the denominator, we get something interesting:
Finally, dividing a complex number by a constant is simple:
Now we have enough math to develop a complex number class.
C++ Complex Class¶
Obviously, our complex number class needs two attributes, and several methods. We will start off with the basic constructors:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // Complex.h - complex number class
#include <iostream>
using namespace std;
class Complex {
private:
double r; // real part
double i; // imaginary part
public:
Complex(); // default constructor
Complex( double r, double i ); // normal constructor
Complex( double r ); // alternate constructor
Complex operator * ( const Complex & rhs );
friend Complex operator + ( double lhs, const Complex & rhs );
|
Displaying Complex Numbers¶
In order to make displaying complex numbers simple, we need to build a routine
that lets us use the normal C++ output operator: <<
. This operator is
actually used by output “stream” objects (remember that iostream
you include in
your code?).
Friend Functions¶
To create a function that will let us display complex numbers we need to use a
special kind of function called a friend
. Friend functions are declared
inside a class, but they are “global”, meaning they can be called anywhere. In
the case of operators, C++ looks at the two objects on either side of the
operator and looks for a method with operands that match the types it finds.
Friend methods have full access to all of the private data in the class.
Here is the prototype for the friend function we need. This method needs to be
a public
method in our Complex
class:
friend ostream & operator << ( ostream & lhs, const Complex & rhs );
The pattern of this method is something we will see again. The name of the
method is those funny “<<” characters. The “operator” in front of that tells
the compiler what you are doing. We send two parameters to this method, The
lhs
is the object in the left side of the operator. In our case, that will
be the “stream” we want to send our object to. The rhs
parameter needs to
be marked as const
, which tells the compiler not to mess with it. That object
will be made available inside the method, where we can inspect it, and figure
out what to do to display that object.
Basically this operator looks like this in action:
cout << complex_number
or
lhs << rhs;
In this example, the operator function is being called between an ostream
object and a Complex
object. These two objects are passed as parameters to
our friend
function. In this example, the lhs
is an ostream
object
(cout
), and the rhs
object is our complex number.
Here is the implementation of our class so far:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <iostream>
#include <sstream>
using namespace std;
#include "Complex.h"
// constructors -------------------------------------------
Complex::Complex() {
r = 0;
i = 0;
}
Complex::Complex( double r, double i ) {
this->r = r;
this->i = i;
}
Complex::Complex( double r ) {
this->r = r;
i = 0;
}
// accessors ----------------------------------------------
string Complex::toString( void ) {
ostringstream tmp;
tmp << r << "+" << i << "i";
return temp;
}
Complex Complex::operator / ( const Complex & rhs ) {
Complex temp;
|
Completing this class for the missing methods should be fairly simple. Here is my test code:
#include <iostream>
#include "Complex.h"
using namespace std;
int main( int argc, char * argv[] ) {
Complex a;
Complex b(2.0);
Complex c(3,5);
cout << a << ' ' << b << ' ' << b + c << ' ' << c << endl;
cout << a + 1.5 << ' ' << 2.5 + b << ' ' << b - c << ' ' << c << endl;
}
You should test your code using example problems you can find on the Internet!