devxlogo

Complex Arithmetic Without Complexities

Complex Arithmetic Without Complexities

omplex numbers are widely-used in electrical engineering, simulations, and scientific applications. And yet, many software engineers who have to use complex arithmetic insist on reinventing the wheel when there’s no need?the C++ Standard Library already has a compact, efficient, and portable library for dealing with complex numbers, including support. Learn how to use without any untoward complexities.


Your app requires complex arithmetic but the burden of writing a library from scratch for that purpose is overwhelming.


Familiarize yourself with and learn how it simplifies complex arithmetic.

real and i
Real numbers are represented in C++ as floating point variables (float, double, and long double). The theory of complex numbers defines a superset of real numbers called complex numbers. A complex number is a composite number that consists of two units. The first one is called the real part and is denoted by a lowercase r. The unit part is the imaginary part and is denoted by a lowercase i. Just as the fractional part and the integral part of the number 10.34 make a single real number, the real and imaginary units are construed as a single complex number. A common way of representing a complex number is to pack two floating point variables in a struct. Problems start when you need to perform mathematical operations on such objects. The built-in operators of C++ +,-,/, etc. do not support an arbitrary user-defined complex number. Using complex numbers in C++ presents two problems:

  • The representation of a complex number
  • Arithmetic operations such as addition, multiplication, and division of complex numbers

The Standard Library header contains a mini-library for manipulating complex numbers easily. It includes the class template std::complex which has three explicit specializations, one for every native floating type:

  • std::complex
  • std::complex
  • std::complex

First, decide which of these three specializations suits your needs best. std::complex is the most compact, occupying eight bytes per one complex number. Alas, it also has the lowest precision and cannot represent real or imaginary values that are higher than numeric_limits::max(). std::complex is a reasonable compromise between space usage (16 bytes per object) and precision. std::complex offers the highest precision but also uses 20 bytes (at least) per complex number.

Creating and Initializing a Complex Number
You instantiate a complex number like this:

#include using std:complex;int main(){ complex  dc;}

dc is an object that represents the complex number (0,0). By convention, a complex number is written as two comma-separated floating point numbers enclosed in parentheses. The first number is always the real part and the second is the imaginary part. To display the value of dc, use cout as usual:

cout

This code will compile because the manipulator has three overloaded versions?one for each std::complex specialization.

In a similar vein, use cin to read a complex number from the standard input:

cout>val;

By design, the constructor of std::complex is not explicit, and thus allows implicit conversions from floating point (and even integral) values to complex:

complex  compnum=5.9;complex  anothercompnum=6;

After the initialization, compnum has the value (5.9,0) and anothercompnum is (5,0). Remember, when you initialize a complex object with a single initializer, that initializer is taken as the real part whereas the imaginary part defaults to 0. If the initializer is an integral value, it's implicitly converted to the floating point datatype of the specialization. In the example above, 6 is silently converted to double, which then becomes the real part of anothercompnum:

coutcout

Initialize a complex object with both the real and imaginary values like this:

complex num2(-10.8,0.8); //(-10.8,0.8)

Arithmetic Operations
One of the advantages of using is the set of built-in operators that it overloads for you. The overloaded unary operators are:

//binary + template  complex operator+ (const complex&, const complex&); template  complex operator+ (const complex&, const T&); template  complex operator+ (const T&, const complex&); //..similar overloads for -, *, /, == and !=//unary + and –template  complex operator+ (const complex&); template  complex operator- (const complex&); 

These overload sets allow you to combine complex objects with native floating point variables in the same expression:

complex  val(2,2), val2(-11.2,3);val = val2 + 9.99; //operator+(complex,double)cout

When you add a floating point value to a complex object, that value is added to the real part whereas the imaginary part remains intact.

Getting real
The C++ Standard defines at least two methods for accessing the real and imaginary parts of a complex number. The first method uses the member functions real() and imag():

complex  compnum(5.9, -2.15);double x=compnum.imag(); //x equals -2.15double y=compnum.real();// y equals 5.9

Alternatively, use the template functions std::real() and std::image() extract the real and imaginary parts of a complex object:

x=std::imag (compnum); y=std::real(compnum);

Here's how you modify the real or imaginary parts:

compnum.real(5.5);compnum.imag(-5.59);

Simple and Efficient
The library is a classic example of the advantages of a standardized, generic solution to a recurring programming task. It's simple enough to allow users to master it easily and pretty efficient because it makes no use of inheritance or virtual functions.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist