How to work with complex numbers in C? - c

How can I work with complex numbers in C? I see there is a complex.h header file, but it doesn't give me much information about how to use it. How to access real and imaginary parts in an efficient way? Is there native functions to get module and phase?

This code will help you, and it's fairly self-explanatory:
#include <stdio.h> /* Standard Library of Input and Output */
#include <complex.h> /* Standard Library of Complex Numbers */
int main() {
double complex z1 = 1.0 + 3.0 * I;
double complex z2 = 1.0 - 4.0 * I;
printf("Working with complex numbers:\n\v");
printf("Starting values: Z1 = %.2f + %.2fi\tZ2 = %.2f %+.2fi\n", creal(z1), cimag(z1), creal(z2), cimag(z2));
double complex sum = z1 + z2;
printf("The sum: Z1 + Z2 = %.2f %+.2fi\n", creal(sum), cimag(sum));
double complex difference = z1 - z2;
printf("The difference: Z1 - Z2 = %.2f %+.2fi\n", creal(difference), cimag(difference));
double complex product = z1 * z2;
printf("The product: Z1 x Z2 = %.2f %+.2fi\n", creal(product), cimag(product));
double complex quotient = z1 / z2;
printf("The quotient: Z1 / Z2 = %.2f %+.2fi\n", creal(quotient), cimag(quotient));
double complex conjugate = conj(z1);
printf("The conjugate of Z1 = %.2f %+.2fi\n", creal(conjugate), cimag(conjugate));
return 0;
}
with:
creal(z1): get the real part (for float crealf(z1), for long double creall(z1))
cimag(z1): get the imaginary part (for float cimagf(z1), for long double cimagl(z1))
Another important point to remember when working with complex numbers is that functions like cos(), exp() and sqrt() must be replaced with their complex forms, e.g. ccos(), cexp(), csqrt().

Complex types are in the C language since C99 standard (-std=c99 option of GCC). Some compilers may implement complex types even in more earlier modes, but this is non-standard and non-portable extension (e.g. IBM XL, GCC, may be intel,... ).
You can start from http://en.wikipedia.org/wiki/Complex.h - it gives a description of functions from complex.h
This manual http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html also gives some info about macros.
To declare a complex variable, use
double _Complex a; // use c* functions without suffix
or
float _Complex b; // use c*f functions - with f suffix
long double _Complex c; // use c*l functions - with l suffix
To give a value into complex, use _Complex_I macro from complex.h:
float _Complex d = 2.0f + 2.0f*_Complex_I;
(actually there can be some problems here with (0,-0i) numbers and NaNs in single half of complex)
Module is cabs(a)/cabsl(c)/cabsf(b); Real part is creal(a), Imaginary is cimag(a). carg(a) is for complex argument.
To directly access (read/write) real an imag part you may use this unportable GCC-extension:
__real__ a = 1.4;
__imag__ a = 2.0;
float b = __real__ a;

For convenience, one may include tgmath.h library for the type generate macros. It creates the same function name as the double version for all type of variable. For example, For example, it defines a sqrt() macro that expands to the sqrtf() , sqrt() , or sqrtl() function, depending on the type of argument provided.
So one don't need to remember the corresponding function name for different type of variables!
#include <stdio.h>
#include <tgmath.h>//for the type generate macros.
#include <complex.h>//for easier declare complex variables and complex unit I
int main(void)
{
double complex z1=1./4.*M_PI+1./4.*M_PI*I;//M_PI is just pi=3.1415...
double complex z2, z3, z4, z5;
z2=exp(z1);
z3=sin(z1);
z4=sqrt(z1);
z5=log(z1);
printf("exp(z1)=%lf + %lf I\n", creal(z2),cimag(z2));
printf("sin(z1)=%lf + %lf I\n", creal(z3),cimag(z3));
printf("sqrt(z1)=%lf + %lf I\n", creal(z4),cimag(z4));
printf("log(z1)=%lf + %lf I\n", creal(z5),cimag(z5));
return 0;
}

The notion of complex numbers was introduced in mathematics, from the need of calculating negative quadratic roots. Complex number concept was taken by a variety of engineering fields.
Today that complex numbers are widely used in advanced engineering domains such as physics, electronics, mechanics, astronomy, etc...
Real and imaginary part, of a negative square root example:
#include <stdio.h>
#include <complex.h>
int main()
{
int negNum;
printf("Calculate negative square roots:\n"
"Enter negative number:");
scanf("%d", &negNum);
double complex negSqrt = csqrt(negNum);
double pReal = creal(negSqrt);
double pImag = cimag(negSqrt);
printf("\nReal part %f, imaginary part %f"
", for negative square root.(%d)",
pReal, pImag, negNum);
return 0;
}

To extract the real part of a complex-valued expression z, use the notation as __real__ z.
Similarly, use __imag__ attribute on the z to extract the imaginary part.
For example;
__complex__ float z;
float r;
float i;
r = __real__ z;
i = __imag__ z;
r is the real part of the complex number "z"
i is the imaginary part of the complex number "z"

Related

How to assign real and imaginary parts of complex variables in C

Using the complex number type of the C99 standard, how does one assign the real and imaginary parts of a variable individually? I found the GNU extension __real__ and __imag__ will do it, as in the following example program. But this isn't portable or standard. How can one do this portably?
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
int
main()
{
complex double z;
__real__ z = 3.0;
__imag__ z = 2.0;
fprintf(stderr, "z = %f + i %f\n", creal(z), cimag(z));
return 0;
}
C 2018 6.2.5 13 implies we can treat complex number as an array of two elements:
Each complex type has the same representation and alignment requirements as an array type containing exactly two elements of the corresponding real type; the first element is equal to the real part, and the second element to the imaginary part, of the complex number.
This is crude wording, at odds with the explicitly stated aliasing rules in 6.5 7, but the standard is imperfect, and footnotes 41 and 49, about integers and pointers, suggest such statements about representation and alignment are supposed to allow some use of one view of the object for another in spite of the rules in 6.5 7. If so, we can define macros:
#define Re(x) (_Generic((x), \
complex float : ((float *) &(x)), \
complex double : ((double *) &(x)), \
complex long double : ((long double *) &(x)))[0])
#define Im(x) (_Generic((x), \
complex float : ((float *) &(x)), \
complex double : ((double *) &(x)), \
complex long double : ((long double *) &(x)))[1])
after which Re(x) and Im(x), when given a complex object, produce an lvalue for the real or imaginary part. So we can assign them:
Re(x) = 3;
Im(x) = 4;
How can one do this portably?
It's just... addition:
z = 3.0;
z += I * 2.0;
You could first zero the imaginary part, if you want to:
z = creal(z) + I * 2.0;
how does one assign the real and imaginary parts of a variable
individually?
// assign real
z = new_value + I * cimag(z);
// assign imaginary
z = creal(z) + I * new_value;
One could prefer _Imaginary_I or CMPLXF macros over I.
I found another possible solution. The code below assumes that complex double is bit-equivalent to double[2] (which I think is correct but would appreciate a verification!). I think the solution below may be more efficient since it doesn't involve an extra addition operation for each assignment (as does KamilCuk's solution).
If anyone can verify this is will be portable to all platforms, I would appreciate it.
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#define SET_REAL(z, x) ( *((double *) &(z)) = (x) )
#define SET_IMAG(z, x) ( *(((double *) &(z)) + 1) = (x) )
int
main()
{
complex double z;
SET_REAL(z, 3.0);
SET_IMAG(z, 2.0);
fprintf(stderr, "z = %f + i %f\n", creal(z), cimag(z));
return 0;
}

Why do the results of my program to find the coordinates of an arc or circle in C differ from the 'correct' results?

