Prev | Contents | Next

# 4<complex.h> Complex Number Functionality

The complex functions in this reference section come in three flavors each: double complex, float complex, and long double complex.

The float variants end with f and the long double variants end with l, e.g. for complex cosine:

ccos()   double complex
ccosf()  float complex
ccosl()  long double complex

The table below only lists the double complex version for brevity.

Function Description
cabs() Compute the complex absolute value
cacos() Compute the complex arc-cosine
cacosh() Compute the complex arc hyperbolic cosine
carg() Compute the complex argument
casin() Compute the complex arc-sine
casinh() Compute the complex arc hyperbolic sine
catan() Compute the complex arc-tangent
catanh() Compute the complex arc hyperbolic tangent
ccos() Compute the complex cosine
ccosh() Compute the complex hyperbolic cosine
cexp() Compute the complex base-$$e$$ exponential
cimag() Returns the imaginary part of a complex number
clog() Compute the complex logarithm
CMPLX() Build a complex value from real and imaginary types
conj() Compute the conjugate of a complex number
cproj() Compute the projection of a complex number
creal() Returns the real part of a complex number
csin() Compute the complex sine
csinh() Compute the complex hyperbolic sine
csqrt() Compute the complex square root
ctan() Compute the complex tangent
ctanh() Compute the complex hyperbolic tangent

You can test for complex number support by looking at the __STDC_NO_COMPLEX__ macro. If it’s defined, complex numbers aren’t available.

There are possibly two types of numbers defined: complex and imaginary. No system I’m currently aware of implements imaginary types.

The complex types, which are a real value plus a multiple of $$i$$, are:

float complex
double complex
long double complex

The imaginary types, which hold a multiple of $$i$$, are:

float imaginary
double imaginary
long double imaginary

The mathematical value $$i=\sqrt{-1}$$ is represented by the symbol _Complex_I or _Imaginary_I, if it exists.

The The macro I will be preferentially set to _Imaginary_I (if it exists), or to _Complex_I otherwise.

You can write imaginary literals (if supported) using this notation:

double imaginary x = 3.4 * I;

You can write complex literals using regular complex notation:

double complex x = 1.2 + 3.4 * I;

or build them with the CMPLX() macro:

double complex x = CMPLX(1.2, 3.4);  // Like 1.2 + 3.4 * I

The latter has the advantage of handing special cases of complex numbers correctly (like those involving infinity or signed zeroes) as if _Imaginary_I were present, even if it’s not.

All angular values are in radians.

Some functions have discontinuities called branch cuts. Now, I’m no mathematician so I can’t really talk sensibly about this, but if you’re here, I like to think you know what you’re doing when it comes to this side of things.

If you system has signed zeroes, you can tell which side of the cut you’re on by the sign. And you can’t if you don’t. The spec elaborates:

Implementations that do not support a signed zero […] cannot distinguish the sides of branch cuts. These implementations shall map a cut so the function is continuous as the cut is approached coming around the finite endpoint of the cut in a counter clockwise direction. (Branch cuts for the functions specified here have just one finite endpoint.) For example, for the square root function, coming counter clockwise around the finite endpoint of the cut along the negative real axis approaches the cut from above, so the cut maps to the positive imaginary axis.

Finally, there’s a pragma called CX_LIMITED_RANGE that can be turned on and off (default is off). You can turn it on with:

#pragma STDC CX_LIMITED_RANGE ON

It allows for certain intermediate operations to underflow, overflow, or deal badly with infinity, presumably for a tradeoff in speed. If you’re sure these types of errors won’t occur with the numbers you’re using AND you’re trying to get as much speed out as you can, you could turn this macro on.

The spec also elaborates here:

The purpose of the pragma is to allow the implementation to use the formulas:

$$(x+iy)\times(u+iv) = (xu-yv)+i(yu+xv)$$

$$(x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u^2+v^2)$$

$$|x+iy|=\sqrt{x^2+y^2}$$

where the programmer can determine they are safe.

## 4.1cacos(), cacosf(), cacosl()

Compute the complex arc-cosine

### Synopsis

#include <complex.h>

double complex cacos(double complex z);

float complex cacosf(float complex z);

long double complex cacosl(long double complex z);

### Description

Computes the complex arc-cosine of a complex number.

The complex number z will have an imaginary component in the range $$[0,\pi]$$, and the real component is unbounded.

There are branch cuts outside the interval $$[-1,+1]$$ on the real axis.

