如何在C中使用复数?


122

如何在C中使用复数?我看到有一个complex.h头文件,但是它没有给我太多有关如何使用它的信息。如何有效地访问实部和虚部?是否有获取模块和阶段的本机函数?


16
我使用C而不是C ++,因为绑定到我的Python代码更容易。
Charles Brunet

Answers:


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),对于double cimagl(z1)

另一个重要的一点要记住,当使用复数的工作是一样的功能cos()exp()并且sqrt()必须与他们复杂的形式,例如更换ccos()cexp()csqrt()


12
这是double complex什么 这是语言扩展还是宏魔术?
Calmarius 2014年

@Calmarius complex是标准的c99类型(在GCC的内部,它实际上是_Complex类型的别名)。
Snaipe 2015年

9
@Snaipe:complex不是一种类型。这是一个扩展为的宏_Complex,它是类型说明符,但本身不是类型。复杂的类型float _Complexdouble _Complexlong double _Complex
基思·汤普森

3
它不仅是GCC,而且在标准中还定义_Complex是类型说明符,而complex.h具有扩展为_Complex的complex宏。_Bool和stdbool.h也是如此。
jv110

40

从C99标准(-std=c99GCC的选项)开始,复杂类型使用C语言。一些编译器甚至可以在更早的模式下实现复杂类型,但这是非标准且不可移植的扩展(例如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)用于复杂的论证。

要直接访问(读/写)真实的imag部件,可以使用以下不可移植的 GCC扩展名

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

1
几乎所有复杂功能都将由编译器以高效方式作为内置函数实现。只需使用现代编译器,并为其提供一些非零级别的优化即可。
osgx 2011年

3
仅供参考,由于OP提及Python绑定,因此在使用Python时,我会尽量坚持使用C89(因为Python的其余代码为C89,并且如果您希望扩展程序在Windows上运行,则通常使用MVSC编译,仅限于C89)。我不知道这是绝对必要的。
2013年

1
该表达式(complex float) { r, i }还可以用于独立设置数字的各个部分(例如,允许实数部分为INF,而虚数部分为NAN)。这避免了特定于GCC的关键字,尽管我不确定它是否真正可移植。
cleong 2014年

2
请注意,复杂支持在C99中是可选的:如果定义,编译器可能根本没有它__STDC_NO_COMPLEX__。但是实际上,它是在主要编译器上实现的。
西罗Santilli郝海东冠状病六四事件法轮功

1
Jasen,请参阅N1256草案open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 “ 7.3复数<complex.h>”的第182页。在C99中可能选择了这样的关键字,以不破坏现有的c(C90)程序,该程序手动实现复杂。如果包含<complex.h>,complex将被定义为宏,扩展为_Complex。您可能还对Derek M. Jones的“新C标准:经济和文化评论”(2008年)第500页“复杂类型” 感兴趣。people.ece.cornell.edu
land/

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特定的扩展。另一个答案已经提到他们,接受的答案已经如何在标准下做到这一点
基思·汤普森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.