Sun Studio 12: C++ User's Guide

Chapter 15 Using the Complex Arithmetic Library

Complex numbers are numbers made up of a real part and an imaginary part. For example:

3.2 + 4i 1 + 3i 1 + 2.3i

In the degenerate case, 0 + 3i is an entirely imaginary number generally written as 3i, and 5 + 0i is an entirely real number generally written as 5. You can represent complex numbers using the complex data type.


Note –

The complex arithmetic library ( libcomplex) is available only for compatibility mode ( -compat[ =4]). In standard mode (the default mode), complex number classes with similar functionality are included with the C++ Standard Library libCstd.


15.1 The Complex Library

The complex arithmetic library implements a complex number data type as a new data type and provides:

Complex numbers can also be represented as an absolute value (or magnitude) and an argument (or angle). The library provides functions to convert between the real and imaginary (Cartesian) representation and the magnitude and angle (polar) representation.

The complex conjugate of a number has the opposite sign in its imaginary part.

15.1.1 Using the Complex Library

To use the complex library, include the header file complex.h in your program, and compile and link with the -library=complex option.

15.2 Type complex

The complex arithmetic library defines one class: class complex. An object of class complex can hold a single complex number. The complex number is constructed of two parts:


class complex {
    double re, im;
};

The value of an object of class complex is a pair of double values. The first value represents the real part; the second value represents the imaginary part.

15.2.1 Constructors of Class complex

There are two constructors for complex. Their definitions are:


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

If you declare a complex variable without specifying parameters, the first constructor is used and the variable is initialized, so that both parts are 0. The following example creates a complex variable whose real and imaginary parts are both 0:


complex aComp;

You can give either one or two parameters. In either case, the second constructor is used. When you give only one parameter, that parameter is taken as the value for the real part and the imaginary part is set to 0. For example:


complex aComp(4.533);

creates a complex variable with the following value:


4.533 + 0i

If you give two values, the first value is taken as the value of the real part and the second as the value of the imaginary part. For example:


complex aComp(8.999, 2.333);

creates a complex variable with the following value:


8.999 + 2.333i

You can also create a complex number using the polar function, which is provided in the complex arithmetic library (see 15.3 Mathematical Functions). The polar function creates a complex value given the polar coordinates magnitude and angle.

There is no destructor for type complex.

15.2.2 Arithmetic Operators

The complex arithmetic library defines all the basic arithmetic operators. Specifically, the following operators work in the usual way and with the usual precedence:

+ - / * =

The subtraction operator (-) has its usual binary and unary meanings.

In addition, you can use the following operators in the usual way:

However, the preceding four operators do not produce values that you can use in expressions. For example, the following expressions do not work:


complex a, b;
...
if ((a+=2)==0) {...}; // illegal
b = a *= b; // illegal

You can also use the equality operator (==) and the inequality operator (!=) in their regular meaning.

When you mix real and complex numbers in an arithmetic expression, C++ uses the complex operator function and converts the real values to complex values.

15.3 Mathematical Functions

The complex arithmetic library provides a number of mathematical functions. Some are peculiar to complex numbers; the rest are complex-number versions of functions in the standard C mathematical library.

All of these functions produce a result for every possible argument. If a function cannot produce a mathematically acceptable result, it calls complex_error and returns some suitable value. In particular, the functions try to avoid actual overflow and call complex_error with a message instead. The following tables describe the remainder of the complex arithmetic library functions.


Note –

The implementation of the sqrt and atan2 functions is aligned with the C99 csqrt Annex G specification.


Table 15–1 Complex Arithmetic Library Functions

Complex Arithmetic Library Function  

Description 

double abs(const complex)

Returns the magnitude of a complex number. 

double arg(const complex)

Returns the angle of a complex number. 

complex conj(const complex)

Returns the complex conjugate of its argument. 

double imag(const complex&)

Returns the imaginary part of a complex number. 

double norm(const complex)

Returns the square of the magnitude of its argument. Faster than abs, but more likely to cause an overflow. For comparing magnitudes.

complex polar(double mag, double ang=0.0)

Takes a pair of polar coordinates that represent the magnitude and angle of a complex number and returns the corresponding complex number. 

double real(const complex&)

Returns the real part of a complex number. 

Table 15–2 Complex Mathematical and Trigonometric Functions

Complex Arithmetic Library Function

Description 

complex acos(const complex)

Returns the angle whose cosine is its argument. 

complex asin(const complex)

Returns the angle whose sine is its argument. 

complex atan(const complex)

Returns the angle whose tangent is its argument. 

complex cos(const complex)

Returns the cosine of its argument. 

complex cosh(const complex)

Returns the hyperbolic cosine of its argument. 

complex exp(const complex)

Computes e**x, where e is the base of the natural logarithms, and x is the argument given to exp.

complex log(const complex)

Returns the natural logarithm of its argument. 

complex log10(const complex)

Returns the common logarithm of its argument. 

complex pow(double b, const complex exp)

complex pow(const complex b, int exp)

complex pow(const complex b, double exp)

complex pow(const complex b, const

complex exp)

Takes two arguments: pow(b, exp). It raises b to the power of exp.