I am a real beginner here and I'm really not sure about this. It is a homework assignment.
We have to find 10 (x,y) coordinates of an arc using the radius, a starting angle and an end angle. The program works, but the results it gives differ very slightly from the 'correct' results as required by the automatic checking system. Here's the code and both mine and the systems results based on r=100, angle1=1, anglef=30!
Thanks in advance!
FILE *pf1;
int n=0;
double angulo1, angulof, angulo, radio, x, y;
printf ("\nIntroduce radio : ");
scanf ("%lf", &radio);
printf ("\nIntroduce angulo inicial : ");
scanf ("%lf", &angulo1);
printf ("\nIntroduce angulo final : ");
scanf ("%lf", &angulof);
angulo = ((angulof-angulo1)/9);
pf1 = fopen("salida.txt", "w");
for (n=0; n<=9; n++)
{
x=radio*cos(angulo1+(angulo*n));
y=radio*sin(angulo1+(angulo*n));
fprintf (pf1, "%lf,%lf\n", x,y);
}
return 0;
.
ERROR
■■■ MY FILE:
54.030231,84.147098
-41.614684,90.929743
-98.999250,14.112001
-65.364362,-75.680250
28.366219,-95.892427
96.017029,-27.941550
75.390225,65.698660
-14.550003,98.935825
-91.113026,41.211849
-83.907153,-54.402111
■■■ CORRECT FILE:
54.030231,84.147095
-41.614685,90.929741
-98.999252,14.112000
-65.364365,-75.680252
28.366219,-95.892426
96.017029,-27.941549
75.390228,65.698662
-14.550003,98.935822
-91.113029,41.211849
-83.907150,-54.402111
The post is very confusing:
Calculating angles from 1 to 30 radians in 10 steps doesn't make much sense. Sensible values for radians are from -2π to +2π, outside that range trigonomic functions quickly lose precision. Also, making steps that are much larger than a few degrees is very unusual. To get from 1 to 30 radians in 10 steps, steps of almost 180° are taken.
Some testing of the output reveals that the steps are smaller: from 1 to 10 radians in 10 steps. This is still 57° per step, and goes almost 2 times around the circle.
Reverse engineering the output with atan2(y,x) reveals that the desired output is less precise than the calculation with doubles. So, probably the calculations used 32 bit floats. To test this, one has to be very careful. Internally, floats can get passed as doubles, and the processor works with 80 bits of precision for arithmetic calculations. (Note that on most machines long double has the same precision as double.)
Now, if you call sin on a float, the compiler often calls the double version of sin. To force the float version, one can try to explicitly call them, they have an f appended to the function name: sinf and cosf.
Testing the following with MicroSoft Visual C, 2017 community edition:
#include <math.h>
void test_sinf()
{
float radio = 100;
float angulo1 = 1;
float angulof = 10;
float angulo = (angulof - angulo1) / 9;
float x, y;
int n;
for (n = 0; n < 10; ++n) {
x = radio * cosf(angulo1 + (angulo*n));
y = radio * sinf(angulo1 + (angulo*n));
printf("%.6lf,%.6lf\n", x, y);
}
}
outputs:
54.030228, 84.147095
-41.614685, 90.929741
-98.999252, 14.112000
-65.364365, -75.680252
28.366220, -95.892426
96.017029, -27.941549
75.390228, 65.698662
-14.550003, 98.935822
-91.113022, 41.211849
-83.907150, -54.402115
This leaves the last digit of only 4 of the numbers with a difference. Which suggests a slightly different library/compiler has been used. As the angles and the radius are all integer numbers which can be represented exact with floats, they are an unprobable cause of the differences.
edit: Testing out the suggestion of #gnasher729 is seems he's right. Running the code with the double precision sin and cos, and convering the result to float before printing, gives exactly the "desired" numbers. This probably gives the same results on most compilers for this test case. (32 bit floats are an IEEE standard, and 64 bit trigonomic functions have enough precision to make implementation details disappear after rounding.)
#include <math.h>
void test_sin_converted_to_float()
{
float radio = 100;
float angulo1 = 1;
float angulof = 10;
float angulo = (angulof - angulo1) / 9;
float x, y;
for (int n = 0; n <= 9; ++n) {
x = radio * cos(angulo1 + (angulo*n));
y = radio * sin(angulo1 + (angulo*n));
printf("%.6lf, %.6lf\n", x, y);
}
}
Checking your data with a spreadsheet, it contains exactly what it ought to contain. The data in the second file however look like sine and cosine where calculated with single precision (float).
Which would mean that whoever created this "automatic checking" should be very, very, ashamed of themselves.

How to compute a cubic root of a complex number in C?

