Bagaimana cara bekerja dengan bilangan kompleks di C?

122

Bagaimana saya bisa bekerja dengan bilangan kompleks di C? Saya melihat ada complex.hfile header, tetapi tidak memberi saya banyak informasi tentang cara menggunakannya. Bagaimana cara mengakses bagian nyata dan imajiner dengan cara yang efisien? Apakah ada fungsi asli untuk mendapatkan modul dan fase?

Charles Brunet
sumber
16
Saya menggunakan C daripada C ++ karena lebih mudah untuk mengikat ke kode Python saya.
Charles Brunet

Jawaban:

186

Kode ini akan membantu Anda, dan cukup jelas:

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

  dengan:

creal(z1): dapatkan bagian nyata (untuk float crealf(z1), untuk double panjang creall(z1))

cimag(z1): dapatkan bagian imajiner (untuk float cimagf(z1), untuk double panjang cimagl(z1))

Hal lain yang penting untuk diingat ketika bekerja dengan bilangan kompleks adalah bahwa fungsi seperti cos(), exp()dan sqrt()harus diganti dengan bentuk kompleks mereka, misalnya ccos(), cexp(), csqrt().

Shelvacu
sumber
12
Apa ini double complex? Apakah ini ekstensi bahasa atau sihir makro?
Calmarius
@Calmarius complexadalah tipe c99 standar (di bawah kap pada GCC, ini sebenarnya adalah alias untuk tipe _Complex).
Snaipe
9
@Snaipe: complexbukan tipe. Ini adalah makro yang diperluas ke _Complex, yang merupakan penentu tipe , tetapi bukan tipe itu sendiri. Jenis kompleks float _Complex, double _Complexdan long double _Complex.
Keith Thompson
3
Bukan hanya GCC, itu didefinisikan dalam standar bahwa _Complex adalah penentu tipe dan kompleks.h memiliki makro kompleks yang diperluas ke _Complex. Hal yang sama berlaku untuk _Bool dan stdbool.h.
jv110
40

Tipe kompleks ada dalam bahasa C sejak standar C99 ( -std=c99opsi GCC). Beberapa kompiler mungkin mengimplementasikan tipe kompleks bahkan dalam mode yang lebih awal, tetapi ini adalah ekstensi non-standar dan non-portabel (misalnya IBM XL, GCC, mungkin intel, ...).

Anda dapat mulai dari http://en.wikipedia.org/wiki/Complex.h - ini memberikan deskripsi fungsi dari complex.h

Panduan ini http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html juga memberikan beberapa info tentang makro.

Untuk mendeklarasikan variabel kompleks, gunakan

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

atau

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

Untuk memberi nilai menjadi kompleks, gunakan _Complex_Imakro dari complex.h:

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

(sebenarnya mungkin ada beberapa masalah di sini dengan (0,-0i)angka dan NaN di setengah kompleks tunggal)

Modul adalah cabs(a)/ cabsl(c)/ cabsf(b); Bagian sebenarnya adalah creal(a), Imajiner cimag(a). carg(a)adalah untuk argumen yang kompleks.

Untuk langsung mengakses (membaca / menulis) bagian gambar nyata, Anda dapat menggunakan ekstensi GCC yang tidak dapat dibawa ini :

 __real__ a = 1.4;
 __imag__ a = 2.0;
 float b = __real__ a;
osgx
sumber
1
hampir setiap fungsi kompleks akan diimplementasikan oleh compiler sebagai fungsi builtin dengan cara yang efisien. Cukup gunakan kompiler modern dan berikan beberapa level optimasi bukan nol.
osgx
3
FYI, karena OP menyebutkan pengikatan Python, ketika bekerja dengan Python saya mencoba untuk tetap menggunakan C89 (karena kode Python lainnya adalah C89, dan jika Anda ingin ekstensi Anda berjalan di Windows, biasanya dikompilasi dengan MVSC, yang dibatasi pada C89). Saya tidak tahu bahwa itu sangat diperlukan.
detly
1
Ekspresi (complex float) { r, i }juga dapat digunakan untuk mengatur bagian-bagian terpisah dari bilangan dan secara independen (memungkinkan bagian nyata menjadi INF sedangkan bagian imajiner adalah NAN, misalnya). Itu menghindari kata kunci khusus GCC, meskipun saya tidak yakin apakah itu benar-benar portabel.
cleong
2
Perhatikan bahwa dukungan Kompleks bersifat opsional di C99: kompiler mungkin tidak memilikinya jika mereka mendefinisikannya __STDC_NO_COMPLEX__. Namun dalam praktiknya, ini diterapkan pada kompiler utama.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Jasen, periksa halaman 182 draf N1256 open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Aritmatika kompleks <complex.h>". Kata kunci tersebut mungkin dipilih di C99 untuk tidak merusak program c (C90) yang ada yang mengimplementasikan kompleks dengan tangan. Jika <complex.h> disertakan, complexakan ditentukan sebagai makro, diperluas menjadi _Complex. Anda mungkin juga tertarik di Derek M. Jones "The New C Standard: Sebuah Ekonomi dan Budaya Commentary" (2008) halaman 500 "jenis kompleks" 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));
}
kompleks
sumber
4

Untuk kenyamanan, seseorang mungkin menyertakan tgmath.hpustaka untuk tipe menghasilkan makro. Ini menciptakan nama fungsi yang sama dengan versi ganda untuk semua jenis variabel. Sebagai contoh, misalnya, mendefinisikan sqrt()makro yang memperluas ke sqrtf(), sqrt()atausqrtl() fungsi, tergantung pada jenis argumen yang disediakan.

Jadi orang tidak perlu mengingat nama fungsi yang sesuai untuk tipe variabel yang berbeda!

#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;
}
tawaran tidak bisa ditolak
sumber
2

Gagasan tentang bilangan kompleks diperkenalkan dalam matematika, dari kebutuhan menghitung akar kuadrat negatif. Konsep bilangan kompleks diambil oleh berbagai bidang teknik.

Saat ini, bilangan kompleks banyak digunakan dalam domain teknik lanjutan seperti fisika, elektronik, mekanik, astronomi, dll.

Bagian nyata dan imajiner, dari contoh akar kuadrat negatif:

#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
sumber
-1

Untuk mengekstrak bagian nyata dari ekspresi bernilai kompleks z, gunakan notasi sebagai __real__ z. Demikian pula, gunakan __imag__atribut pada zuntuk mengekstrak bagian imajiner.

Sebagai contoh;

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

r adalah bagian nyata dari bilangan kompleks "z" i adalah bagian imajiner dari bilangan kompleks "z"

Cyclops
sumber
2
Ini adalah ekstensi khusus gcc. Jawaban lain sudah menyebutkan mereka, dan jawaban yang diterima sudah bagaimana melakukan ini dalam standar C.
Keith Thompson