Come lavorare con numeri complessi in C?


122

Come posso lavorare con numeri complessi in C? Vedo che c'è un complex.hfile di intestazione, ma non mi dà molte informazioni su come usarlo. Come accedere in modo efficiente a parti reali e immaginarie? Esistono funzioni native per ottenere modulo e fase?


16
Sto usando C invece di C ++ perché è più facile collegarsi al mio codice Python.
Charles Brunet

Risposte:


186

Questo codice ti aiuterà ed è abbastanza autoesplicativo:

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

  con:

creal(z1): ottieni la parte reale (per float crealf(z1), per long double creall(z1))

cimag(z1): ottieni la parte immaginaria (per float cimagf(z1), per long double cimagl(z1))

Un altro punto importante da ricordare quando si lavora con numeri complessi è che funzioni come cos(), exp()e sqrt()deve essere sostituito con le loro forme complesse, per esempio ccos(), cexp(), csqrt().


12
Cos'è questo double complex? È un'estensione del linguaggio o qualche macro magia?
Calmarius

@Calmarius complexè un tipo c99 standard (sotto il cofano su GCC, in realtà è un alias per il tipo _Complex).
Snaipe

9
@Snaipe: complexnon è un tipo. È una macro che si espande in _Complex, che è un identificatore di tipo , ma non un tipo a sé stante. I tipi complessi sono float _Complex, double _Complexe long double _Complex.
Keith Thompson

3
Non è solo GCC, è definito nello standard che _Complex è un identificatore di tipo e complex.h ha una macro complessa che si espande in _Complex. Lo stesso vale per _Bool e stdbool.h.
jv110

40

I tipi complessi sono in linguaggio C dallo standard C99 ( -std=c99opzione di GCC). Alcuni compilatori possono implementare tipi complessi anche in modalità più precedenti, ma questa è un'estensione non standard e non portabile (ad esempio IBM XL, GCC, potrebbe essere Intel, ...).

Puoi iniziare da http://en.wikipedia.org/wiki/Complex.h - fornisce una descrizione delle funzioni da complex.h

Questo manuale http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html fornisce anche alcune informazioni sulle macro.

Per dichiarare una variabile complessa, utilizzare

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

o

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

Per dare un valore a complesso, usa la _Complex_Imacro da complex.h:

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

(in realtà qui possono esserci dei problemi con (0,-0i)numeri e NaN nella singola metà del complesso)

Il modulo è cabs(a)/ cabsl(c)/ cabsf(b); La parte reale è creal(a), l'immaginario è cimag(a). carg(a)è per argomenti complessi.

Per accedere direttamente (lettura / scrittura) alla parte reale e dell'immagine puoi utilizzare questa estensione GCC non portatile :

 __real__ a = 1.4;
 __imag__ a = 2.0;
 float b = __real__ a;

1
quasi ogni funzione complessa sarà implementata dal compilatore come funzione incorporata in modo efficiente. Basta usare il compilatore moderno e dargli un livello di ottimizzazione diverso da zero.
osgx

3
Cordiali saluti, dal momento che l'OP menziona i collegamenti Python, quando lavoro con Python cerco di attenermi a C89 (poiché il resto del codice di Python è C89 e se vuoi che la tua estensione funzioni su Windows, di solito è compilata con MVSC, che è limitato a C89). Non so se sia strettamente necessario però.
Detly

1
L'espressione (complex float) { r, i }può anche essere utilizzata per impostare le parti separate del numero e in modo indipendente (consentendo alla parte reale di essere INF mentre la parte immaginaria è NAN, per esempio). Ciò evita la parola chiave specifica di GCC, anche se non sono sicuro che sia effettivamente portabile.
Cleong

2
Nota che il supporto Complex è opzionale in C99: i compilatori potrebbero semplicemente non averlo se definiscono __STDC_NO_COMPLEX__. In pratica, tuttavia, è implementato sui principali compilatori.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
Jasen, controlla la pagina 182 della bozza N1256 di open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Aritmetica complessa <complex.h>". Tale parola chiave è stata probabilmente selezionata in C99 per non interrompere i programmi c (C90) esistenti che implementano manualmente complessi. Se <complex.h> è incluso, complexsarà definito come macro, espanso a _Complex. Potresti anche essere interessato a "The New C Standard: An Economic and Cultural Commentary" (2008) di Derek M. Jones a pagina 500 "tipi complessi" 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));
}

4

Per comodità, si può includere una tgmath.hlibreria per il tipo di macro generate. Crea lo stesso nome di funzione della versione doppia per tutti i tipi di variabili. Ad esempio, per esempio, si definisce una sqrt()macro che si espande al sqrtf(), sqrt()o sqrtl()funzione, a seconda del tipo di argomento fornito.

Quindi non è necessario ricordare il nome della funzione corrispondente per diversi tipi di variabili!

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

2

La nozione di numeri complessi è stata introdotta in matematica, dalla necessità di calcolare radici quadratiche negative. Il concetto di numero complesso è stato adottato da una varietà di campi dell'ingegneria.

Oggi quei numeri complessi sono ampiamente utilizzati in domini di ingegneria avanzata come fisica, elettronica, meccanica, astronomia, ecc ...

Parte reale e immaginaria, di un esempio di radice quadrata negativa:

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

-1

Per estrarre la parte reale di un'espressione con valori complessi z, utilizzare la notazione come __real__ z. Allo stesso modo, usa l' __imag__attributo su zper estrarre la parte immaginaria.

Per esempio;

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

r è la parte reale del numero complesso "z" i è la parte immaginaria del numero complesso "z"


2
Queste sono estensioni specifiche di gcc. Un'altra risposta li ha già menzionati e la risposta accettata già come farlo nello standard C.
Keith Thompson,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.