Як працювати зі складними числами в С?


122

Як я можу працювати зі складними числами в С? Я бачу, що є complex.hфайл заголовка, але він не дає мені багато інформації про те, як ним користуватися. Як ефективно отримати доступ до реальних та уявних частин? Чи є вбудовані функції для отримання модуля та фази?


16
Я використовую C замість C ++, тому що це простіше прив’язати до мого коду Python.
Чарльз Брунет

Відповіді:


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): отримати справжню частину (для поплавця crealf(z1), для довгого подвійного creall(z1))

cimag(z1): отримати уявну частину (для поплавця cimagf(z1), для довгого подвійного cimagl(z1))

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


12
Що це double complex? Це розширення мови чи якась макро-магія?
Кальмарій

@Calmarius complex- це стандартний тип c99 (під кришкою на GCC це фактично псевдонім типу _Complex).
Снайп

9
@Snaipe: complexне є типом. Це макрос, який розширюється на _Complex, який є специфікатором типу , але не самим типом. Складні типи float _Complex, double _Complexі long double _Complex.
Кіт Томпсон

3
Це не лише GCC, а у стандарті визначено, що _Complex є специфікатором типу, а complex.h має складний макрос, який розширюється до _Complex. Те саме стосується _Bool та stdbool.h.
jv110

40

Складні типи є мовою С з моменту стандарту C99 ( -std=c99опція GCC). Деякі компілятори можуть реалізовувати складні типи навіть у більш ранніх режимах, але це нестандартне і не портативне розширення (наприклад, IBM XL, GCC, можливо, інтелект, ...).

Ви можете почати з 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;

1
майже кожна складна функція буде реалізована компілятором як вбудована функція ефективно. Просто використовуйте сучасний компілятор і надайте йому деякий ненульовий рівень оптимізації.
osgx

3
FYI, оскільки OP згадує прив'язки Python, я працюю з Python, я намагаюся дотримуватися C89 (оскільки решта коду Python - це C89; якщо ви хочете, щоб ваше розширення працювало на Windows, воно зазвичай компілюється з MVSC, який обмежений С89). Я не знаю, що це вкрай необхідно.
detly

1
Вираз (complex float) { r, i }можна також використовувати для встановлення окремих частин числа та незалежно (дозволяючи реальній частині бути INF, тоді як уявною частиною є NAN, наприклад). Це дозволяє уникнути ключового слова, специфічного для GCC, хоча я не впевнений, чи є він насправді портативним.
cleong

2
Зауважте, що комплексна підтримка в C99 не є обов'язковою: компілятори можуть просто не мати її, якщо вони визначають __STDC_NO_COMPLEX__. На практиці він реалізується на основних компіляторах.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
Ясен, перевірте сторінку 182 проекту N1256 проекту open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Складна арифметика <комплекс.h>". Таке ключове слово, ймовірно, було вибрано в C99, щоб не порушувати існуючі програми c (C90), які реалізують склад вручну. Якщо <комплекс.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;
}

-1

Для вилучення реальної частини складнозначного виразу zвикористовуйте позначення як __real__ z. Аналогічно використовуйте __imag__атрибут on zдля витягування уявної частини.

Наприклад;

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

r - реальна частина комплексного числа "z" i - уявна частина комплексного числа "z"


2
Це розширення, специфічні для gcc. Інша відповідь вже згадувала їх, і прийнята відповідь вже, як це зробити у стандартному С.
Кіт Томпсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.