As the name suggested, I'd like to compute cubic roots of a complex number in C. cbrt doesn't work.
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <cmath.h>
int main(){
double complex x, z = 1+2*I;
x = cbrt(z);
printf("z is %f + %fi \n", creal(z), cimag(z));
printf("x is %f + %fi \n", creal(x), cimag(x));
return(0);
}
The output is as follows.
z is 1.000000 + 2.000000i
x is 1.000000 + 0.000000i
cbrt doesn't work.
That function works on real values. #squeamish ossifrage
x is 1.000000 + 0.000000i is a reasonable result.
double cbrt(double x);
The cbrt functions compute the real cube root of x. C11dr §7.12.7.1 2
A good compiler with warnings fully enabled with report on the following. Save time, enable all compiler warnings.
// warning expected such as:
// warning: conversion to 'long double' from 'complex double' discards imaginary component [-Wconversion]
x = cbrt(z);
How to compute a cubic root of a complex number in C?
<cmath.h> is not part of the C standard library. Its role here is unclear.
Code can use double complex cpow(double complex, double complex);
x = cpow(z, 1.0/3.0);
...
// Ouptut
// x is 1.219617 + 0.471711i
I do not find a double complex ccbrt(double complex); in the standard library nor access to one via type-generic math <tgmath.h>.
... to compute cubic roots ...
Emphasis on plural "roots" here: to compute all 'n' roots:
int n = 3;
const double complex two_pi_i = 2.0 * asin(-1.0) * I;
double complex rotate = cexp(two_pi_i / n);
x = cpow(z, 1.0 / 3.0);
for (int k = 0; k < n; k++) {
printf("x[%d] is % f + % fi \n", k, creal(x), cimag(x));
x *= rotate;
}
Output
x[0] is 1.219617 + 0.471711i
x[1] is 1.018322 + -0.820363i
x[2] is -0.201294 + -1.292075i
I would look at this answer from the Mathematics Stack Exchange.
Essentially you want to compute the radius and angle of the Eurler formula. Then divide both the radius and angle by three (see link). So first you need to convert your complex number to Euler format. I don't have time now to figure that out, but maybe this gave you an idea at where to look.
Hope this helps!
Addition: #squeamish probably has a better idea with cpow, but as he mentioned this will only return one of the roots.

How to pass infinity values to a function and test the result

