วิธีการทำงานกับจำนวนเชิงซ้อนใน C?


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):รับส่วนจริง (สำหรับลูกลอยcrealf(z1)สำหรับคู่ยาวcreall(z1))

cimag(z1):รับส่วนจินตภาพ (สำหรับลอยcimagf(z1)สำหรับคู่ยาวcimagl(z1))

อีกจุดที่สำคัญที่ต้องจำเมื่อทำงานกับตัวเลขที่ซับซ้อนเป็นฟังก์ชั่นที่ชอบcos(), exp()และsqrt()ต้องถูกแทนที่ด้วยรูปแบบที่ซับซ้อนของพวกเขาเช่นccos(), ,cexp()csqrt()


12
นี่มันอะไรกันdouble complex? นี่เป็นส่วนขยายภาษาหรือเวทมนตร์มาโคร?
Calmarius

@Calmarius complexเป็นประเภท c99 มาตรฐาน (ภายใต้ประทุนของ GCC เป็นนามแฝงของประเภท _Complex)
Snaipe

9
@Snaipe: complexไม่ใช่ประเภท เป็นมาโครที่ขยายไปถึง_Complexซึ่งเป็นตัวระบุประเภทแต่ไม่ใช่ประเภทด้วยตัวมันเอง ประเภทที่ซับซ้อนfloat _Complex, และdouble _Complex long double _Complex
Keith Thompson

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;

1
เกือบทุกฟังก์ชันที่ซับซ้อนจะถูกใช้งานโดยคอมไพเลอร์เป็นฟังก์ชันในตัวอย่างมีประสิทธิภาพ เพียงแค่ใช้คอมไพเลอร์ที่ทันสมัยและเพิ่มระดับการเพิ่มประสิทธิภาพที่ไม่ใช่ศูนย์
osgx

3
FYI เนื่องจาก OP กล่าวถึงการผูก Python เมื่อทำงานกับ Python ฉันจึงพยายามยึดติดกับ C89 (เนื่องจากโค้ดของ Python ที่เหลือคือ C89 และหากคุณต้องการให้ส่วนขยายของคุณทำงานบน Windows ก็มักจะรวบรวมด้วย MVSC ซึ่ง จำกัด ไว้ที่ C89) ฉันไม่รู้ว่ามันจำเป็นอย่างยิ่ง
ตรงกับ

1
นอกจากนี้นิพจน์(complex float) { r, i }ยังสามารถใช้เพื่อตั้งค่าส่วนที่แยกจากกันของจำนวนและแยกกันได้ (อนุญาตให้ส่วนจริงเป็น INF ในขณะที่ส่วนจินตภาพเป็น NAN เป็นต้น) ซึ่งเป็นการหลีกเลี่ยงคีย์เวิร์ดเฉพาะ GCC แม้ว่าฉันจะไม่แน่ใจว่าเป็นแบบพกพาจริงหรือไม่
เคลียร์

2
โปรดทราบว่าการสนับสนุนคอมเพล็กซ์เป็นตัวเลือกใน C99: __STDC_NO_COMPLEX__คอมไพเลอร์ก็อาจไม่ได้ถ้าพวกเขากำหนด อย่างไรก็ตามในทางปฏิบัติจะใช้กับคอมไพเลอร์หลัก
Ciro Santilli 郝海东冠状病六四事件法轮功

1
Jasen ตรวจสอบหน้า 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คุณอาจสนใจ "The New C Standard: An Economic and Cultural Commentary" ของ Derek M. (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__แอตทริบิวต์zเพื่อแยกส่วนจินตภาพ

ตัวอย่างเช่น;

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

r คือส่วนจริงของจำนวนเชิงซ้อน "z" i คือส่วนจินตภาพของจำนวนเชิงซ้อน "z"


2
นี่คือส่วนขยายเฉพาะ gcc คำตอบอื่นกล่าวถึงพวกเขาแล้วและคำตอบที่ยอมรับแล้วจะทำอย่างไรในมาตรฐาน C.
Keith Thompson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.