復(fù)數(shù)稱Complex Number,從英文上來看似乎它是“復(fù)雜的數(shù)”。其實(shí)并不然,它實(shí)際上指的是復(fù)合數(shù),即由實(shí)部和虛部復(fù)合而成的數(shù)。它可以用下面的公式表示:
a(Real part)+ib(Imaginary part)
這里,純實(shí)數(shù)a是實(shí)部,ib是虛部,其中,a b都是實(shí)數(shù),i是虛數(shù)。
如果我們將實(shí)部作為x軸,虛部作為y軸,復(fù)數(shù)就可以在坐標(biāo)軸上表示了,這樣的坐標(biāo)系我們稱作復(fù)數(shù)坐標(biāo)系。它和復(fù)平面上原點(diǎn)的連線可以表示一個(gè)向量,向量和x軸的夾角為復(fù)數(shù)的輻角theta。
實(shí)數(shù)我們大家都很熟悉,在平時(shí)生活中,常用的也都是一些實(shí)數(shù)。那么,虛數(shù)是什么呢?
虛數(shù)并不是單純的數(shù)字,如果x^2=-1,我們就將它們的解定義為+/-i,這里的i就是虛數(shù),很顯然虛數(shù)似乎并不是我們平時(shí)所使用的數(shù),因?yàn)樵谖覀兯斫獾膶?shí)數(shù)領(lǐng)里任何一個(gè)數(shù)進(jìn)行平方之后都不可能是小于0的,但這并代表它沒有意義,我們可以換一個(gè)角度來理解虛數(shù),我們通過它可將實(shí)數(shù)擴(kuò)展到復(fù)數(shù)域。
要理解虛數(shù)我們就需要先復(fù)習(xí)一下之前學(xué)習(xí)的歐拉公式:
如果,
則,
相信這里大家應(yīng)該有了發(fā)現(xiàn):
在復(fù)數(shù)域中,
復(fù)數(shù)與復(fù)指數(shù)相乘,相當(dāng)于復(fù)數(shù)對(duì)應(yīng)的向量旋轉(zhuǎn)對(duì)應(yīng)的角度。
這里就相當(dāng)于我們把1逆時(shí)針旋轉(zhuǎn)90度,就可以得到i,如果我們?cè)倌鏁r(shí)針旋轉(zhuǎn)90度就是-1,也就是i*i。
所以,大家也就明白了i的含義,以及為什么i的平方等于-1了。
因此,虛數(shù)i的幾何意義上是一個(gè)旋轉(zhuǎn)量。
數(shù)學(xué)是一個(gè)偉大的工具,從實(shí)數(shù)到復(fù)數(shù)的擴(kuò)展是一個(gè)里程碑的進(jìn)步。數(shù)學(xué)家雅克·阿達(dá)馬說,在實(shí)數(shù)域中,連接兩個(gè)真理的最短的路徑是通過復(fù)數(shù)域。
程序中如何定義復(fù)數(shù)?
在C++中,complex頭文件中定義了一個(gè)complex模板類型,用來處理復(fù)數(shù)。格式如下:
template <class T> class complex;
template<> class complex<float>;
template<> class complex<double>;
template<> class complex<long double>;
T是實(shí)部和虛部的數(shù)字的數(shù)據(jù)類型,它可以支持float、double、long double這幾種類型。
復(fù)數(shù)這個(gè)類模板有多個(gè)構(gòu)造函數(shù):
complex( const T& re = T(), const T& im = T() );
complex( const complex& other );
template<class X > complex( const complex<X>& other);
從上面復(fù)數(shù)的構(gòu)造函數(shù)可以看出,我們可以用下面的幾種方法來定義一個(gè)復(fù)數(shù):
- 根據(jù)實(shí)部和虛部的值來構(gòu)造一個(gè)復(fù)數(shù);
- 根據(jù)一個(gè)復(fù)數(shù)的值來構(gòu)造一個(gè)復(fù)數(shù);
- 從不同類型的復(fù)數(shù)構(gòu)造一個(gè)復(fù)數(shù)。
#include <iostream>
#include <complex>
int main ()
{
std::complex<float> z1(1.2, 2.3);
std::complex<float> z2(z1);
std::complex<double> z3(z2);
std::cout << z3 << 'n';
return 0;
}
結(jié)果輸出:
(1.2,2.3)
復(fù)數(shù)的運(yùn)算
復(fù)數(shù)和實(shí)數(shù)一樣是可以進(jìn)行+ - × /等算術(shù)運(yùn)算的。假如有兩個(gè)復(fù)數(shù)z1和z2,如下:
復(fù)數(shù)的加法是將兩個(gè)復(fù)數(shù)的實(shí)部和實(shí)部相加,虛部和虛部相加:
同樣的,復(fù)數(shù)的減法是將兩個(gè)復(fù)數(shù)的實(shí)部和實(shí)部相減,虛部和虛部相減:
復(fù)數(shù)的乘法呢?因?yàn)閺?fù)數(shù)也是滿足實(shí)數(shù)域的交換律、結(jié)合律以及分配律這些定理,因此,我們可以對(duì)乘法進(jìn)行分解。
除法就會(huì)復(fù)雜一些,我們需要考慮將分母的復(fù)數(shù)轉(zhuǎn)成實(shí)數(shù)。該怎么進(jìn)行轉(zhuǎn)換呢?在這之前,我們需要先了解共軛復(fù)數(shù),如果有兩個(gè)復(fù)數(shù)z2=c+di和z3=c-di,他們實(shí)部相同,虛部互為相反數(shù),我們稱它們互為共軛,z2是z3的共軛復(fù)數(shù),z3也是z2的共軛復(fù)數(shù)。
共軛
共軛復(fù)數(shù)有這樣的一個(gè)特性,如果兩個(gè)共軛復(fù)數(shù)相乘,它們的結(jié)果是一個(gè)實(shí)數(shù)。
因此,我們可以利用共軛復(fù)數(shù)的這個(gè)特性進(jìn)行復(fù)數(shù)的除法運(yùn)算。
實(shí)際上,我們?cè)谑褂肅++寫程序時(shí)不需要這么復(fù)雜的公式計(jì)算,complex類實(shí)際上已經(jīng)進(jìn)行重載了這些操作。
complex& operator= (const T& val);
template<class X> complex& operator= (const complex<X>& rhs);
template<class T> complex<T> operator+(const complex<T>& lhs, const complex<T>& rhs);
template<class T> complex<T> operator+(const complex<T>& lhs, const T& val);
template<class T> complex<T> operator+(const T& val, const complex<T>& rhs);
template<class T> complex<T> operator-(const complex<T>& lhs, const complex<T>& rhs);
template<class T> complex<T> operator-(const complex<T>& lhs, const T& val);
template<class T> complex<T> operator-(const T& val, const complex<T>& rhs);
template<class T> complex<T> operator*(const complex<T>& lhs, const complex<T>& rhs);
template<class T> complex<T> operator*(const complex<T>& lhs, const T& val);
template<class T> complex<T> operator*(const T& val, const complex<T>& rhs);
template<class T> complex<T> operator/(const complex<T>& lhs, const complex<T>& rhs);
template<class T> complex<T> operator/(const complex<T>& lhs, const T& val);
template<class T> complex<T> operator/(const T& val, const complex<T>& rhs);
template<class T> complex<T> operator+(const complex<T>& rhs);
template<class T> complex<T> operator-(const complex<T>& rhs);
complex頭文件中已經(jīng)包含了常見的運(yùn)算操作,我們通過下面的的例子來加深了解。
#include <iostream>
#include <complex>
int main ()
{
std::complex<double> z1(1, 2);
std::complex<double> z2 = std::complex<double>(3, 4);
std::cout << "z1: " << z1 << std::endl;
std::cout << "z2: " << z2 << std::endl;
std::cout << "z1+z2: " << z1+z2 << std::endl;
std::cout << "z1-z2: " << z1-z2 << std::endl;
std::cout << "z1*z2: " << z1*z2 << std::endl;
std::cout << "z1/z2: " << z1/z2 << std::endl;
std::cout << "z1+2: " <<z1 + 2.0<< std::endl;
return 0;
}
上面的例子中,我們可以使用=直接對(duì)復(fù)數(shù)進(jìn)行賦值操作,還可以使用運(yùn)算符對(duì)復(fù)數(shù)進(jìn)行運(yùn)算,而且也支持實(shí)數(shù)和復(fù)數(shù)之間的運(yùn)算,其輸出結(jié)果如下:
z1: (1,2)
z2: (3,4)
z1+z2: (4,6)
z1-z2: (-2,-2)
z1*z2: (-5,10)
z1/z2: (0.44,0.08)
z1+2: (3,2)
當(dāng)然,除了上面的運(yùn)算,還支持+= -= *= /=等這些運(yùn)算。
complex& operator+= (const T& val);
complex& operator-= (const T& val);
complex& operator*= (const T& val);
complex& operator/= (const T& val);
template<class X> complex& operator+= (const complex<X>& rhs);
template<class X> complex& operator-= (const complex<X>& rhs);
template<class X> complex& operator*= (const complex<X>& rhs);
template<class X> complex& operator/= (const complex<X>& rhs);
同樣的,我們看下面的代碼:
#include <iostream>
#include <complex>
int main ()
{
std::complex<double> z1(1, 2);
std::complex<double> z2 = std::complex<double>(3, 4);
z1 += 2.0;
z2 -= z1;
std::cout << "z1: " << z1 << std::endl;
std::cout << "z2: " << z2 << std::endl;
return 0;
}
上面的代碼執(zhí)行結(jié)果:
z1: (3,2)
z2: (0,2)
一些其他函數(shù)
除了上面的一些運(yùn)算,complex頭文件里還有一些函數(shù),我們選擇一些常見的函數(shù)來進(jìn)行介紹。
- real和imag函數(shù)
- abs函數(shù)
- conj函數(shù)
- arg和polar函數(shù)
- norm函數(shù)
- exp函數(shù)
real和imag函數(shù)
我們知道了復(fù)數(shù)有實(shí)部和虛部組成,當(dāng)我們需要分開對(duì)實(shí)部和虛部處理的時(shí)候,如何取得實(shí)部和虛部的值呢?
complex頭文件定義了獲取實(shí)部(real函數(shù))和虛部(imag函數(shù))的函數(shù):
template<class T> T real (const complex<T>& x);
template<class T> T imag (const complex<T>& x);
示例:
#include <iostream>
#include <complex>
int main ()
{
std::complex<double> z1 (1,2);
std::cout << "real part: " << std::real(z1) << 'n';
std::cout << "imag part: " << std::imag(z1) << 'n';
return 0;
}
結(jié)果:
real part: 1
imag part: 2
abs函數(shù)
復(fù)數(shù)的模也就是向量的長(zhǎng)度,它可以根據(jù)復(fù)數(shù)的實(shí)部與虛部數(shù)值的平方和的平方根的值求出。我們常利用abs函數(shù)計(jì)算信號(hào)的幅度大小。
complex頭文件中取模函數(shù)是abs,其定義:
template<class T> T abs (const complex<T>& x);
示例:
#include <iostream>
#include <complex>
int main ()
{
std::complex<double> z1 (3.0,4.0);
std::cout << "Absolute value: "<< std::abs(z1) << std::endl;
return 0;
}
結(jié)果:
Absolute value: 5
conj函數(shù)
在上面的除法運(yùn)算中,我們知道,如果實(shí)部相同,虛部互為相反數(shù),那么它們互為共軛復(fù)數(shù)。complex也提供了一個(gè)函數(shù)conj便于我們求解一個(gè)復(fù)數(shù)的共軛復(fù)數(shù)。
template<class T> complex<T> conj (const complex<T>& x);
示例:
#include <iostream>
#include <complex>
int main ()
{
std::complex<double> z1 (2.0,3.0);
std::cout << "z1: " << z1 << std::endl;
std::cout << "z1 conjugate: " << std::conj(z1) << std::endl;
return 0;
}
結(jié)果:
z1: (2,3)
z1 conjugate: (2,-3)
arg函數(shù)與polar函數(shù)
arg和polar是兩個(gè)”相反“的函數(shù),這兩個(gè)函數(shù)可以進(jìn)行相互轉(zhuǎn)換。arg函數(shù)作用是根據(jù)一個(gè)復(fù)數(shù)返回一個(gè)角度,而polar函數(shù)可以根據(jù)角度返回一個(gè)復(fù)數(shù)。它們?cè)谟?jì)算相位或者根據(jù)相位計(jì)算其對(duì)應(yīng)的IQ時(shí)較為常用。
template<class T> T arg (const complex<T>& x);
template<class T> complex<T> polar (const T& rho, const T& theta = 0);
示例:
#include <iostream>
#include <complex>
int main ()
{
std::complex<double> z1 (3,4);
double theta = std::arg(z1);
std::complex<double> z2 = std::polar(5.0, theta);
std::cout << "angle:" << theta << std::endl;
std::cout << "polar:" << z2 << std::endl;
return 0;
}
上面的示例先用arg函數(shù)求出對(duì)應(yīng)的theta角,然后,再用polar函數(shù)根據(jù)求出的theta角以及幅值r返回相應(yīng)的復(fù)數(shù),結(jié)果如下:
angle:0.927295
polar:(3,4)
norm函數(shù)
norm函數(shù)可以計(jì)算復(fù)數(shù)的平方和,即實(shí)部和虛部平方的和,可用于計(jì)算IQ數(shù)據(jù)的功率大小。其定義如下:
template<class T> T norm (const complex<T>& x);
示例:
#include <iostream>
#include <complex>
int main ()
{
std::complex<double> z1 (3.0,4.0);
std::cout << "z1 norm: " << std::norm(z1) << std::endl;
return 0;
}
結(jié)果:
z1 norm: 25
exp函數(shù)
complex也支持自然指數(shù),我們可以使用exp函數(shù)。通過這個(gè)函數(shù),我們就可以生成我們想要的復(fù)指數(shù)信號(hào)了。
template<class T> complex<T> exp (const complex<T>& x);
我們可以利用這個(gè)函數(shù)生成一個(gè)theta角為pi的復(fù)指數(shù)數(shù)據(jù),示例代碼:
#include <complex>
#include <iostream>
int main()
{
double pi = std::acos(-1);
std::complex<double> i(0, 1);
std::cout << std::fixed << " exp(i*pi) = " << std::exp(i * pi) << 'n';
}
運(yùn)行結(jié)果如下:
exp(i*pi) = (-1.000000,0.000000)
最后
毋庸置疑,復(fù)數(shù)的提出對(duì)數(shù)學(xué)界來說是一個(gè)全新的發(fā)展,復(fù)數(shù)擴(kuò)展了數(shù)的概念,讓數(shù)從一維變成了二維。復(fù)數(shù)也是現(xiàn)代數(shù)字通信行業(yè)發(fā)展的必要條件,它是數(shù)字信號(hào)處理的基礎(chǔ)。數(shù)字信號(hào)處理是一個(gè)極為抽象和復(fù)雜的學(xué)科,掌握復(fù)數(shù)的處理方法對(duì)數(shù)字信號(hào)處理應(yīng)用實(shí)為必要,因此大家一定要熟練掌握這些方法的應(yīng)用。