Clément Lavoillotte
personal page
Clement's web pages
A complex number class in C++
Une classe pour représenter les nombres complexes en C++.
Yet another complex number class in C++
Here is an atempt to provide a simple and correct complex class in C++. It's a bit more complete than the standart std::complex<double> class on the operator side, but not for the provided functions.
It provides operators +, -, /, *, = (and their compounds) ++, --, !=, <, >, <= and >= so that you can write things like
Complex a = -5 * J + 1.34;
It also provides I/O operators >> and <<, with several syntaxes:
-7.2+5.4i
.5 - 1e2J (= 0.5-100i)
1 + -1 i (= 1-1i)
Compile with gcc4, gcc4-apple and MSVS 2005.
Content of complex.h file:
#ifndef CPX_COMPLEX_H
#define CPX_COMPLEX_H 1
#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>
namespace cpx {
// Complex number class
class Complex
{
public:
// Constructors
Complex();
Complex( double );
Complex( double, double );
Complex( const Complex& );
// Destructor
~Complex();
// Selectors
double real() const;
double imag() const;
// Modifiers
void set( double, double );
// Operator overloads
// assignment & arithmetic-assignment operators
Complex& Complex::operator=( const Complex& );
Complex& Complex::operator=( const double& );
Complex& Complex::operator+=( const Complex& );
Complex& Complex::operator+=( const double& );
Complex& Complex::operator-=( const Complex& );
Complex& Complex::operator-=( const double& );
Complex& Complex::operator*=( const Complex& );
Complex& Complex::operator*=( const double& );
Complex& Complex::operator/=( const Complex& );
Complex& Complex::operator/=( const double& );
// increment & decrement operators (adds/remove 1 to/from the real part)
Complex& operator++(); // prefix ++ returns a reference
Complex operator++( int ); // postfix ++ returns a value
Complex& operator--();
Complex operator--( int );
// stream operators are our friends
friend std::ostream& operator <<(std::ostream &, const Complex &);
friend std::istream& operator >>(std::istream &, Complex &);
private:
// Member variables
double re; // real part
double im; // imaginary part
};
// Nonmember operators (to allow implicit conversion of the left operand)
// Note: doubles are considered as complex with no imaginary part
Complex operator+( const Complex&, const Complex& );
Complex operator+( const Complex&, const double& );
Complex operator+( const double&, const Complex& );
Complex operator+( const Complex& ); // unary + operator
Complex operator-( const Complex&, const Complex& );
Complex operator-( const Complex&, const double& );
Complex operator-( const double&, const Complex& );
Complex operator-( const Complex& ); // unary - operator
Complex operator*( const Complex&, const Complex& );
Complex operator*( const Complex&, const double& );
Complex operator*( const double&, const Complex& );
//Division operator returns + or - infinity if the right operand is zero
Complex operator/( const Complex&, const Complex& );
Complex operator/( const Complex&, const double& );
Complex operator/( const double&, const Complex& );
bool operator==( const Complex&, const Complex& );
bool operator==( const Complex&, const double& );
bool operator==( const double&, const Complex& );
bool operator!=( const Complex&, const Complex& );
bool operator!=( const Complex&, const double& );
bool operator!=( const double&, const Complex& );
// Comparison between complex are actually comparison of their module (inline function abs beloz)
bool operator<( const Complex&, const Complex& );
bool operator>( const Complex&, const Complex& );
bool operator<=( const Complex&, const Complex& );
bool operator>=( const Complex&, const Complex& );
// Other non-mermber function
// real(c) is more natural than c.real() for some people, so we provide both
inline double real( const Complex& c ) {
return c.real();
}
inline double imag( const Complex& c ) {
return c.imag();
}
// Imaginary units defined in complex.cpp
extern const Complex I;
extern const Complex& J; // J is an alias for I
} // end namespace cpx
namespace std {
// overload of the std::abs function for complex
inline double abs( const cpx::Complex& c ) {
return sqrt( c.real() * c.real() + c.imag() * c.imag() );
}
}
#endif
Content of the complex.cpp file :
#include "complex.h"
using namespace std;
namespace {
// Used to compare 2 values of type double
// Two double are considered as "equals" if their difference is significantly
// smaller than themselves.
// Derived from FAQ C++ Lite, http://www.parashift.com/c++-faq-lite/ section 29.17
// see "The Art of Computer Programming", by Donald E. Knuth, section 4.2.2 pages 217-218
inline bool is_equal( const double& x, const double& y )
{
static const double epsilon = numeric_limits<double>::epsilon();
const double diff = abs( x - y );
return ( diff <= epsilon * abs(x) || diff <= epsilon * abs(y) );
// we have to take <= and not < in case difference x and y are both 0
}
const double infinity = numeric_limits<double>::infinity();
}
namespace cpx {
Complex::Complex()
{
}
Complex::Complex( double re )
{
this->re = re;
this->im = 0;
}
Complex::Complex( double re, double im )
{
this->re = re;
this->im = im;
}
Complex::~Complex()
{
}
Complex::Complex( const Complex& c )
{
re = c.re;
im = c.im;
}
double Complex::real() const
{
return re;
}
double Complex::imag() const
{
return im;
}
void Complex::set( double real, double imaginary )
{
re = real;
im = imaginary;
}
Complex& Complex::operator=( const Complex& c )
{
if (this == &c) return *this;
re = c.re;
im = c.im;
return (*this);
}
Complex& Complex::operator=( const double& d )
{
re = d;
im = 0;
return (*this);
}
Complex& Complex::operator+=( const Complex& c )
{
re += c.re;
im += c.im;
return (*this);
}
Complex& Complex::operator+=( const double& d )
{
re += d;
return (*this);
}
Complex& Complex::operator-=( const Complex& c )
{
re -= c.re;
im -= c.im;
return (*this);
}
Complex& Complex::operator-=( const double& d )
{
re -= d;
return (*this);
}
Complex& Complex::operator*=( const Complex& c )
{
double re2 = re; // backup re, as we're going to modify it
double cre2 = re; // backup c.re too, in case c *= c;
re = re * c.re - im * c.im;
im = re2 * c.im + im * cre2;
return (*this);
}
Complex& Complex::operator*=( const double& d )
{
re *= d; // same as above with c.im = 0 and c.re = d
im *= d; // logically and happily simplified
return (*this);
}
Complex& Complex::operator/=( const Complex& c )
{
if (this == &c) { // c /= c;
re = 1;
im = 0;
}
else if (c == 0) {
re = (re < 0) ? -infinity : infinity;
im = (im < 0) ? -infinity : infinity;
}
else {
double re2 = re; // backup re, as we're going to modify it
// no need to backup c.re here
re = ( re * c.re + im * c.im ) / ( c.re * c.re + c.im * c.im );
im = ( im * c.re - re2 * c.im ) / ( c.re * c.re + c.im * c.im );
}
return (*this);
}
Complex& Complex::operator/=( const double& d )
{
if( is_equal(d, 0) ) {
re = (re < 0) ? -infinity : infinity;
im = (im < 0) ? -infinity : infinity;
}
re /= d;
im /= d;
return (*this);
}
Complex& Complex::operator++()
{
++re;
return (*this);
}
Complex Complex::operator++( int )
{
Complex tmp (*this);
++( *this );
return tmp;
}
Complex& Complex::operator--() {
--re;
return (*this);
}
Complex Complex::operator--( int )
{
Complex tmp (*this);
--( *this );
return tmp;
}
// Prints out a complex with the form a+bi or a-bi or 0
ostream& operator<<( ostream& s, const Complex& c )
{
s << c.re << setiosflags( ios::showpos );
if( c.im != 0 ) {
s << c.im << "i";
}
s << resetiosflags ( ios::showpos );
return s;
}
// Reads a complex number c into the input stream s.
// c has to be the form: number + ('+' or '-') + number + ('i' or 'j' or 'I' or 'J')
// spaces can be used between the elements, but not inside an element ("- 7+2i" is incorrect)
// ex: valid: 1.2+5i ; 1e2-.5J (= 100-0.5i) ; -4 + -8 i (= -4-8i)
// invalid : - 7+5J (space inside the first number) ; 7i-4 (order)
// If bad input is encountered, s.setstate(ios::failbit) is called.
istream& operator>>( istream& s, Complex& c )
{
char op, ij;
if( !( (s >> c.re >> op >> c.im >> ij)
&& (op == '+' || op == '-')
&& (ij == 'i' || ij == 'I' || ij == 'j' || ij == 'J') ) )
{
s.setstate( ios::failbit );
}
else if( op == '-' && c.im != 0 ) {
c.im *= -1;
}
return s;
}
Complex operator+( const Complex& lhs, const Complex& rhs ) {
return Complex( real(lhs) + real(rhs) , imag(lhs) + imag(rhs) );
}
Complex operator+( const Complex& lhs, const double& rhs ) {
return Complex( real(lhs) + rhs , imag(lhs) );
}
Complex operator+( const double& lhs, const Complex& rhs ) {
return Complex( lhs + real(rhs) , imag(rhs) );
}
Complex operator+( const Complex& lhs ) {
return Complex( lhs );
}
Complex operator-( const Complex& lhs, const Complex& rhs ) {
return Complex( real(lhs) - real(rhs) , imag(lhs) - imag(rhs) );
}
Complex operator-( const Complex& lhs, const double& rhs ) {
return Complex( real(lhs) - rhs , imag(lhs) );
}
Complex operator-( const double& lhs, const Complex& rhs ) {
return Complex( lhs - real(rhs) , - imag(rhs) );
}
Complex operator-( const Complex& c ) {
return Complex( - real(c) , - imag(c) );
}
Complex operator*( const Complex& lhs, const Complex& rhs ) {
return Complex(
real(lhs) * real(rhs) - imag(lhs) * imag(rhs),
real(lhs) * imag(rhs) + imag(lhs) * real(rhs)
);
}
Complex operator*( const Complex& lhs, const double& rhs ) {
return Complex( real(lhs) * rhs, imag(lhs) * rhs );
}
Complex operator*( const double& lhs, const Complex& rhs ) {
return Complex( lhs * real(rhs), lhs * imag(rhs) );
}
// Division operator returns + or - infinity if the right operand is zero
Complex operator/( const Complex& lhs, const Complex& rhs ) {
if( rhs == 0 )
return Complex(
( real(lhs) < 0 ) ? -infinity : infinity,
( imag(lhs) < 0 ) ? -infinity : infinity
);
else return Complex(
( real(lhs) * real(rhs) + imag(lhs) * imag(rhs) ) / ( real(rhs) * real(rhs) + imag(rhs) * imag(rhs) ),
( imag(lhs) * real(rhs) - real(lhs) * imag(rhs) ) / ( real(rhs) * real(rhs) + imag(rhs) * imag(rhs) )
);
}
Complex operator/( const Complex& lhs, const double& rhs ) {
if( is_equal(rhs, 0) )
return Complex(
( lhs < 0 ) ? -infinity : infinity,
infinity
);
else return Complex(
( real(lhs) * rhs ) / ( rhs * rhs ),
( imag(lhs) * rhs ) / ( rhs * rhs )
);
}
Complex operator/( const double& lhs, const Complex& rhs ) {
if( rhs == 0 )
return Complex(
( real(lhs) < 0 ) ? -infinity : infinity,
( imag(lhs) < 0 ) ? -infinity : infinity
);
else return Complex(
( lhs * real(rhs) ) / ( real(rhs) * real(rhs) + imag(rhs) * imag(rhs) ),
( - lhs * imag(rhs) ) / ( real(rhs) * real(rhs) + imag(rhs) * imag(rhs) )
);
}
bool operator==( const Complex& lhs, const Complex& rhs ) {
return ( is_equal( real(lhs), real(rhs) ) && is_equal( imag(lhs), imag(rhs) ) );
}
bool operator==( const Complex& lhs, const double& rhs ) {
return ( is_equal( real(lhs), rhs ) && is_equal( imag(lhs), 0 ) );
}
bool operator==( const double& lhs, const Complex& rhs ) {
return ( is_equal( lhs, real(rhs) ) && is_equal( 0, imag(rhs) ) );
}
bool operator!=( const Complex& lhs, const Complex& rhs ) {
return !( lhs == rhs );
}
bool operator!=( const Complex& lhs, const double& rhs ) {
return !( lhs == rhs );
}
bool operator!=( const double& lhs, const Complex& rhs ) {
return !( lhs == rhs );
}
bool operator<( const Complex& lhs, const Complex& rhs ) {
return ( abs(lhs) < abs(rhs) );
}
bool operator>( const Complex& lhs, const Complex& rhs ) {
return ( abs(lhs) > abs(rhs) );
}
bool operator<=( const Complex& lhs, const Complex& rhs ) {
return ( lhs < rhs || lhs == rhs );
}
bool operator>=( const Complex& lhs, const Complex& rhs ) {
return ( lhs > rhs || lhs == rhs );
}
// Imaginary units declared in complex.h
const Complex I(0, 1);
const Complex& J = I; // J is an alias for I
} // end namespace cpx
If you have any question or comment regarding this code, feel free to email me.