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.
Related
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.
I want to create a program that use decimal numbers, so I thought I would need to use float types, but I don't understand how these types behave. I made a test:
#include <stdio.h>
#include <float.h>
int main(void)
{
float fl;
fl = 5 - 100000000;
printf("%f\n", fl);
fl = FLT_MAX - FLT_MAX * 2;
printf("%f\n", fl);
fl = -100000000000000;
printf("%f\n", fl);
return 0;
}
Output:
-99999992.000000 // I expected it to be -99999995.000000
-inf // I expected it to be -340282346638528859811704183484516925440.000000
-100000000376832.000000 // I expected it to be -100000000000000
Why are the results different of my expectations?
EDIT: Thank's to people who don't just downvote my question for some reasons, and actually try to help me. However, what I could learn in this thread doesn't help me understanding why some float variables containing integers (ending with .000000) behaves strangely.
I'm not sure, but I have some ideas.
In float numbers any number consists of 2 parts: m,p. Any number can be shown as:
X = m * 2^p. (m and p - binary. 0< m <1)
So, if you try to do some calculations with numbers(X+Y), firstly computer needs to represent X and Y with the same p.
Simple example (not like in program, but like people could do the same):
X=0.5, Y=1.45
0.55+1.45
0.55 * 10^0 + 0.145 * 10^1
0.055 * 10^1 + 0.145 * 10^1 (*)
0.200 * 10^1
BUT. If X and Y has too different p we have some problems in (*) line. m has limited number of digits, so:
Ex.:
X = 0.1, Y = 0.000000000000000001
X + Y = 0.100000000000(000001) <- this part didn't fit into m, so
X + Y = 0.1.
Hope you got what I wanted to say
I've created a function to compute cosine based on taylor serie ,
only to encounter a precision problem when comparing it with the standard library cosine.
for example,computing 23 my cos gives:
-0.532834
and the standard library gives:
-0.532833
I've been searching the web,and trying to figure it myself but just couldn't figure what the problem is!
when increasing the treashould to be 1.0e-7,the problem is solved.
but it should work well for 1.0e-6 as well(as it worked for my friends)
would appreciate any insight,thanks ahead.
#define PI 3.14159265358979323846264338327950288419716
double my_cos(double rad){
int i = 0;
double numer = 1, denom = 1;
double x2, cos = 0;
rad = fmod(fabs(rad),2*PI);
x2 = pow(rad,2);
do{
cos += pow(-1,i)*(numer/denom);
i++;
numer *= x2;
denom *= (2*i)*(2*i-1);
} while (numer/denom>1.0e-6);
return cos ;
}
The rounding happens when you call printf
This
printf("%f\n", my_cos(23));
printf("%f\n", cos(23));
will print
-0.532834
-0.532833
which seems "wrong".
But
if you increase the number of digits print like
printf("%0.12f\n", my_cos(23));
printf("%0.12f\n", cos(23));
it will print
-0.532833931872
-0.532833020333
So you have the precision you want. It's just the printing that makes it look as if something is wrong.
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
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"