最近写计算程序经常要用到复数运算,以前都是用 gsl 库中对复数运算的支持。这两天看了看C99 标准,发现C99 中对复数运算的支持还是蛮给力的,这里做个总结。C99 中引入了两个关键字 _Complex和 _Imaginary,并且定义了如下的复数类型:
float _Complex double _Complex long double _Complex float _Imaginary double _Imaginary long double _Imaginary这六种复数类型的含义显而易见,这里不多解释。需要特殊指出的是 _Imaginary相关数据类型在当前版本的 gcc 中还没有被支持。因为我现在电脑上没有安装其他的编译器,所以别的编译器能否支持也不清楚。不过 _Imaginary相关数据类型似乎用处不大,至少我没发现什么地方有这个需要。
下面给个简单的程序例子:
#include <stdio.h> extern double creal(double _Complex); extern double cimag(double _Complex); extern double _Complex csqrt(double _Complex); extern double _Complex csin(double _Complex); int main(void) { double _Complex a = 1.0 + 2.0 * csqrt(-1); double _Complex b = 5.0 + 4.0 * csqrt(-1); printf("a = %f + %fi\n", creal(a), cimag(a)); printf("b = %f + %fi\n", creal(b), cimag(b)); a *= b; printf("a * b = %f + %fi\n", creal(a), cimag(a)); a = csin(b); printf("sin(b) = %f + %fi\n", creal(a), cimag(a)); return 0; }计算结果如下:a = 1.000000 + 2.000000i
上面程序中用到了几个函数:
creal() 获得复数的实部
cimag() 获得复数的虚部
csqrt() 计算复数的平方根
csin() 计算复数的sin值
因为程序中没有包含复数支持的头文件,因此需要自己声明这几个函数。我之所以这样做是为了强调 _Complex 是编译器支持的原生类型,不是在头文件中声明的结构体。
C99 标准中之所以使用 _Complex和 _Imaginary而不直接用 complex 和 imaginary 作为关键字,是为了避免与一些现存的C 程序中的变量名发生冲突。如果能够确定自己的代码中没有用到 complex、imaginary 、I 作为变量名,那么可以包含 complex.h 头文件,包含这个头文件后就可以用 complex 代替 _Complex 了。这里需要特别提一句,C99 标准中似乎没有约定单位虚数i 在程序中如何简便的表示。gcc的实现方式是定义了两个宏,_Complex_I和 I 来表示单位虚数 i 。
因此上面的程序可以简化成如下的样子:
#include <stdio.h> #include <complex.h> int main(void) { double _Complex a = 1.0 + 2.0 * I; double _Complex b = 5.0 + 4.0 * I; printf("a = %f + %fi\n", creal(a), cimag(a)); printf("b = %f + %fi\n", creal(b), cimag(b)); a *= b; printf("a * b = %f + %fi\n", creal(a), cimag(a)); a = csin(b); printf("sin(b) = %f + %fi\n", creal(a), cimag(a)); return 0; }