Complex Numbers

This chapter describes the complex numbers as supported by MAD-NG. The module for Complex numbers is not exposed, only the contructors are visible from the MAD environment and thus, complex numbers are handled directly by their methods or by the generic functions of the same name from the module MAD.gmath. Note that complex have value semantic like a pair of number equivalent to a C structure or an array const num_t[2] for direct compliance with the C API.

Types promotion

The operations on complex numbers may involve other data types like real numbers leading to few combinations of types. In order to simplify the descriptions, the generic names num and cpx are used for real and complex numbers respectively. The following table summarizes all valid combinations of types for binary operations involving at least one complex type:

Left Operand Type

Right Operand Type

Result Type

number

complex

complex

complex

number

complex

complex

complex

complex

Constructors

The constructors for complex numbers are directly available from the MAD environment, except for the special case of the imaginary postfix, which is part of the language definition.

i

The imaginary postfix that qualifies literal numbers as imaginary numbers, i.e. 1i is the imaginary unit, and 1+2i is the complex number \(1+2i\).

complex(re_, im_)

Return the complex number equivalent to re + im * 1i. Default: re_ = 0, im_ = 0.

tocomplex(str)

Return the complex number decoded from the string str containing the literal complex number "a+bi" (with no spaces) where a and b are literal numbers, i.e. the strings "1", "2i" and "1+2i" will give respectively the complex numbers \(1+0i\), \(0+2i\) and \(1+2i\).

Attributes

cpx.re

The real part of the complex number cpx.

cpx.im

The imaginary part of the complex number cpx.

Functions

is_complex(a)

Return true if a is a complex number, false otherwise. This function is only available from the module MAD.typeid.

is_scalar(a)

Return true if a is a number or a complex number, false otherwise. This function is only available from the module MAD.typeid.

Methods

Operator-like Methods

Functions

Return values

Metamethods

C functions

z:unm()

\(-z\)

__unm(z,_)

z:add(z2)

\(z + z_2\)

__add(z,z2)

z:sub(z2)

\(z - z_2\)

__sub(z,z2)

z:mul(z2)

\(z \cdot z_2\)

__mul(z,z2)

z:div(z2)

\(z / z_2\)

__div(z,z2)

mad_cpx_div_r() [1]

z:mod(z2)

\(z \mod z_2\)

__mod(z,z2)

mad_cpx_mod_r()

z:pow(z2)

\(z ^ {z_2}\)

__pow(z,z2)

mad_cpx_pow_r()

z:eq(z2)

\(z = z_2\)

__eq(z,z2)

Real-like Methods

Functions

Return values

C functions

z:abs()

\(|z|\)

mad_cpx_abs_r()

z:acos()

\(\cos^{-1} z\)

mad_cpx_acos_r()

z:acosh()

\(\cosh^{-1} z\)

mad_cpx_acosh_r()

z:acot()

\(\cot^{-1} z\)

mad_cpx_atan_r()

z:acoth()

\(\coth^{-1} z\)

mad_cpx_atanh_r()

z:asin()

\(\sin^{-1} z\)

mad_cpx_asin_r()

z:asinc()

\(\frac{\sin^{-1} z}{z}\)

mad_cpx_asinc_r()

z:asinh()

\(\sinh^{-1} x\)

mad_cpx_asinh_r()

z:asinhc()

\(\frac{\sinh^{-1} z}{z}\)

mad_cpx_asinhc_r()

z:atan()

\(\tan^{-1} z\)

mad_cpx_atan_r()

z:atanh()

\(\tanh^{-1} z\)

mad_cpx_atanh_r()

z:ceil()

\(\lceil\Re(z)\rceil+i\,\lceil\Im(z)\rceil\)

z:cos()

\(\cos z\)

mad_cpx_cos_r()

z:cosh()

\(\cosh z\)

mad_cpx_cosh_r()

z:cot()

\(\cot z\)

mad_cpx_tan_r()