complex sin(const complex)

Returns the sine of its argument. 

complex sinh(const complex)

Returns the hyperbolic sine of its argument. 

complex sqrt(const complex)

Returns the square root of its argument. 

complex tan(const complex)

Returns the tangent of its argument. 

complex tanh(const complex)

Returns the hyperbolic tangent of its argument. 

15.4 Error Handling

The complex library has these definitions for error handling:


extern int errno;
class c_exception {...};
int complex_error(c_exception&);

The external variable errno is the global error state from the C library. errno can take on the values listed in the standard header errno.h (see the man page perror(3)). No function sets errno to zero, but many functions set it to other values.

To determine whether a particular operation fails:

  1. Set errno to zero before the operation.

  2. Test the operation.

The function complex_error takes a reference to type c_exception and is called by the following complex arithmetic library functions:

The default version of complex_error returns zero. This return of zero means that the default error handling takes place. You can provide your own replacement function complex_error that performs other error handling. Error handling is described in the man page cplxerr(3CC4).

Default error handling is described in the man pages cplxtrig(3CC4) and cplxexp(3CC4) It is also summarized in the following table.

Complex Arithmetic Library Function  

Default Error Handling Summary  

exp

If overflow occurs, sets errno to ERANGE and returns a huge complex number.

log, log10

If the argument is zero, sets errno to EDOM and returns a huge complex number.

sinh, cosh

If the imaginary part of the argument causes overflow, returns a complex zero. If the real part causes overflow, returns a huge complex number. In either case, sets errno to ERANGE.

15.5 Input and Output

The complex arithmetic library provides default extractors and inserters for complex numbers, as shown in the following example:


ostream& operator<<(ostream&, const complex&); //inserter
istream& operator>>(istream&, complex&); //extractor

For basic information on extractors and inserters, see 14.2 Basic Structure of iostream Interaction and 14.3.1 Output Using iostream.

For input, the complex extractor >> extracts a pair of numbers (surrounded by parentheses and separated by a comma) from the input stream and reads them into a complex object. The first number is taken as the value of the real part; the second as the value of the imaginary part. For example, given the declaration and input statement:


complex x;
cin >> x;

and the input (3.45, 5), the value of x is equivalent to 3.45 + 5.0i. The reverse is true for inserters. Given complex x(3.45, 5), cout<<x prints (3.45, 5).

The input usually consists of a pair of numbers in parentheses separated by a comma; white space is optional. If you provide a single number, with or without parentheses and white space, the extractor sets the imaginary part of the number to zero. Do not include the symbol i in the input text.

The inserter inserts the values of the real and imaginary parts enclosed in parentheses and separated by a comma. It does not include the symbol i. The two values are treated as doubles.

15.6 Mixed-Mode Arithmetic

Type complex is designed to fit in with the built-in arithmetic types in mixed-mode expressions. Arithmetic types are silently converted to type complex, and there are complex versions of the arithmetic operators and most mathematical functions. For example:


int i, j;
double x, y;
complex a, b;
a = sin((b+i)/y) + x/j;

The expression b+i is mixed-mode. Integer i is converted to type complex via the constructor complex::complex(double,double=0), the integer first being converted to type double. The result is to be divided by y, a double, so y is also converted to complex and the complex divide operation is used. The quotient is thus type complex, so the complex sine routine is called, yielding another complex result, and so on.

Not all arithmetic operations and conversions are implicit, or even defined, however. For example, complex numbers are not well-ordered, mathematically speaking, and complex numbers can be compared for equality only.


complex a, b;
a == b; // OK
a != b; // OK
a <  b; // error: operator < cannot be applied to type complex
a >= b; // error: operator >= cannot be applied to type complex

Similarly, there is no automatic conversion from type complex to any other type, because the concept is not well-defined. You can specify whether you want the real part, imaginary part, or magnitude, for example.


complex a;
double f(double);
f(abs(a)); // OK
f(a);      // error: no match for f(complex)

15.7 Efficiency

The design of the complex class addresses efficiency concerns.

The simplest functions are declared inline to eliminate function call overhead.

Several overloaded versions of functions are provided when that makes a difference. For example, the pow function has versions that take exponents of type double and int as well as complex, since the computations for the former are much simpler.

The standard C math library header math.h is included automatically when you include complex.h. The C++ overloading rules then result in efficient evaluation of expressions like this:


double x;
complex x = sqrt(x);

In this example, the standard math function sqrt(double) is called, and the result is converted to type complex, rather than converting to type complex first and then calling sqrt(complex). This result falls right out of the overload resolution rules, and is precisely the result you want.

15.8 Complex Man Pages

The remaining documentation of the complex arithmetic library consists of the man pages listed in the following table.

Table 15–3 Man Pages for Type complex

Man Page 

Overview  

cplx.intro(3CC4)

General introduction to the complex arithmetic library 

cartpol(3CC4)

Cartesian and polar functions 

cplxerr(3CC4)

Error-handling functions 

cplxexp(3CC4)

Exponential, log, and square root functions 

cplxops(3CC4)

Arithmetic operator functions 

cplxtrig(3CC4)

Trigonometric functions