Wie arbeite ich mit komplexen Zahlen in C?


122

Wie kann ich mit komplexen Zahlen in C arbeiten? Ich sehe, dass es eine complex.hHeader-Datei gibt, aber sie gibt mir nicht viele Informationen darüber, wie man sie verwendet. Wie kann man effizient auf Real- und Imaginärteile zugreifen? Gibt es native Funktionen, um Modul und Phase abzurufen?


16
Ich verwende C anstelle von C ++, weil es einfacher ist, an meinen Python-Code zu binden.
Charles Brunet

Antworten:


186

Dieser Code hilft Ihnen und ist ziemlich selbsterklärend:

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

  mit:

creal(z1): Holen Sie sich den Realteil (für Float crealf(z1), für Long Double creall(z1))

cimag(z1): Holen Sie sich den Imaginärteil (für Float cimagf(z1), für Long Double cimagl(z1))

Ein weiterer wichtiger Punkt zu erinnern , wenn mit komplexen Zahlen arbeiten , ist , dass Funktionen wie cos(), exp()und sqrt()müssen mit ihren komplexen Formen ersetzt werden, zum Beispiel ccos(), cexp(), csqrt().


12
Was ist das double complex? Ist das eine Spracherweiterung oder eine Makromagie?
Calmarius

@Calmarius complexist ein Standard-c99-Typ (unter der Haube von GCC ist es tatsächlich ein Alias ​​für den _Complex-Typ).
Snaipe

9
@Snaipe: complexist kein Typ. Es ist ein Makro , das sich ausdehnt auf _Complex, die eine Art ist Spezifizierer , aber nicht eine Art von selbst aus . Die komplexen Typen sind float _Complex, double _Complexund long double _Complex.
Keith Thompson

3
Es ist nicht nur GCC, es ist im Standard definiert, dass _Complex ein Typspezifizierer ist und complex.h ein komplexes Makro hat, das zu _Complex erweitert wird. Gleiches gilt für _Bool und stdbool.h.
jv110

40

Komplexe Typen sind seit dem C99-Standard in der Sprache C ( -std=c99Option von GCC). Einige Compiler implementieren möglicherweise komplexe Typen auch in früheren Modi, dies ist jedoch eine nicht standardmäßige und nicht portable Erweiterung (z. B. IBM XL, GCC, möglicherweise Intel, ...).

Sie können von http://en.wikipedia.org/wiki/Complex.h ausgehen - es enthält eine Beschreibung der Funktionen von complex.h

Dieses Handbuch http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html enthält auch einige Informationen zu Makros.

Verwenden Sie, um eine komplexe Variable zu deklarieren

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

oder

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

Verwenden Sie ein _Complex_IMakro aus complex.h:

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

( (0,-0i)Tatsächlich kann es hier einige Probleme mit Zahlen und NaNs in einer Hälfte des Komplexes geben.)

Modul ist cabs(a)/ cabsl(c)/ cabsf(b); Realteil ist creal(a), imaginär ist cimag(a). carg(a)ist für komplexe Argumente.

Um direkt auf ein Bildteil zuzugreifen (lesen / schreiben), können Sie diese nicht portierbare GCC-Erweiterung verwenden :

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

1
Fast jede komplexe Funktion wird vom Compiler effizient als eingebaute Funktion implementiert. Verwenden Sie einfach einen modernen Compiler und optimieren Sie ihn ungleich Null.
Osgx

3
Zu Ihrer Information, da das OP Python-Bindungen erwähnt, versuche ich bei der Arbeit mit Python, mich an C89 zu halten (da der Rest des Python-Codes C89 ist und wenn Sie möchten, dass Ihre Erweiterung unter Windows ausgeführt wird, wird sie normalerweise mit MVSC kompiliert, das auf beschränkt ist C89). Ich weiß nicht, dass es unbedingt notwendig ist.
Detly

1
Der Ausdruck (complex float) { r, i }kann auch verwendet werden, um die einzelnen Teile der Zahl unabhängig voneinander festzulegen (so dass der Realteil INF sein kann, während der Imaginärteil beispielsweise NAN ist). Dadurch wird das GCC-spezifische Schlüsselwort vermieden, obwohl ich nicht sicher bin, ob es tatsächlich portabel ist.
Cleong

2
Beachten Sie, dass die komplexe Unterstützung in C99 optional ist: Compiler verfügen möglicherweise nicht über diese Unterstützung, wenn sie diese definieren __STDC_NO_COMPLEX__. In der Praxis ist es jedoch auf großen Compilern implementiert.
Ciro Santilli 法轮功 冠状 病 六四 事件 17

1
Jasen, siehe Seite 182 des N1256-Entwurfs open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Komplexe Arithmetik <complex.h>". Ein solches Schlüsselwort wurde wahrscheinlich in C99 ausgewählt, um vorhandene c (C90) -Programme, die komplexe von Hand implementieren, nicht zu beschädigen. Wenn <complex.h> enthalten ist, complexwird es als Makro definiert und auf erweitert _Complex. Vielleicht interessiert Sie auch Derek M. Jones '"Der neue C-Standard: Ein wirtschaftlicher und kultureller Kommentar" (2008) Seite 500 "Komplexe Typen" 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

Der Einfachheit halber kann man eine tgmath.hBibliothek für die Typgenerierungsmakros einschließen . Es wird für alle Variablentypen der gleiche Funktionsname wie für die Doppelversion erstellt. Zum Beispiel Zum Beispiel definiert es einen sqrt()Makro , das auf das erweitert sqrtf(), sqrt()odersqrtl() Funktion, abhängig von der Art des Arguments vorgesehen.

Man muss sich also nicht den entsprechenden Funktionsnamen für verschiedene Variablentypen merken!

#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

Der Begriff der komplexen Zahlen wurde in der Mathematik eingeführt, da negative quadratische Wurzeln berechnet werden mussten. Das komplexe Zahlenkonzept wurde von einer Vielzahl von technischen Bereichen übernommen.

Heutzutage werden komplexe Zahlen in fortgeschrittenen technischen Bereichen wie Physik, Elektronik, Mechanik, Astronomie usw. häufig verwendet.

Real- und Imaginärteil eines negativen Quadratwurzelbeispiels:

#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

zVerwenden Sie die Notation as, um den Realteil eines Ausdrucks mit komplexem Wert zu extrahieren __real__ z. Verwenden Sie in ähnlicher Weise das __imag__Attribut on z, um den Imaginärteil zu extrahieren.

Beispielsweise;

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

r ist der Realteil der komplexen Zahl "z" i ist der Imaginärteil der komplexen Zahl "z"


2
Dies sind gcc-spezifische Erweiterungen. Eine andere Antwort erwähnte sie bereits und die akzeptierte Antwort bereits, wie dies in Standard C zu tun ist.
Keith Thompson
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.