z:coth()

\(\coth z\)

mad_cpx_tanh_r()

z:exp()

\(\exp z\)

mad_cpx_exp_r()

z:floor()

\(\lfloor\Re(z)\rfloor+i\,\lfloor\Im(z)\rfloor\)

z:frac()

\(z - \operatorname{trunc}(z)\)

z:hypot(z2)

\(\sqrt{z^2+z_2^2}\)

[2]

z:hypot3(z2,z3)

\(\sqrt{z^2+z_2^2+z_3^2}\)

[2]

z:inv(v_)

\(\frac{v}{z}\)

mad_cpx_inv_r() [1]

z:invsqrt(v_)

\(\frac{v}{\sqrt z}\)

mad_cpx_invsqrt_r() [1]

z:log()

\(\log z\)

mad_cpx_log_r()

z:log10()

\(\log_{10} z\)

mad_cpx_log10_r()

z:powi(n)

\(z^n\)

mad_cpx_powi_r()

z:round()

\(\lfloor\Re(z)\rceil+i\,\lfloor\Im(z)\rceil\)

z:sin()

\(\sin z\)

mad_cpx_sin_r()

z:sinc()

\(\frac{\sin z}{z}\)

mad_cpx_sinc_r()

z:sinh()

\(\sinh z\)

mad_cpx_sinh_r()

z:sinhc()

\(\frac{\sinh z}{z}\)

mad_cpx_sinhc_r()

z:sqr()

\(z \cdot z\)

z:sqrt()

\(\sqrt{z}\)

mad_cpx_sqrt_r()

z:tan()

\(\tan z\)

mad_cpx_tan_r()

z:tanh()

\(\tanh z\)

mad_cpx_tanh_r()

z:trunc()

\(\operatorname{trunc} \Re(z)+i\,\operatorname{trunc} \Im(z)\)

z:unit()

\(\frac{z}{|z|}\)

mad_cpx_unit_r()

In methods inv() and invsqrt(), default is v_ = 1.

Complex-like Methods

Functions

Return values

C functions

z:cabs()

\(|z|\)

mad_cpx_abs_r()

z:carg()

\(\arg z\)

mad_cpx_arg_r()

z:conj()

\(z^*\)

z:fabs()

\(|\Re(z)|+i\,|\Im(z)|\)

z:imag()

\(\Im(z)\)

z:polar()

\(|z|\,e^{i \arg z}\)

mad_cpx_polar_r()

z:proj()

\(\operatorname{proj}(z)\)

mad_cpx_proj_r()

z:real()

\(\Re(z)\)

z:rect()

\(\Re(z)\cos \Im(z)+i\,\Re(z)\sin \Im(z)\)

mad_cpx_rect_r()

z:reim()

\(\Re(z), \Im(z)\)

Error-like Methods

Error-like methods call C wrappers to the corresponding functions from the Faddeeva library from the MIT, considered as one of the most accurate and fast implementation over the complex plane [FADDEEVA] (see mad_num.c).

Functions

Return values

C functions

z:erf(rtol_)

\(\frac{2}{\sqrt\pi}\int_0^z e^{-t^2} dt\)

mad_cpx_erf_r()

z:erfc(rtol_)

\(1-\operatorname{erf}(z)\)

mad_cpx_erfc_r()

z:erfi(rtol_)

\(-i\operatorname{erf}(i z)\)

mad_cpx_erfi_r()

z:erfcx(rtol_)

\(e^{z^2}\operatorname{erfc}(z)\)

mad_cpx_erfcx_r()

z:wf(rtol_)

\(e^{-z^2}\operatorname{erfc}(-i z)\)

mad_cpx_wf_r()

z:dawson(rtol_)

\(\frac{-i\sqrt\pi}{2}e^{-z^2}\operatorname{erf}(iz)\)

mad_cpx_dawson_r()

Operators

The operators on complex follow the conventional mathematical operations of Complex numbers.

