Как работать с комплексными числами на Си?

122

Как я могу работать с комплексными числами на C? Я вижу, что есть complex.hфайл заголовка, но он не дает мне много информации о том, как его использовать. Как эффективно получить доступ к реальным и мнимым частям? Есть ли собственные функции для получения модуля и фазы?

Шарль Брюне
источник
16
Я использую C вместо C ++, потому что его легче привязать к моему коду Python.
Charles Brunet,

Ответы:

186

Этот код поможет вам, и он не требует пояснений:

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

  с участием:

creal(z1): получить реальную часть (для float crealf(z1), для long double creall(z1))

cimag(z1): получить мнимую часть (для float cimagf(z1), для long double cimagl(z1))

Еще один важный момент , чтобы помнить при работе с комплексными числами , является то , что такие функции , как cos(), exp()и sqrt()должны быть заменены их сложными формами, например ccos(), cexp(), csqrt().

Shelvacu
источник
12
Что это double complex? Это расширение языка или магия макросов?
Calmarius
@Calmarius complex- это стандартный тип c99 (в GCC это фактически псевдоним типа _Complex).
Snaipe
9
@Snaipe: complexэто не тип. Это макрос, который расширяется до спецификатора_Complex типа , но не сам по себе. Сложные типы , и . float _Complexdouble _Complexlong double _Complex
Кейт Томпсон
3
Это не просто GCC, в стандарте определено, что _Complex является спецификатором типа, а complex.h имеет сложный макрос, который расширяется до _Complex. То же самое касается _Bool и stdbool.h.
jv110
40

Сложные типы находятся в языке C, начиная со стандарта C99 ( -std=c99вариант GCC). Некоторые компиляторы могут реализовывать сложные типы даже в более ранних режимах, но это нестандартное и непереносимое расширение (например, IBM XL, GCC, может быть Intel, ...).

Вы можете начать с http://en.wikipedia.org/wiki/Complex.h - он дает описание функций из complex.h

Это руководство http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html также дает некоторую информацию о макросах.

Чтобы объявить сложную переменную, используйте

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

или

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

Чтобы преобразовать значение в комплекс, используйте _Complex_Iмакрос из complex.h:

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

(на самом деле здесь могут быть проблемы с (0,-0i)числами и NaN в одной половине комплекса)

Модуль есть cabs(a)/ cabsl(c)/ cabsf(b); Реальная часть - это creal(a)мнимая часть cimag(a). carg(a)для сложного аргумента.

Для прямого доступа (чтения / записи) к реальной части изображения вы можете использовать это непереносимое расширение GCC :

 __real__ a = 1.4;
 __imag__ a = 2.0;
 float b = __real__ a;
osgx
источник
1
почти каждая сложная функция будет эффективно реализована компилятором как встроенная функция. Просто используйте современный компилятор и дайте ему ненулевой уровень оптимизации.
osgx
3
К вашему сведению, поскольку OP упоминает привязки Python, при работе с Python я стараюсь придерживаться C89 (поскольку остальной код Python - C89, и если вы хотите, чтобы ваше расширение работало в Windows, оно обычно компилируется с помощью MVSC, который ограничен C89). Но я не знаю, что это строго необходимо.
Detly 09
1
Выражение (complex float) { r, i }также можно использовать для установки отдельных частей числа и независимо (например, позволяя действительной части быть INF, а мнимой - NAN). Это позволяет избежать ключевого слова, специфичного для GCC, хотя я не уверен, действительно ли оно переносимо.
cleong
2
Обратите внимание, что поддержка Complex не является обязательной в C99: компиляторы могут просто не иметь ее, если они определяют __STDC_NO_COMPLEX__. Однако на практике это реализовано на основных компиляторах.
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
1
Джасен, посмотрите страницу 182 черновика N1256 open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 «7.3 Комплексная арифметика <complex.h>». Такое ключевое слово, вероятно, было выбрано в C99, чтобы не нарушать существующие программы c (C90), которые реализуют сложные вручную. Если включен <complex.h>, complexбудет определен как макрос, расширенный до _Complex. Возможно, вас заинтересует книга Дерека М. Джонса «Новый стандарт Си: экономический и культурный комментарий» (2008), стр. 500 «сложные типы» 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

Для удобства можно включить tgmath.hбиблиотеку для типа создания макросов. Он создает то же имя функции, что и двойная версия для всех типов переменных. Например, Например, он определяет sqrt()макрос , который расширяется к sqrtf(), sqrt()или sqrtl()функции, в зависимости от типа аргумента при условии.

Так что не нужно запоминать соответствующее имя функции для разных типов переменных!

#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

Понятие комплексных чисел было введено в математику из-за необходимости вычисления отрицательных квадратных корней. Концепция комплексных чисел была взята на вооружение в самых разных областях техники.

Сегодня эти комплексные числа широко используются в передовых инженерных областях, таких как физика, электроника, механика, астрономия и т. Д.

Пример действительной и мнимой части отрицательного квадратного корня:

#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
источник
-1

Чтобы извлечь действительную часть выражения с комплексным знаком z, используйте обозначение as __real__ z. Точно так же используйте __imag__атрибут zдля извлечения мнимой части.

Например;

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

r - действительная часть комплексного числа "z"; i - мнимая часть комплексного числа "z".

Циклоп
источник
2
Это расширения, специфичные для gcc. Другой ответ уже упоминал их, и уже принятый ответ, как это сделать в стандартном C.
Кейт Томпсон,