Complex Data Types and Functions
Users can perform computations with complex arithmetic by using predefined data types. These types are available in two floating-point precisions:
1. f_complex z for single-precision complex values
2. d_complex w for double-precision complex values
Each complex value is a C language structure that consists of a pair of real values, the real and imaginary part of the complex number. To access the real part of a single-precision complex number z, use the subexpression z.re. For the imaginary part, use the subexpression z.im. Use subexpressions w.re and w.im for the real and imaginary parts of a double-precision complex number w. The structure is declared within imsl.h as follows:
typedef struct{
float re;
float im;
} f_complex;
Several standard operations and functions are available for users to perform calculations with complex numbers within their programs. The operations are provided for both single and double precision data types. Notice that even the ordinary arithmetic operations of “+”, “-”, “*”, and “/” must be performed using the appropriate functions.
A uniform prefix name is used as part of the names for the operations and functions. The prefix imsl_c_ is used for f_complex data. The prefix imsl_z_ is used with d_complex data.
Single-Precision Complex Operations and Functions
Operation | Function Name | Function Result | Function Argument(s) |
z = –x | z = imsl_c_neg(x) | f_complex | f_complex |
z = x + y | z = imsl_c_add(x,y) | f_complex | f_complex (both) |
z = x – y | z = imsl_c_sub(x,y) | f_complex | f_complex (both) |
z = x * y | z = imsl_c_mul(x,y) | f_complex | f_complex (both) |
z = x / y | z = imsl_c_div(x,y) | f_complex | f_complex (both) |
x= =ya | z = imsl_c_eq(x,y) | Int | f_complex (both) |
z = x Drop Precision | z = imsl_cz_convert(x) | f_complex | d_complex |
a Result has the value 1 if x and y are valid numbers with real and imaginary parts identical; otherwise, result has the value 0.
Operation | Function Name | Function Result | Function Argument(s) |
z = a + ib Ascend Data | z = imsl_cf_convert(a,b) | f_complex | float (both) |
| z = imsl_c_conjg(x) | f_complex | f_complex |
a = |z| | a = imsl_c_abs(z) | float | f_complex |
a = arg (z) –π < a ≤ π | a = imsl_c_arg(z) | float | f_complex |
| z = imsl_c_sqrt(z) | f_complex | f_complex |
z = cos (z) | z = imsl_c_cos(z) | f_complex | f_complex |
z = sin (z) | z = imsl_c_sin(z) | f_complex | f_complex |
z = exp (z) | z = imsl_c_exp(z) | f_complex | f_complex |
z = log (z) | z = imsl_c_log(z) | f_complex | f_complex |
z = xa | z = imsl_cf_power(x,a) | f_complex | f_complex, float |
z = xy | z = imsl_cc_power(x,y) | f_complex | f_complex (both) |
c = ak | c = imsl_fi_power(a,k) | float | float, int |
c = ab | c = imsl_ff_power(a,b) | float | float (both) |
m = jk | m = imsl_ii_power(j,k) | Int | int (both) |
Double-Precision Complex Operations and Functions
Operation | Function Name | Function Result | Function Argument(s) |
z = –x | z = imsl_z_neg(x) | d_complex | d_complex |
z = x + y | z = imsl_z_add(x,y) | d_complex | d_complex (both) |
z = x – y | z = imsl_z_sub(x,y) | d_complex | d_complex (both) |
z = x * y | z = imsl_z_mul(x,y) | d_complex | d_complex (both) |
z = x / y | z = imsl_z_div(x,y) | d_complex | d_complex (both) |
x==yb | z = imsl_z_eq(x,y) | Int | d_complex (both) |
z = x Drop Precision | z = imsl_zc_convert(x) | d_complex | f_complex |
z = a + ib Ascend Data | z = imsl_zd_convert(a,b) | d_complex | double (both) |
b Result has the value 1 if x and y are valid numbers with real and imaginary parts identical; otherwise, result has the value 0.
Operation | Function Name | Function Result | Function Argument(s) |
z = x | z = imsl_z_conjg(x) | d_complex | d_complex |
a = |z| | a = imsl_z_abs(z) | Double | d_complex |
a = arg (z) –π < a ≤ π | a = imsl_z_arg(z) | Double | d_complex |
| z = imsl_z_sqrt(z) | d_complex | d_complex |
z = cos (z) | z = imsl_z_cos(z) | d_complex | d_complex |
z = sin (z) | z = imsl_z_sin(z) | d_complex | d_complex |
z = exp (z) | z = imsl_z_exp(z) | d_complex | d_complex |
z = log (z) | z = imsl_z_log(z) | d_complex | d_complex |
z = xa | z = imsl_zd_power(x,a) | d_complex | d_complex, double |
z = xy | z = imsl_zz_power(x,y) | d_complex | d_complex (both) |
c = ak | c = imsl_di_power(a,k) | Double | double, int |
c = ab | c = imsl_dd_power(a,b) | Double | double (both) |
m = jk | m = imsl_ii_power(j,k) | Int | int (both) |
Example
The following sample code computes and prints several quantities associated with complex numbers. Note that the quantity
has a rounding error associated with it. Also the quotient z = (1 + 2i) / (3 + 4i) has a rounding error. The result is acceptable in both cases because the relative errors |w – (2 + 2i)|/ |w| and |z * (3 + 4i) – (1 + 2i)|/ |(1 + 2i)| are approximately the size of machine precision.
#include <imsl.h>
main()
{
f_complex x = {1,2};
f_complex y = {3,4};
f_complex z;
f_complex w;
int isame;
float eps = imsl_f_machine(4);
/* Echo inputs x and y */
printf("Data: x = (%g, %g)\n y = (%g, %g)\n\n",
x.re, x.im, y.re, y.im);
/* Add inputs */
z = imsl_c_add(x,y);
printf("Sum: z = x + y = (%g, %g)\n\n", z.re, z.im);
/* Compute square root of y */
w = imsl_c_sqrt(y);
printf("Square Root: w = sqrt(y) = (%g, %g)\n", w.re, w.im);
/* Check results */
z = imsl_c_mul(w,w);
printf("Check: w*w = (%g, %g)\n", z.re, z.im);
isame = imsl_c_eq(y,z);
printf(" y == w*w = %d\n", isame);
z = imsl_c_sub(z,y);
printf("Difference: w*w - y = (%g, %g) = (%g, %g) * eps\n\n",
z.re, z.im, z.re/eps, z.im/eps);
/* Divide inputs */
z = imsl_c_div(x,y);
printf("Quotient: z = x/y = (%g, %g)\n", z.re, z.im);
/* Check results */
w = imsl_c_sub(x, imsl_c_mul(z, y));
printf("Check: w = x - z*y = (%g, %g) = (%g, %g) * eps\n",
w.re, w.im, w.re/eps, w.im/eps);
}
Output
Data: x = (1, 2)
y = (3, 4)
Sum: z = x + y = (4, 6)
Square Root: w = sqrt(y) = (2, 1)
Check: w*w = (3, 4)
y == w*w = 0
Difference: w*w - y = (-2.38419e-07, 4.76837e-07) = (-2, 4) * eps
Quotient: z = x/y = (0.44, 0.08)
Check: w = x - z*y = (5.96046e-08, 0) = (0.5, 0) * eps