-cpx

Return a complex resulting from the negation of the operand as computed by cpx:unm().

num + cpx
cpx + num
cpx + cpx

Return a complex resulting from the sum of the left and right operands as computed by cpx:add().

num - cpx
cpx - num
cpx - cpx

Return a complex resulting from the difference of the left and right operands as computed by cpx:sub().

num * cpx
cpx * num
cpx * cpx

Return a complex resulting from the product of the left and right operands as computed by cpx:mul().

num / cpx
cpx / num
cpx / cpx

Return a complex resulting from the division of the left and right operands as computed by cpx:div(). If the right operand is a complex number, the division uses a robut and fast algorithm implemented in mad_cpx_div_r() [1].

num % cpx
cpx % num
cpx % cpx

Return a complex resulting from the rest of the division of the left and right operands, i.e. \(x - y \lfloor \frac{x}{y} \rfloor\), as computed by cpx:mod(). If the right operand is a complex number, the division uses a robut and fast algorithm implemented in mad_cpx_div_r() [1].

num ^ cpx
cpx ^ num
cpx ^ cpx

Return a complex resulting from the left operand raised to the power of the right operand as computed by cpx:pow().

num == cpx
cpx == num
cpx == cpx

Return false if the real or the imaginary part differ between the left and right operands, true otherwise. A number a will be interpreted as \(a+i0\) for the comparison.

C API

These functions are provided for performance reason and compliance (i.e. branch cut) with the C API of other modules dealing with complex numbers like the linear and the differential algebra. For the same reason, some functions hereafter refer to the section 7.3 of the C Programming Language Standard [ISOC99CPX].

num_t mad_cpx_abs_r(num_t x_re, num_t x_im)

Return the modulus of the complex x as computed by cabs().

num_t mad_cpx_arg_r(num_t x_re, num_t x_im)

Return the argument in \([-\pi, +\pi]\) of the complex x as computed by carg().

void mad_cpx_unit_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the complex x divided by its modulus as computed by cabs().

void mad_cpx_proj_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the projection of the complex x on the Riemann sphere as computed by cproj().

void mad_cpx_rect_r(num_t rho, num_t ang, cpx_t *r)

Put in r the rectangular form of the complex rho * exp(i*ang).

void mad_cpx_polar_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the polar form of the complex x.

void mad_cpx_inv_r(num_t x_re, num_t x_im, cpx_t *r)
cpx_t mad_cpx_inv(cpx_t x)

Put in r or return the inverse of the complex x.

void mad_cpx_invsqrt_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the square root of the inverse of the complex x.

void mad_cpx_div_r(num_t x_re, num_t x_im, num_t y_re, num_t y_im, cpx_t *r)
cpx_t mad_cpx_div(cpx_t x, cpx_t y)

Put in r or return the complex x divided by the complex y.

void mad_cpx_mod_r(num_t x_re, num_t x_im, num_t y_re, num_t y_im, cpx_t *r)

Put in r the remainder of the division of the complex x by the complex y.

void mad_cpx_pow_r(num_t x_re, num_t x_im, num_t y_re, num_t y_im, cpx_t *r)

Put in r the complex x raised to the power of complex y using cpow().

void mad_cpx_powi_r(num_t x_re, num_t x_im, int n, cpx_t *r)
cpx_t mad_cpx_powi(cpx_t x, int n)

Put in r or return the complex x raised to the power of the integer n using a fast algorithm.

void mad_cpx_sqrt_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the square root of the complex x as computed by csqrt().

void mad_cpx_exp_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the exponential of the complex x as computed by cexp().

void mad_cpx_log_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the natural logarithm of the complex x as computed by clog().

void mad_cpx_log10_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the logarithm of the complex x.

void mad_cpx_sin_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the sine of the complex x as computed by csin().

void mad_cpx_cos_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the cosine of the complex x as computed by ccos().

