¿Cómo trabajar con números complejos en C?

122

¿Cómo puedo trabajar con números complejos en C? Veo que hay un complex.harchivo de encabezado, pero no me da mucha información sobre cómo usarlo. ¿Cómo acceder a partes reales e imaginarias de manera eficiente? ¿Hay funciones nativas para obtener el módulo y la fase?

Charles Brunet
fuente
16
Estoy usando C en lugar de C ++ porque es más fácil de vincular a mi código Python.
Charles Brunet

Respuestas:

186

Este código te ayudará, y es bastante claro:

#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): obtener la parte real (para flotante crealf(z1), para doble largo creall(z1))

cimag(z1): obtener la parte imaginaria (para flotante cimagf(z1), para doble largo cimagl(z1))

Otro punto importante a recordar cuando se trabaja con números complejos es que funciona como cos(), exp()y sqrt()debe ser reemplazado con sus formas complejas, por ejemplo ccos(), cexp(), csqrt().

Shelvacu
fuente
12
¿Qué es esto double complex? ¿Es esta una extensión de lenguaje o alguna macro magia?
Calmarius
@Calmarius complexes un tipo c99 estándar (debajo del capó en GCC, en realidad es un alias para el tipo _Complex).
Snaipe
9
@Snaipe: complexno es un tipo. Es una macro que se expande a _Complex, que es un especificador de tipo , pero no un tipo en sí mismo. Los tipos son complejas float _Complex, double _Complexy long double _Complex.
Keith Thompson,
3
No es solo GCC, se define en el estándar que _Complex es un especificador de tipo y complex.h tiene una macro compleja que se expande a _Complex. Lo mismo ocurre con _Bool y stdbool.h.
jv110
40

Los tipos complejos están en lenguaje C desde el estándar C99 ( -std=c99opción de GCC). Algunos compiladores pueden implementar tipos complejos incluso en modos más anteriores, pero esta es una extensión no estándar y no portátil (por ejemplo, IBM XL, GCC, puede ser Intel, ...).

Puede comenzar desde http://en.wikipedia.org/wiki/Complex.h : proporciona una descripción de las funciones de complex.h

Este manual http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html también brinda información sobre macros.

Para declarar una variable compleja, use

  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

Para dar un valor en complejo, use _Complex_Imacro de complex.h:

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

(en realidad puede haber algunos problemas aquí con (0,-0i)números y NaN en la mitad del complejo)

Módulo es cabs(a)/ cabsl(c)/ cabsf(b); La parte real es creal(a), Imaginary is cimag(a). carg(a)es para argumentos complejos.

Para acceder directamente (leer / escribir) una parte real e imag puede usar esta extensión GCC no portable :

 __real__ a = 1.4;
 __imag__ a = 2.0;
 float b = __real__ a;
osgx
fuente
1
Casi todas las funciones complejas serán implementadas por el compilador como funciones integradas de manera eficiente. Simplemente use el compilador moderno y dele un nivel de optimización distinto de cero.
osgx
3
Para su información, dado que el OP menciona enlaces de Python, cuando trabajo con Python trato de mantenerme en C89 (ya que el resto del código de Python es C89, y si desea que su extensión se ejecute en Windows, generalmente se compila con MVSC, que se limita a C89). Sin embargo, no sé si es estrictamente necesario.
detly
1
La expresión (complex float) { r, i }también se puede usar para establecer las partes separadas del número e independientemente (permitiendo que la parte real sea INF mientras que la parte imaginaria es NAN, por ejemplo). Eso evita la palabra clave específica de GCC, aunque no estoy seguro de si en realidad es portátil.
cleong
2
Tenga en cuenta que el soporte complejo es opcional en C99: los compiladores simplemente no lo tienen si lo definen __STDC_NO_COMPLEX__. En la práctica, sin embargo, se implementa en los principales compiladores.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Jasen, consulte la página 182 del borrador N1256 open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Aritmética compleja <complex.h>". Tal palabra clave probablemente fue seleccionada en C99 para no romper los programas existentes de c (C90) que implementan complejos a mano. Si se incluye <complex.h>, complexse definirá como macro, expandido a _Complex. Puede ser también interesado en Derek M. Jones "La nueva C estándar: Comentario Una Económica y Cultural" (2008) página 500 "tipos complejos" 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));
}
complejo
fuente
4

Por conveniencia, se puede incluir una tgmath.hbiblioteca para el tipo generar macros. Crea el mismo nombre de función que la versión doble para todo tipo de variable. Por ejemplo, Por ejemplo, se define una sqrt()macro que se expande a la sqrtf(), sqrt()o sqrtl()función, dependiendo del tipo de argumento proporcionado.

¡Entonces no es necesario recordar el nombre de la función correspondiente para diferentes tipos 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;
}
una oferta no puede rechazar
fuente
2

La noción de números complejos se introdujo en las matemáticas, a partir de la necesidad de calcular raíces cuadráticas negativas. El concepto de número complejo fue tomado por una variedad de campos de ingeniería.

Hoy en día, los números complejos se utilizan ampliamente en dominios de ingeniería avanzados como la física, la electrónica, la mecánica, la astronomía, etc.

Parte real e imaginaria, de un ejemplo de raíz cuadrada 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
fuente
-1

Para extraer la parte real de una expresión de valor complejo z, use la notación como __real__ z. Del mismo modo, use el __imag__atributo en zpara extraer la parte imaginaria.

Por ejemplo;

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

r es la parte real del número complejo "z" i es la parte imaginaria del número complejo "z"

Cíclope
fuente
2
Estas son extensiones específicas de gcc. Otra respuesta ya los mencionó, y la respuesta aceptada ya cómo hacerlo en el estándar C.
Keith Thompson