Làm thế nào để làm việc với số phức trong C?


122

Làm cách nào để làm việc với các số phức trong C? Tôi thấy có một complex.htệp tiêu đề, nhưng nó không cung cấp cho tôi nhiều thông tin về cách sử dụng nó. Làm thế nào để truy cập các phần thực và ảo một cách hiệu quả? Có các hàm gốc để lấy mô-đun và pha không?


16
Tôi đang sử dụng C thay vì C ++ vì nó dễ liên kết với mã Python của tôi hơn.
Charles Brunet

Câu trả lời:


186

Mã này sẽ giúp bạn và nó khá dễ hiểu:

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

  với:

creal(z1): lấy phần thực (đối với float crealf(z1), đối với dài đôi creall(z1))

cimag(z1): lấy phần ảo (đối với float cimagf(z1), đối với dài gấp đôi cimagl(z1))

Một điểm quan trọng cần nhớ khi làm việc với những con số phức tạp là chức năng thích cos(), exp()sqrt()phải được thay thế bằng hình thức phức tạp của họ, ví dụ như ccos(), cexp(), csqrt().


12
Cái gì thế này double complex? Đây là một phần mở rộng ngôn ngữ hay một phép thuật vĩ mô nào đó?
Calmarius

@Calmarius complexlà một loại c99 tiêu chuẩn (dưới mui xe trên GCC, nó thực sự là một bí danh của loại _Complex).
Đồ ăn nhẹ

9
@Snaipe: complexkhông phải là một loại. Đó là một macro mở rộng thành _Complex, là một chỉ định kiểu , nhưng không phải là một kiểu của chính nó. Các loại phức tạp là float _Complex, double _Complex, và long double _Complex.
Keith Thompson

3
Nó không chỉ là GCC, nó được định nghĩa trong tiêu chuẩn rằng _Complex là một chỉ định kiểu và phức tạp. H có một macro phức tạp mở rộng thành _Complex. Tương tự với _Bool và stdbool.h.
jv110,

40

Các kiểu phức tạp trong ngôn ngữ C kể từ tiêu chuẩn C99 ( -std=c99tùy chọn của GCC). Một số trình biên dịch có thể thực hiện các kiểu phức tạp ngay cả trong các chế độ sớm hơn, nhưng đây là phần mở rộng không chuẩn và không di động (ví dụ như IBM XL, GCC, có thể là intel, ...).

Bạn có thể bắt đầu từ http://en.wikipedia.org/wiki/Complex.h - nó cung cấp mô tả về các chức năng từ complex.h

Hướng dẫn này http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html cũng cung cấp một số thông tin về macro.

Để khai báo một biến phức tạp, hãy sử dụng

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

hoặc là

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

Để cung cấp một giá trị thành phức, hãy sử dụng _Complex_Imacro từ complex.h:

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

(thực sự có thể có một số vấn đề ở đây với (0,-0i)số và NaN trong nửa đơn của phức)

Mô-đun là cabs(a)/ cabsl(c)/ cabsf(b); Phần thực là creal(a), phần tưởng tượng là cimag(a). carg(a)dành cho đối số phức tạp.

Trực tiếp truy cập (đọc / ghi) thực một phần IMAG bạn có thể sử dụng này unportable GCC-mở rộng :

 __real__ a = 1.4;
 __imag__ a = 2.0;
 float b = __real__ a;

1
hầu hết mọi chức năng phức tạp sẽ được thực hiện bởi trình biên dịch dưới dạng chức năng nội trang một cách hiệu quả. Chỉ cần sử dụng trình biên dịch hiện đại và cung cấp cho nó một số mức tối ưu hóa khác nhau.
osgx

3
FYI, vì OP đề cập đến các liên kết Python, khi làm việc với Python, tôi cố gắng bám vào C89 (vì phần còn lại của mã Python là C89 và nếu bạn muốn tiện ích mở rộng của mình chạy trên Windows, nó thường được biên dịch bằng MVSC, được giới hạn ở C89). Tôi không biết rằng nó hoàn toàn cần thiết.
detly

1
Biểu thức (complex float) { r, i }cũng có thể được sử dụng để đặt các phần riêng biệt của số và độc lập (ví dụ: cho phép phần thực là INF trong khi phần ảo là NAN). Điều đó tránh từ khóa dành riêng cho GCC, mặc dù tôi không chắc liệu nó có thực sự là di động hay không.
cleong

2
Lưu ý rằng hỗ trợ Phức hợp là tùy chọn trong C99: các trình biên dịch có thể đơn giản là không có nó nếu họ định nghĩa __STDC_NO_COMPLEX__. Tuy nhiên, trong thực tế, nó được triển khai trên các trình biên dịch lớn.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
Jasen, xem trang 182 của bản nháp N1256 open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Số học phức <complex.h>". Từ khóa như vậy có lẽ đã được chọn trong C99 để không phá vỡ các chương trình c (C90) hiện có thực hiện phức tạp bằng tay. Nếu <complex.h> được bao gồm, complexsẽ được định nghĩa là macro, được mở rộng thành _Complex. Bạn cũng có thể quan tâm đến "Tiêu chuẩn C mới: Bình luận về kinh tế và văn hóa" của Derek M. Jones (2008), trang 500 "loại phức tạp" 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

Để thuận tiện, người ta có thể bao gồm tgmath.hthư viện cho kiểu tạo macro. Nó tạo ra tên hàm giống như phiên bản kép cho tất cả các loại biến. Ví dụ, ví dụ, nó định nghĩa một sqrt()macro mở rộng đến sqrtf(), sqrt()hoặc sqrtl()chức năng, tùy thuộc vào loại của các đối số được cung cấp.

Vì vậy, người ta không cần phải nhớ tên hàm tương ứng cho các loại biến khác nhau!

#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

Khái niệm về số phức được đưa ra trong toán học, xuất phát từ nhu cầu tính các căn bậc hai âm. Khái niệm số phức đã được thực hiện bởi nhiều lĩnh vực kỹ thuật.

Ngày nay, số phức được sử dụng rộng rãi trong các lĩnh vực kỹ thuật tiên tiến như vật lý, điện tử, cơ học, thiên văn học, v.v.

Phần thực và phần ảo, của một ví dụ căn bậc hai âm:

#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

Để trích xuất phần thực của một biểu thức có giá trị phức z, hãy sử dụng ký hiệu là __real__ z. Tương tự, sử dụng __imag__thuộc tính trên zđể trích xuất phần ảo.

Ví dụ;

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

r là phần thực của số phức "z" i là phần ảo của số phức "z"


2
Đây là các tiện ích mở rộng dành riêng cho gcc. Câu trả lời khác đã đề cập họ, và câu trả lời được chấp nhận đã làm thế nào để làm điều này trong tiêu chuẩn C.
Keith Thompson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.