### Return Value

Returns the complex arc-cosine of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = cacos(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 0.195321 + -2.788006i

## 4.2casin(), casinf(), casinl()

Compute the complex arc-sine

### Synopsis

#include <complex.h>

double complex casin(double complex z);

float complex casinf(float complex z);

long double complex casinl(long double complex z);

### Description

Computes the complex arc-sine of a complex number.

The complex number z will have an imaginary component in the range $$[-\pi/2,+\pi/2]$$, and the real component is unbounded.

There are branch cuts outside the interval $$[-1,+1]$$ on the real axis.

### Return Value

Returns the complex arc-sine of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = casin(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 1.375476 + 2.788006i

## 4.3catan(), catanf(), catanl()

Compute the complex arc-tangent

### Synopsis

#include <complex.h>

double complex catan(double complex z);

float complex catanf(float complex z);

long double complex catanl(long double complex z);

### Description

Computes the complex arc-tangent of a complex number.

The complex number z will have an real component in the range $$[-\pi/2,+\pi/2]$$, and the imaginary component is unbounded.

There are branch cuts outside the interval $$[-i,+i]$$ on the imaginary axis.

### Return Value

Returns the complex arc-tangent of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double wheat = 8;
double sheep = 1.5708;

double complex x = wheat + sheep * I;

double complex y = catan(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 1.450947 + 0.023299i

## 4.4ccos(), ccosf(), ccosl()

Compute the complex cosine

### Synopsis

#include <complex.h>

double complex ccos(double complex z);

float complex ccosf(float complex z);

long double complex ccosl(long double complex z);

### Description

Computes the complex cosine of a complex number.

### Return Value

Returns the complex cosine of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = ccos(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: -0.365087 + -2.276818i

## 4.5csin(), csinf(), csinl()

Compute the complex sine

### Synopsis

#include <complex.h>

double complex csin(double complex z);

float complex csinf(float complex z);

long double complex csinl(long double complex z);

### Description

Computes the complex sine of a complex number.

### Return Value

Returns the complex sine of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = csin(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 2.482485 + -0.334840i

## 4.6ctan(), ctanf(), ctanl()

Compute the complex tangent

### Synopsis

#include <complex.h>

double complex ctan(double complex z);

float complex ctanf(float complex z);

long double complex ctanl(long double complex z);

### Description

Computes the complex tangent of a complex number.

### Return Value

Returns the complex tangent of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = ctan(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: -0.027073 + 1.085990i

## 4.7cacosh(), cacoshf(), cacoshl()

Compute the complex arc hyperbolic cosine

### Synopsis

#include <complex.h>

double complex cacosh(double complex z);

float complex cacoshf(float complex z);

long double complex cacoshl(long double complex z);

### Description

Computes the complex arc hyperbolic cosine of a complex number.

There is a branch cut at values less than $$1$$ on the real axis.

The return value will be non-negative on the real number axis, and in the range $$[-i\pi,+i\pi]$$ on the imaginary axis.

### Return Value

Returns the complex arc hyperbolic cosine of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = cacosh(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 2.788006 + 0.195321i

## 4.8casinh(), casinhf(), casinhl()

Compute the complex arc hyperbolic sine

### Synopsis

#include <complex.h>

double complex casinh(double complex z);

float complex casinhf(float complex z);

long double complex casinhl(long double complex z);

### Description

Computes the complex arc hyperbolic sine of a complex number.

There are branch cuts outside $$[-i,+i]$$ on the imaginary axis.

The return value will be unbounded on the real number axis, and in the range $$[-i\pi/2,+i\pi/2]$$ on the imaginary axis.

### Return Value

Returns the complex arc hyperbolic sine of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = casinh(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 2.794970 + 0.192476i

## 4.9catanh(), catanhf(), catanhl()

Compute the complex arc hyperbolic tangent

### Synopsis

#include <complex.h>

double complex catanh(double complex z);

float complex catanhf(float complex z);

long double complex catanhl(long double complex z);

### Description

Computes the complex arc hyperbolic tangent of a complex number.

There are branch cuts outside $$[-1,+1]$$ on the real axis.

The return value will be unbounded on the real number axis, and in the range $$[-i\pi/2,+i\pi/2]$$ on the imaginary axis.

### Return Value

Returns the complex arc hyperbolic tangent of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = catanh(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 0.120877 + 1.546821i

## 4.10ccosh(), ccoshf(), ccoshl()

Compute the complex hyperbolic cosine

### Synopsis

#include <complex.h>

double complex ccosh(double complex z);

float complex ccoshf(float complex z);

long double complex ccoshl(long double complex z);

### Description

Computes the complex hyperbolic cosine of a complex number.

### Return Value

Returns the complex hyperbolic cosine of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = ccosh(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: -0.005475 + 1490.478826i

## 4.11csinh(), csinhf(), csinhl()

Compute the complex hyperbolic sine

### Synopsis

#include <complex.h>

double complex csinh(double complex z);

float complex csinhf(float complex z);

long double complex csinhl(long double complex z);

### Description

Computes the complex hyperbolic sine of a complex number.

### Return Value

Returns the complex hyperbolic sine of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = csinh(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: -0.005475 + 1490.479161i

## 4.12ctanh(), ctanhf(), ctanhl()

Compute the complex hyperbolic tangent

### Synopsis

#include <complex.h>

double complex ctanh(double complex z);

float complex ctanhf(float complex z);

long double complex ctanhl(long double complex z);

### Description

Computes the complex hyperbolic tangent of a complex number.

### Return Value

Returns the complex hyperbolic tangent of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 8 + 1.5708 * I;

double complex y = ctanh(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 1.000000 + -0.000000i

## 4.13cexp(), cexpf(), cexpl()

Compute the complex base-$$e$$ exponential

### Synopsis

#include <complex.h>

double complex cexp(double complex z);

float complex cexpf(float complex z);

long double complex cexpl(long double complex z);

### Description

Computes the complex base-$$e$$ exponential of z.

### Return Value

Returns the complex base-$$e$$ exponential of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 1 + 2 * I;

double complex y = cexp(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: -1.131204 + 2.471727i

## 4.14clog(), clogf(), clogl()

Compute the complex logarithm

### Synopsis

#include <complex.h>

double complex clog(double complex z);

float complex clogf(float complex z);

long double complex clogl(long double complex z);

### Description

Compute the base-$$e$$ complex logarithm of z. There is a branch cut on the negative real axis.

The returns value is unbounded on the real axis and in the range $$[-i\pi,+i\pi]$$ on the imaginary axis.

### Return Value

Returns the base-$$e$$ complex logarithm of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 1 + 2 * I;

double complex y = clog(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 0.804719 + 1.107149i

## 4.15cabs(), cabsf(), cabsl()

Compute the complex absolute value

### Synopsis

#include <complex.h>

double cabs(double complex z);

float cabsf(float complex z);

long double cabsl(long double complex z);

### Description

Computes the complex absolute value of z.

### Return Value

Returns the complex absolute value of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 1 + 2 * I;

double complex y = cabs(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 2.236068 + 0.000000i

## 4.16cpow(), cpowf(), cpowl()

Compute complex power

### Synopsis

#include <complex.h>

double complex cpow(double complex x, double complex y);

float complex cpowf(float complex x, float complex y);

long double complex cpowl(long double complex x,
long double complex y);

### Description

Computes the complex $$x^y$$.

There is a branch cut for x along the negative real axis.

### Return Value

Returns the complex $$x^y$$.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 1 + 2 * I;
double complex y = 3 + 4 * I;

double r = cpow(x, y);

printf("Result: %f + %fi\n", creal(r), cimag(r));
}

Result:

Result: 0.129010 + 0.000000i

## 4.17csqrt(), csqrtf(), csqrtl()

Compute the complex square root

### Synopsis

#include <complex.h>

double complex csqrt(double complex z);

float complex csqrtf(float complex z);

long double complex csqrtl(long double complex z);

### Description

Computes the complex square root of z.

There is a branch cut along the negative real axis.

The return value is in the right half of the complex plane and includes the imaginary axis.

### Return Value

Returns the complex square root of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 1 + 2 * I;

double complex y = csqrt(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 1.272020 + 0.786151i

## 4.18carg(), cargf(), cargl()

Compute the complex argument

### Synopsis

#include <complex.h>

double carg(double complex z);

float cargf(float complex z);

long double cargl(long double complex z);

### Description

Computes the complex argument (AKA phase angle) of z.

There is a branch cut along the negative real axis.

Returns a value in the range $$[-\pi,+\pi]$$.

### Return Value

Returns the complex argument of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 1 + 2 * I;

double y = carg(x);

printf("Result: %f\n", y);
}

Output:

Result: 1.107149

## 4.19cimag(), cimagf(), cimagl()

Returns the imaginary part of a complex number

### Synopsis

#include <complex.h>

double cimag(double complex z);

float cimagf(float complex z);

long double cimagl(long double complex z);

### Description

Returns the imaginary part of z.

As a footnote, the spec points out that any complex number x is part of the following equivalency:

x == creal(x) + cimag(x) * I;

### Return Value

Returns the imaginary part of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 1 + 2 * I;

double y = cimag(x);

printf("Result: %f\n", y);
}

Output—just the imaginary part:

Result: 2.000000

creal()

## 4.20CMPLX(), CMPLXF(), CMPLXL()

Build a complex value from real and imaginary types

### Synopsis

#include <complex.h>

double complex CMPLX(double x, double y);

float complex CMPLXF(float x, float y);

long double complex CMPLXL(long double x, long double y);

### Description

These macros build a complex value from real and imaginary types.

Now I know what you’re thinking. “But I can already build a complex value from real and imaginary types using the I macro, like in the example you’re about to give us.”

double complex x = 1 + 2 * I;

And that’s true.

But the reality of the matter is weird and complex.

Maybe I got undefined, or maybe you redefined it.

Or maybe I was defined as _Complex_I which doesn’t necessarily preserve the sign of a zero value.

As the spec points out, these macros build complex numbers as if _Imaginary_I were defined (thus preserving your zero sign) even if it’s not. That is, they are defined equivalently to:

#define CMPLX(x, y)  ((double complex)((double)(x) + \
_Imaginary_I * (double)(y)))

#define CMPLXF(x, y) ((float complex)((float)(x) + \
_Imaginary_I * (float)(y)))

#define CMPLXL(x, y) ((long double complex)((long double)(x) + \
_Imaginary_I * (long double)(y)))

### Return Value

Returns the complex number for the given real x and imaginary y components.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = CMPLX(1, 2);  // Like 1 + 2 * I

printf("Result: %f + %fi\n", creal(x), cimag(x));
}

Output:

Result: 1.000000 + 2.000000i

## 4.21conj(), conjf(), conjl()

Compute the conjugate of a complex number

### Synopsis

#include <complex.h>

double complex conj(double complex z);

float complex conjf(float complex z);

long double complex conjl(long double complex z);

### Description

This function computes the complex conjugate13 of z. Apparently it does this by reversing the sign of the imaginary part, but dammit, I’m a programmer not a mathematician, Jim!

### Return Value

Returns the complex conjugate of z

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 1 + 2 * I;

double complex y = conj(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 1.000000 + -2.000000i

## 4.22cproj(), cproj(), cproj()

Compute the projection of a complex number

### Synopsis

#include <complex.h>

double complex cproj(double complex z);

float complex cprojf(float complex z);

long double complex cprojl(long double complex z);

### Description

Computes the projection of z onto a Riemann sphere14.

Now we’re really outside my expertise. The spec has this to say, which I’m quoting verbatim because I’m not knowledgable enough to rewrite it sensibly. Hopefully it makes sense to anyone who would need to use this function.

z projects to z except that all complex infinities (even those with one infinite part and one NaN part) project to positive infinity on the real axis. If z has an infinite part, then cproj(z) is equivalent to

INFINITY + I * copysign(0.0, cimag(z))

So there you have it.

### Return Value

Returns the projection of z onto a Riemann sphere.

### Example

Fingers crossed this is a remotely sane example…

#include <stdio.h>
#include <complex.h>
#include <math.h>

int main(void)
{
double complex x = 1 + 2 * I;

double complex y = cproj(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));

x = INFINITY + 2 * I;
y = cproj(x);

printf("Result: %f + %fi\n", creal(y), cimag(y));
}

Output:

Result: 1.000000 + 2.000000i
Result: inf + 0.000000i

## 4.23creal(), crealf(), creall()

Returns the real part of a complex number

### Synopsis

#include <complex.h>

double creal(double complex z);

float crealf(float complex z);

long double creall(long double complex z);

### Description

Returns the real part of z.

As a footnote, the spec points out that any complex number x is part of the following equivalency:

x == creal(x) + cimag(x) * I;

### Return Value

Returns the real part of z.

### Example

#include <stdio.h>
#include <complex.h>

int main(void)
{
double complex x = 1 + 2 * I;

double y = creal(x);

printf("Result: %f\n", y);
}

Output—just the real part:

Result: 1.000000

cimag()