void mad_cpx_tan_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the tangent of the complex x as computed by ctan().

void mad_cpx_sinh_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the hyperbolic sine of the complex x as computed by csinh().

void mad_cpx_cosh_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the hyperbolic cosine of the complex x as computed by ccosh().

void mad_cpx_tanh_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the hyperbolic tangent of the complex x as computed by ctanh().

void mad_cpx_asin_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the arc sine of the complex x as computed by casin().

void mad_cpx_acos_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the arc cosine of the complex x as computed by cacos().

void mad_cpx_atan_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the arc tangent of the complex x as computed by catan().

void mad_cpx_asinh_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the hyperbolic arc sine of the complex x as computed by casinh().

void mad_cpx_acosh_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the hyperbolic arc cosine of the complex x as computed by cacosh().

void mad_cpx_atanh_r(num_t x_re, num_t x_im, cpx_t *r)

Put in r the hyperbolic arc tangent of the complex x as computed by catanh().

void mad_cpx_sinc_r(num_t x_re, num_t x_im, cpx_t *r)
cpx_t mad_cpx_sinc(cpx_t x)

Put in r or return the sine cardinal of the complex x.

void mad_cpx_sinhc_r(num_t x_re, num_t x_im, cpx_t *r)
cpx_t mad_cpx_sinhc(cpx_t x)

Put in r or return the hyperbolic sine cardinal of the complex x.

void mad_cpx_asinc_r(num_t x_re, num_t x_im, cpx_t *r)
cpx_t mad_cpx_asinc(cpx_t x)

Put in r or return the arc sine cardinal of the complex x.

void mad_cpx_asinhc_r(num_t x_re, num_t x_im, cpx_t *r)
cpx_t mad_cpx_asinhc(cpx_t x)

Put in r or return the hyperbolic arc sine cardinal of the complex x.

void mad_cpx_wf_r(num_t x_re, num_t x_im, num_t relerr, cpx_t *r)
cpx_t mad_cpx_wf(cpx_t x, num_t relerr)

Put in r or return the Faddeeva function of the complex x.

void mad_cpx_erf_r(num_t x_re, num_t x_im, num_t relerr, cpx_t *r)
cpx_t mad_cpx_erf(cpx_t x, num_t relerr)

Put in r or return the error function of the complex x.

void mad_cpx_erfc_r(num_t x_re, num_t x_im, num_t relerr, cpx_t *r)
cpx_t mad_cpx_erfc(cpx_t x, num_t relerr)

Put in r or return the complementary error function of the complex x.

void mad_cpx_erfcx_r(num_t x_re, num_t x_im, num_t relerr, cpx_t *r)
cpx_t mad_cpx_erfcx(cpx_t x, num_t relerr)

Put in r or return the scaled complementary error function of the complex x.

void mad_cpx_erfi_r(num_t x_re, num_t x_im, num_t relerr, cpx_t *r)
cpx_t mad_cpx_erfi(cpx_t x, num_t relerr)

Put in r or return the imaginary error function of the complex x.

void mad_cpx_dawson_r(num_t x_re, num_t x_im, num_t relerr, cpx_t *r)
cpx_t mad_cpx_dawson(cpx_t x, num_t relerr)

Put in r or return the Dawson integral for the complex x.

References

[CPXDIV]
    1. Smith, “Algorithm 116: Complex division”, Commun. ACM, 5(8):435, 1962.

[CPXDIV2]
  1. Baudin and R. L. Smith, “A robust complex division in Scilab”, October 2012. http://arxiv.org/abs/1210.4539.

[FADDEEVA]
  1. Oeftiger, R. De Maria, L. Deniau et al, “Review of CPU and GPU Faddeeva Implementations”, IPAC2016. https://cds.cern.ch/record/2207430/files/wepoy044.pdf.

[ISOC99CPX]

ISO/IEC 9899:1999 Programming Languages - C. https://www.iso.org/standard/29237.html.

Footnotes