第3回目


【解説】 複素数について

今回より,複素数を扱います.今後の課題の基礎となる部分ですのでしっかりと理解しておいてください.

複素数については数学の授業で扱ったと思いますので思い出してみて下さい.
なお,検索すればいくらでも解説のページは見付かると思います.

z = re + j im

で示されるものです.プログラム中では,z = x + j yとします.
虚部に関してはiと示す場合もあれば,jと示す場合もあります.
imageの頭文字で i となりますが他の変数と紛らわしくなる場合もあり,制御などでは j と表記します.
ここでも j とします.

さて,複素数の概念そのものが計算機にあるわけではありません.
四則演算であれば,メモリ内の数値を直接操作することができるのですが,複素数の場合は異なります.
複素数zの場合,re と im というパラメータを持った関数として扱う必要があります.

それでは,以下の複素数の意味を思い出してみて下さい.

複素数の演算について

[和] 実部,虚部それぞれの和
[差] 実部,虚部それぞれの差
[積] z1 z2 = x1 x2 - y1 y2 + j (x1 y2 + x2 y1)
[商] z1 / z2 = (x1 x2 + y1 y2) / (x2 x2 + y2 y2) + j (x2 y1 - x1 y2) / (x2 x2 + y2 y2)

[絶対値] |z| = x x + y y
[偏角] θ = atan (y/x)

[共役複素数] 虚部の符号が変わる
[指数関数] 来週の授業中に説明します.
[べき乗] 来週の授業中に説明します.
[n乗根] 来週の授業中に説明します.

いろいろと複雑なものになっていることがお分かりいただけたと思います.

さて,複素数を扱う上で,構造体を使えば表現することはできます.例えば以下のように,

typdef struct COMPLEX_
{
 double re;
 double im;
} Complex;

しかしながら,これや上記のような関数を毎回用いるばあい,その関数を毎回演算のために記述するのは楽ではありません.
しかも,
毎回記述することは間違いのもとでもある
ので,できれば一度書いたらいつでも同じように使えるものを作ってしまった方が良いかと思います.

そこで,情報処理・演習1で用いた分割コンパイルの手法を用います.
http://www.isc.meiji.ac.jp/~re00104/ch13.html

何をするのか整理してみましょう.

この目的を達成するには,

を用意します.
本日の課題は,
1)複素数の各関数作成
2)各関数を利用するための別ファイルのソースとヘッダの作成
3)メインとなるソースにて複素数関数を呼び出して実行
という中身です.

さて,分割コンパイルに関してはちょっと難しかったかと思います.
やっていることを理解するために,以下のものをご覧ください.

ごく簡単なMakefile
kadai3_1.exe: main.obj complex.obj
           bcc32 -e kadai3_1.exe main.obj complex.obj
main.obj:     main.c
           bcc32 -c main.c
complex.obj:  complex.c
           bcc32 -c complex.c

最終的にはkadai3_1.exeという実行ファイルを作りますが,そのためには
上記のコマンドをひとまとめにしたファイルMakefileを作成します.
なお,拡張子はありませんので御留意下さい.


本日の課題

課題1 複素数の演算について で示した各演算を作成し,関数を扱うための関数complex.cを作成せよ.
関数や変数の意味が分かるよう,コメントは必ず付けておくこと.
今回は和差積商と絶対値,偏角,共役複素数まででよい.(残りは来週)

#include <stdio.h>
#include <math.h>
#include "complex.h"

Complex ToComplex(double x, double y) /*複素数のパラメータを与える*/
{
 Complex z;

 z.re = x;

 z.im = y;
 return z;
}

Complex Cadd(Complex a, Complex b)
{
 Complex z;

 z.re = a.re + b.re;
 z.im = a.im + b.im;
 return z;
}

Complex Csub(Complex a, Complex b)
{
 同様
}

Complex Cmul(Complex a, Complex b)
{
 同様
}

Complex Cdiv(Complex a, Complex b)
{
 同様
}

double Cabs(Complex a)
{
 double x;
 x = sqrt(a.re * a.re + a.im * a.im);
 return x;
}

double Carg(Complex a)
{
 同様,関数はatan2を使う
}

Complex Conj(Complex a) /*共役複素数*/
{
 同様
}

以下,次回
Complex Cexp(Complex)
Complex Cpow(Complex, double)
Complex Csqrt(Complex),
void Cdisp(Complex);
Complex Cinp(void);

課題2 以下のヘッダファイルcomplex.hも合わせて作成しておくこと.
来週作成する関数も含まれているので,対応関係を理解しておき,コメント分を付けておく.

typedef struct COMPLEX_
{
 double re;
 double im;
} Complex;

Complex ToComplex(double, double),
      Cadd(Complex, Complex), Csub(Complex, Complex), Cmul(Complex, Complex),
      Cdiv(Complex, Complex), Conj(Complex, Complex), Cexp(Complex, Complex),
      Cpow(Complex, double), Csqrt(Complex), Cinp();
double  Cabs(Complex), Carg(Complex);
void    Cdisp(Complex);

※今回の課題は,多くのことを含んでいるため,できたところまでで問題ない.
来週も引き続き解説しながら,新しいことを追加するので,もう一度完成版を提出すること.

今回は,bcc32 -c complex.cとタイプすれば,コンパイルだけでき,文法のミスはチェックできる.
余力のある人は以下のようなmain.cを作り関数を呼び出して使ってみて欲しい.

#include <stdio.h>
#include <math.h>
#include "complex.h"

main()
{
 Complex x, y;
 int ???
 double ???

 呼び出したい関数

 printf("re im = %g %g |n"), x.re, x.im;
 printf("re im = %g %g |n"), y.re, y.im;

}

※情報処理演習1ではC++言語を用いたので拡張子はcppとなる.こちらを用いても良い.