Comment travailler avec des nombres complexes en C?

122

Comment puis-je travailler avec des nombres complexes en C? Je vois qu'il y a un complex.hfichier d'en-tête, mais il ne me donne pas beaucoup d'informations sur la façon de l'utiliser. Comment accéder de manière efficace aux parties réelles et imaginaires? Existe-t-il des fonctions natives pour obtenir le module et la phase?

Charles Brunet
la source
16
J'utilise C au lieu de C ++ car il est plus facile de se lier à mon code Python.
Charles Brunet

Réponses:

186

Ce code vous aidera, et il est assez explicite:

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

  avec:

creal(z1): obtenir la vraie partie (pour float crealf(z1), pour long double creall(z1))

cimag(z1): récupère la partie imaginaire (pour float cimagf(z1), pour long double cimagl(z1))

Un autre point important à retenir lorsque l'on travaille avec des nombres complexes est que des fonctions comme cos(), exp()et sqrt()doit être remplacé par leurs formes complexes, par exemple ccos(), cexp(), csqrt().

Shelvacu
la source
12
Qu'est-ce que c'est double complex? Est-ce une extension de langage ou une magie macro?
Calmarius
@Calmarius complexest un type c99 standard (sous le capot sur GCC, c'est en fait un alias du type _Complex).
Snaipe
9
@Snaipe: complexn'est pas un type. C'est une macro qui se développe en _Complex, qui est un spécificateur de type , mais pas un type en soi. Les types complexes sont float _Complex, double _Complexet long double _Complex.
Keith Thompson
3
Ce n'est pas seulement GCC, il est défini dans la norme que _Complex est un spécificateur de type et complex.h a une macro complexe qui se développe en _Complex. Il en va de même pour _Bool et stdbool.h.
jv110
40

Les types complexes sont en langage C depuis le standard C99 ( -std=c99option de GCC). Certains compilateurs peuvent implémenter des types complexes même dans des modes plus anciens, mais il s'agit d'une extension non standard et non portable (par exemple IBM XL, GCC, peut être Intel, ...).

Vous pouvez commencer à partir de http://en.wikipedia.org/wiki/Complex.h - il donne une description des fonctions de complex.h

Ce manuel http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html donne également des informations sur les macros.

Pour déclarer une variable complexe, utilisez

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

ou

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

Pour donner une valeur en complexe, utilisez la _Complex_Imacro de complex.h:

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

(en fait, il peut y avoir des problèmes ici avec les (0,-0i)nombres et les NaN dans une seule moitié du complexe)

Le module est cabs(a)/ cabsl(c)/ cabsf(b); La vraie partie est creal(a), imaginaire est cimag(a). carg(a)est pour un argument complexe.

Pour accéder directement (lecture / écriture) à une partie imag réelle, vous pouvez utiliser cette extension GCC non portable :

 __real__ a = 1.4;
 __imag__ a = 2.0;
 float b = __real__ a;
osgx
la source
1
presque toutes les fonctions complexes seront implémentées par le compilateur en tant que fonction intégrée de manière efficace. Utilisez simplement un compilateur moderne et donnez-lui un niveau d'optimisation non nul.
osgx
3
Pour info, puisque l'OP mentionne les liaisons Python, lorsque je travaille avec Python, j'essaye de m'en tenir à C89 (puisque le reste du code de Python est C89, et si vous voulez que votre extension s'exécute sur Windows, elle est généralement compilée avec MVSC, qui est limité à C89). Je ne sais pas si c'est strictement nécessaire.
detly le
1
L'expression (complex float) { r, i }peut également être utilisée pour définir les parties séparées du nombre et indépendamment (permettant à la partie réelle d'être INF alors que la partie imaginaire est NAN, par exemple). Cela évite le mot-clé spécifique à GCC, même si je ne suis pas sûr qu'il soit réellement portable.
cleong
2
Notez que le support Complex est facultatif dans C99: les compilateurs peuvent simplement ne pas l'avoir s'ils définissent __STDC_NO_COMPLEX__. En pratique cependant, il est implémenté sur les principaux compilateurs.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Jasen, consultez la page 182 du projet N1256 open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Arithmétique complexe <complex.h>". Un tel mot-clé a probablement été sélectionné en C99 pour ne pas casser les programmes c (C90) existants qui implémentent le complexe à la main. Si <complex.h> est inclus, complexsera défini comme macro, développé en _Complex. Vous pourriez également être intéressé par "The New C Standard: An Economic and Cultural Commentary" (2008) page 500 "types complexes" 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));
}
complexe
la source
4

Pour plus de commodité, on peut inclure une tgmath.hbibliothèque pour le type générer des macros. Il crée le même nom de fonction que la version double pour tous les types de variables. Par exemple, Par exemple, on définit une sqrt()macro qui se dilate à la sqrtf(), sqrt()ou sqrtl()fonction, selon le type d'argument fourni.

Il n'est donc pas nécessaire de se souvenir du nom de la fonction correspondante pour différents types de 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;
}
une offre ne peut pas refuser
la source
2

La notion de nombres complexes a été introduite en mathématiques, à partir de la nécessité de calculer des racines quadratiques négatives. Le concept de nombre complexe a été adopté par une variété de domaines de l'ingénierie.

Aujourd'hui, les nombres complexes sont largement utilisés dans des domaines d'ingénierie avancés tels que la physique, l'électronique, la mécanique, l'astronomie, etc ...

Partie réelle et imaginaire, d'un exemple de racine carrée négative:

#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
la source
-1

Pour extraire la partie réelle d'une expression à valeurs complexes z, utilisez la notation comme __real__ z. De même, utilisez l' __imag__attribut sur zpour extraire la partie imaginaire.

Par exemple;

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

r est la partie réelle du nombre complexe "z" i est la partie imaginaire du nombre complexe "z"

cyclope
la source
2
Ce sont des extensions spécifiques à gcc. Une autre réponse les a déjà mentionnés, et la réponse acceptée déjà comment faire cela dans la norme C.
Keith Thompson