Como trabalhar com números complexos em C?

122

Como posso trabalhar com números complexos em C? Vejo que há um complex.harquivo de cabeçalho, mas ele não fornece muita informação sobre como usá-lo. Como acessar partes reais e imaginárias de maneira eficiente? Existem funções nativas para obter módulo e fase?

Charles Brunet
fonte
16
Estou usando C em vez de C ++ porque é mais fácil vincular ao meu código Python.
Charles Brunet

Respostas:

186

Este código irá ajudá-lo e é bastante auto-explicativo:

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

  com:

creal(z1): obtém a parte real (para float crealf(z1), long long creall(z1))

cimag(z1): obtém a parte imaginária (para float cimagf(z1), long long cimagl(z1))

Outro ponto importante a lembrar quando se trabalha com números complexos é que as funções gosto cos(), exp()e sqrt()deve ser substituído por suas formas complexas, por exemplo ccos(), cexp(), csqrt().

Shelvacu
fonte
12
O que é isso double complex? Isso é uma extensão de idioma ou alguma macro mágica?
Calmarius
@Calmarius complexé um tipo c99 padrão (sob o capô do GCC, na verdade é um alias para o tipo _Complex).
Snaipe 12/04/2015
9
@ Snipe: complexnão é um tipo. É uma macro que se expande para _Complex, que é um especificador de tipo , mas não um tipo por si só. Os tipos complexos são float _Complex, double _Complexe long double _Complex.
Keith Thompson
3
Não é apenas o GCC, é definido no padrão que _Complex é um especificador de tipo e complex.h possui uma macro complexa que se expande para _Complex. O mesmo vale para _Bool e stdbool.h.
Jv110
40

Tipos complexos estão no idioma C desde o padrão C99 ( -std=c99opção do GCC). Alguns compiladores podem implementar tipos complexos, mesmo em modos mais antigos, mas essa é uma extensão não padrão e não portátil (por exemplo, IBM XL, GCC, pode ser intel, ...).

Você pode começar em http://en.wikipedia.org/wiki/Complex.h - fornece uma descrição das funções em complex.h

Este manual http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html também fornece algumas informações sobre macros.

Para declarar uma variável complexa, use

  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

Para atribuir um valor ao complexo, use a _Complex_Imacro de complex.h:

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

(na verdade, pode haver alguns problemas aqui com (0,-0i)números e NaNs na metade única do complexo)

O módulo é cabs(a)/ cabsl(c)/ cabsf(b); Parte real é creal(a), imaginário é cimag(a). carg(a)é para argumento complexo.

Para acessar diretamente (ler / escrever) uma parte imag real, você pode usar esta extensão GCC não portável :

 __real__ a = 1.4;
 __imag__ a = 2.0;
 float b = __real__ a;
osgx
fonte
1
quase todas as funções complexas serão implementadas pelo compilador como função interna de maneira eficiente. Basta usar o compilador moderno e fornecer um nível de otimização diferente de zero.
osgx
3
FYI, como o OP menciona ligações Python, ao trabalhar com Python, tento manter o C89 (já que o restante do código do Python é C89 e, se você deseja que sua extensão seja executada no Windows, geralmente é compilada com o MVSC, que é limitado a C89). Eu não sei se é estritamente necessário.
detly
1
A expressão (complex float) { r, i }também pode ser usada para definir as partes separadas do número e de forma independente (permitindo que a parte real seja INF enquanto a parte imaginária é NAN, por exemplo). Isso evita a palavra-chave específica do GCC, embora não tenha certeza se ela é realmente portátil.
cleong
2
Observe que o suporte complexo é opcional no C99: os compiladores podem simplesmente não tê-lo se eles definirem __STDC_NO_COMPLEX__. Na prática, no entanto, é implementado nos principais compiladores.
Ciro Santilli escreveu
1
Jasen, consulte a página 182 do rascunho da N1256 open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Aritmética complexa <complex.h>". Essa palavra-chave provavelmente foi selecionada em C99 para não quebrar os programas c (C90) existentes que implementam complexos manualmente. Se <complex.h> for incluído, complexserá definido como macro, expandido para _Complex. Você pode também estar interessado em "O Novo Padrão C: Um Comentário Econômico e Cultural", de Derek M. Jones (2008), página 500 "tipos complexos" 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));
}
complexo
fonte
4

Por conveniência, pode-se incluir uma tgmath.hbiblioteca para o tipo gerar macros. Ele cria o mesmo nome da função que a versão dupla para todo tipo de variável. Por exemplo, Por exemplo, ele define um sqrt()macro que se expande para o sqrtf(), sqrt()ou sqrtl()função, dependendo do tipo de argumento fornecida.

Portanto, não é necessário lembrar o nome da função correspondente para diferentes tipos de variáveis!

#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;
}
uma oferta não pode recusar
fonte
2

A noção de números complexos foi introduzida na matemática, a partir da necessidade de calcular raízes quadráticas negativas. O conceito de número complexo foi adotado por uma variedade de campos de engenharia.

Hoje, esses números complexos são amplamente utilizados em domínios de engenharia avançada, como física, eletrônica, mecânica, astronomia, etc.

Parte real e imaginária, de um exemplo de raiz quadrada 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;
}
LXSoft
fonte
-1

Para extrair a parte real de uma expressão com valor complexo z, use a notação como __real__ z. Da mesma forma, use o __imag__atributo no zpara extrair a parte imaginária.

Por exemplo;

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

r é a parte real do número complexo "z" i é a parte imaginária do número complexo "z"

Cyclops
fonte
2
Essas são extensões específicas do gcc. Outra resposta já mencionado-los, ea resposta aceita já como fazer isso no padrão C.
Keith Thompson