Jak pracować z liczbami zespolonymi w C?

122

Jak mogę pracować z liczbami zespolonymi w C? Widzę, że istnieje complex.hplik nagłówkowy, ale nie zawiera on zbyt wielu informacji o tym, jak go używać. Jak efektywnie uzyskać dostęp do rzeczywistych i wyimaginowanych części? Czy istnieją natywne funkcje do pobrania modułu i fazy?

Charles Brunet
źródło
16
Używam języka C zamiast C ++, ponieważ łatwiej jest powiązać z moim kodem w języku Python.
Charles Brunet

Odpowiedzi:

186

Ten kod ci pomoże i jest dość zrozumiały:

#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;
}

  z:

creal(z1): zdobądź prawdziwą część (dla float crealf(z1), dla długiego double creall(z1))

cimag(z1): pobierz część urojoną (dla float cimagf(z1), dla długiego double cimagl(z1))

Innym ważnym punktem pamiętać podczas pracy z liczb zespolonych jest to, że funkcje takie jak cos(), exp()i sqrt()muszą być zastępowane ich złożonych form, na przykład ccos(), cexp(), csqrt().

Shelvacu
źródło
12
Co to jest double complex? Czy to rozszerzenie języka, czy jakaś magia makr?
Calmarius
@Calmarius complexto standardowy typ c99 (pod maską w GCC jest to właściwie alias do typu _Complex).
Snaipe
9
@Snaipe: complexnie jest typem. Jest to makro, które rozwija się do _Complex, które jest specyfikatorem typu , ale nie jest typem samym w sobie. Złożone typy float _Complex, double _Complexi long double _Complex.
Keith Thompson
3
To nie tylko GCC, jest zdefiniowane w standardzie, że _Complex jest specyfikatorem typu i złożonym. H ma złożone makro, które rozwija się do _Complex. To samo dotyczy _Bool i stdbool.h.
jv110
40

Typy złożone są w języku C od standardu C99 ( -std=c99opcja GCC). Niektóre kompilatory mogą implementować złożone typy nawet we wcześniejszych trybach, ale jest to niestandardowe i nieprzenośne rozszerzenie (np. IBM XL, GCC, może być intel, ...).

Możesz zacząć od http://en.wikipedia.org/wiki/Complex.h - zawiera opis funkcji z complex.h

Ten podręcznik http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html również zawiera informacje o makrach.

Aby zadeklarować zmienną złożoną, użyj

  double _Complex  a;        // use c* functions without suffix

lub

  float _Complex   b;        // use c*f functions - with f suffix
  long double _Complex c;    // use c*l functions - with l suffix

Aby nadać wartość złożonemu, użyj _Complex_Imakra z complex.h:

  float _Complex d = 2.0f + 2.0f*_Complex_I;

(właściwie mogą tu występować problemy z (0,-0i)liczbami i NaN w jednej połowie złożonej)

Moduł to cabs(a)/ cabsl(c)/ cabsf(b); Prawdziwą częścią jest creal(a)wyobrażenie cimag(a). carg(a)służy do złożonych argumentów.

Aby uzyskać bezpośredni dostęp (odczyt / zapis) do rzeczywistej części obrazu , możesz użyć tego nieporęcznego rozszerzenia GCC :

 __real__ a = 1.4;
 __imag__ a = 2.0;
 float b = __real__ a;
osgx
źródło
1
prawie każda złożona funkcja zostanie zaimplementowana przez kompilator jako funkcja wbudowana w efektywny sposób. Po prostu użyj nowoczesnego kompilatora i nadaj mu niezerowy poziom optymalizacji.
osgx
3
Do Twojej wiadomości, ponieważ OP wspomina o powiązaniach Pythona, podczas pracy z Pythonem staram się trzymać C89 (ponieważ reszta kodu Pythona to C89, a jeśli chcesz, aby twoje rozszerzenie działało w systemie Windows, zwykle jest kompilowane za pomocą MVSC, co jest ograniczone do C89). Nie wiem, czy to absolutnie konieczne.
detly
1
Wyrażenia (complex float) { r, i }można również użyć do ustawienia oddzielnych części liczby i niezależnie (na przykład część rzeczywista to INF, podczas gdy część urojoną to NAN). Pozwala to uniknąć słowa kluczowego specyficznego dla GCC, chociaż nie jestem pewien, czy rzeczywiście jest przenośny.
cleong
2
Zauważ, że obsługa złożona jest opcjonalna w C99: kompilatory mogą po prostu jej nie mieć, jeśli zdefiniują __STDC_NO_COMPLEX__. W praktyce jest jednak zaimplementowany na głównych kompilatorach.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Jasen, sprawdź stronę 182 szkicu N1256 open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Złożona arytmetyka <complex.h>". Takie słowo kluczowe zostało prawdopodobnie wybrane w C99, aby nie przerywać istniejących programów c (C90), które implementują złożone ręcznie. Jeśli dołączono <complex.h>, complexzostanie zdefiniowany jako makro, rozszerzony do _Complex. Możesz być także zainteresowany "The New C Standard: An Economic and Cultural Commentary" (2008) strona 500 "złożone typy" people.ece.cornell.edu/land/courses/ece4760/…
osgx
9

Complex.h

#include <stdio.h>      /* Standard Library of Input and Output */
#include <complex.h>    /* Standart 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));
}
złożony
źródło
4

Dla wygody można dołączyć tgmath.hbibliotekę dla typu generującego makra. Tworzy tę samą nazwę funkcji co podwójna wersja dla wszystkich typów zmiennych. Na przykład, na przykład, definiuje sqrt()makro, która rozciąga się na sqrtf(), sqrt()lub sqrtl()funkcji, w zależności od rodzaju argumentu usług.

Nie trzeba więc pamiętać odpowiedniej nazwy funkcji dla różnych typów zmiennych!

#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;
}
oferta nie może odrzucić
źródło
2

Pojęcie liczb zespolonych zostało wprowadzone do matematyki z potrzeby obliczania ujemnych pierwiastków kwadratowych. Złożona koncepcja liczbowa została podjęta w różnych dziedzinach inżynierii.

Dziś te liczby zespolone są szeroko stosowane w zaawansowanych dziedzinach inżynierii, takich jak fizyka, elektronika, mechanika, astronomia itp.

Część rzeczywista i urojona ujemnego pierwiastka kwadratowego:

#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;
}
LXSoft
źródło
-1

Aby wyodrębnić część rzeczywistą wyrażenia o wartościach zespolonych z, użyj notacji as __real__ z. Podobnie użyj __imag__atrybutu w, zaby wyodrębnić część urojoną.

Na przykład;

__complex__ float z;
float r;
float i;
r = __real__ z;
i = __imag__ z;

r jest częścią rzeczywistą liczby zespolonej „z” i jest częścią urojoną liczby zespolonej „z”

cyklop
źródło
2
Są to rozszerzenia specyficzne dla gcc. Inna odpowiedź już o nich wspomniała, a zaakceptowana już odpowiedź jak to zrobić w standardzie C.
Keith Thompson