I have this function:
#include <complex.h>
complex double f(complex double x, complex double y) {
return x*y;
}
I would like to call it with x = inf + i inf and y = i inf and see what the result is. In particular I want to test if the result is an infinity value (as it should be) or if it is NaN + iNaN. The reason for this is to test different C compilers.
How do you do this in C?
I would add an intermediate check, too:
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <math.h>
complex double f(complex double x, complex double y) {
return x*y;
}
int main(void){
complex double x = INFINITY + INFINITY * I;
complex double y = 0.0 + INFINITY * I;
complex double ret;
printf("x = %g + %g*I\n", creal(x), cimag(x));
printf("y = %g + %g*I\n", creal(y), cimag(y));
ret = f(x,y);
printf("f = %g + %g*I\n", creal(ret), cimag(ret));
exit(EXIT_SUCCESS);
}
Why?
Result with gcc-4.9.real (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4
x = nan + inf*I
y = nan + inf*I
f = -inf + -nan*I
Result with Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
x = nan + inf*I
y = nan + inf*I
f = nan + nan*I
A complete and utter failure from the get go.
I'm not 100% sure this is correct since I've never worked with complex numbers in C, but I've tried this snippet:
#include <stdio.h>
#include <math.h>
#include <complex.h>
double complex f(double complex x, double complex y) {
return x*y;
}
int main(void)
{
double complex z1 = INFINITY + INFINITY * I;
double complex z2 = INFINITY + INFINITY * I;
complex double result = f(z1, z2);
printf("%f + i%f\n", creal(result), cimag(result));
}
I used both clang 3.8 (C 11) and GCC 6.1 (C 11) and the result was:
-inf + i-nan
Based on http://en.cppreference.com/w/c/numeric/math/INFINITY.
Apparently the macro INFINITY is not always supported and thus defined. Check the link above for more info.
You can specify what is basically a complex literal using multiplication with the I macro (which also has a _Complex_I alias). A minor example creating such a value is seen below:
#include <math.h>
#include <complex.h>
int main()
{
complex c = INFINITY * I + INFINITY;
}
The function, as written, is fine, the problem is with the way the complex numbers with special values are created and interpreted.
If you just write
double complex z1 = I * INFINITY;
double complex z2 = INFINITY + I * INFINITY;
you may discover that most of the popular compilers today do not support C99's imaginary numbers, and this expression actually multiplies (0,1) by (inf,0) and then adds (inf,0) to the result.
With gcc, I get z1 = (nan, inf), z2 = (nan, inf), f(z1,z2) = (-inf, -nan)
with clang, I get z1 = (nan, inf), z2 = (nan, inf), f(z1,z2) = (-inf, -nan)
with icc, I get z1 = (-nan, inf), z2 = (-nan, inf), f(z1, z2) = (-nan, -nan)
The only compiler that defines I as a pure imaginary number that I have access to is the C compiler from Oracle Studio
with oracle studio, I get z1 = (0, inf), z2 = (inf, inf), f(z1,z2) = (-inf, inf)
Now this is not actually supposed to be a problem because in C, there is only one Complex Infinity, and every complex number whose one component is infinite is considered to be that infinity, even if the other component is NaN. All built-in arithmetic is supposed to honor that: so in my list above, only Intel appears to have a bug here where multiplication of two complex infinities gave a complex nan.
For the lazy compilers, C11 has a macro that saves the day: CMPLX
double complex z1 = CMPLX(0, INFINITY);
double complex z2 = CMPLX(INFINITY, INFINITY);
now,
with gcc, I get z1 = (0, inf), z2 = (inf, inf), f(z1,z2) = (-inf, inf)

How to create a complex type of a existing function?

I am just beginning C programming (not C++) and I have to convert the quadratic formula for adressing complex roots, and for printing these. The normal quadratic equation is as follows (for discriminant > 0):
else {
/* */
x1 = ((-b) + sqrt(discr)) / (2 * a);
x2 = ((-b) - sqrt(discr)) / (2 * a);
printf("%s%.4lf%s%.4lf\n\n", "x1: ", x1, "\tx2: ", x2);
}
When I try to convert this into its complex values I have used the following strategies:
Creating a new version of the result of the sqrt(discr), the complex part in the equation, by creating a variable _Complex double discr_complex = discr * I.
-> OR discr_complex = discr + discr * I.
Making x1 and x2 complex by 'complex x1' or '_Complex c1' or 'complex x1 = ..formula.. * I' or '_Complex x1 = ...formula * I'.
Making every part complex by using the keyword complex.
For all these versions it does not print the correct complex output (#+#i). I tried printing the normal values, which works, but not for the complex part. I tried using the methods creal(x1) and cimag(x1) which do not work (undeclared reference to creal / cimag), or x1.real() / x1.imag(), which also doesn't work ('imag' in something not a structure or union).
Does anybody maybe know how to convert my x1 and x2 values into complex numbers, with maybe a clear explanation how to return each seperate part of the complex equation (real/imaginary) and how this conversion takes place taken my 'normal' formula?
The reason that calling creal does not work is that either you have not included the proper header complex.h or you are calling it with an argument x1 that is not of the correct type double complex. The second error, when you call x1.real() is because the . notation tries to access a member of a struct but x1 is a double.
I suggest using complex.h that enables working with complex numbers and define a new abc-formula that deals with complex numbers. Also note that you can not use 'regular' math functions like sqrt on variables of complex type but need to use the complex.h analogs e.g. csqrt()
#include <complex.h>
int main(void)
{
double complex z = 1.0 + 0.5 * I;
printf("The real part of z = %f\n", creal(z));
printf("The iamginary part of z = %f\n", cimag(z));
return 0;
}
Edit:
completely redefine your function, try something like this:
void complex_abc() {
double complex a = 1;
double complex b = 2;
double complex c = 3;
double complex x1;
double complex x2;
double complex d;
d = b*b - 4 * a * c;
x1 = ( -b + csqrt(d) ) / 2*a;
x2 = ( -b - csqrt(d) ) / 2*a;
printf("x1 = %f + i %f\n", creal(x1), cimag(x1));
printf("x2 = %f + i %f\n", creal(x2), cimag(x2));
return;
}
And as correctly noted by #Lutzl in the comments you need to link the math library with the flag -lm during compiling

Resources