double a[2], b[2] ;
.
.
.
のように,要素数が2であるdouble型の配列を用意して,それらの配列(上の例では a, b
)の,0番目の要素( a[0], b[0]
)を実数部分,1番目の要素( a[1], b[1]
)を虚数部分と(自分の心の中で)約束して,複素数の計算をするコードを書いていく,という方法です。
/* 複素数a, bを受け取って,a*bの値をansに納める */
mul(double ans[], double a[], doulbe b[])
{
ans[0] = a[0]*b[0] - a[1]*b[1] ; /* a*bの実数部分 */
ans[1] = a[0]*b[1] + a[1]*b[0] ; /* a*bの虚数部分 */
}
しかしながら,そのようにプログラミングをして,その場をしのげたとしても,他の人がそのコードを見た場合や,何ヵ月かたってから,自分の書いたそのコードを見たとき,a[]
や b[]
の配列が(複素数ではなくて)単なる配列を表していると勘違いしたり,あるいは上の関数 mul()
についても,(複素数どうしの掛け算ではなくて)単に配列どうし(ベクトルどうし)の掛け算(外積)を行う関数であると勘違いをしてしまうかもしれません。
struct complex {
double real; /* real part */
double imag; /* imaginary part */
} ;
新たな変数の型の名前(上の例では complex
)は,自由に自分でつけることができます。この新たな変数の型の名前のことを,real, imag
のことを,complex
型を定義すれば,その complex
型の変数を使いたいときには,以下のようにして型宣言文を書けばOKです。
struct complex tx ; /* complex型の変数としてtxを型宣言 */
この complex
型は,新しい変数の型ですから,以下のようにして配列としても使用することができます。
struct complex tx[10] ; /* complex型の配列(要素数10)としてtxを型宣言 */
struct complex ux[10][20] ; /* complex型の2次元配列(10行20列)としてtxを型宣言 */
あるいは,complex
型を指すポインタ型の変数も使えるようになります。
struct complex *p_tx ; /* complex型を指すポインタ型の変数(complex*型の変数)としてp_txを型宣言 */
便利でしょう!complex
型の,実数部分を取り出したいときには,以下のようにすればOKです。
tx.real ; /* complex型の変数txの実数部分(real)の参照 */
同様に,虚数部分を取り出したいときには,
tx.imag ; /* complex型の変数txの虚数部分(imag)の参照 */
とします。
typedef short seisu ; /* shortにあだなとしてseisuをつけた */
これ以降,
short sx ;
と型宣言する代わりに,
seisu sx ;
と型宣言することができます。すなわち,short
という言葉を使わずにコードを書くことができるというわけです。short
という名前にわざわざ seisu
とあだなをつける人は滅多にいないと思いますが,この“typedef宣言”は,実は,構造体を使用するときに便利に使うことができるのです。complex
型の変数を使いたいときには,
struct complex tx ;
のようにして型宣言文を書かなければなりませんね。complex
型という名前の変数の型を定義したわけですから,この complex
型についても通常の変数の型宣言文のように,
complex tx ;
と型宣言できるようになったら,非常にすっきりしますね(struct といちいち書くの,めんどくさい,ですよね)。complex
の定義文である,
struct complex {
double real; /* real part */
double imag; /* imaginary part */
} ;
の全体に対して,complex
とあだなをつければよさそうです。
typedef struct{
double real; /* real part */
double imag; /* imaginary part */
} complex;
これ以降,complex
型の変数を使いたいときには,
struct complex tx ;
と型宣言する代わりに,
complex tx ;
と型宣言することができる,というわけです。
/*************************************
complex number calculation
*************************************/
#include <stdio.h>
/* complex(複素数)型の定義 */
typedef struct{
double real; /* real part */
double imag; /* imaginary part */
} complex;
/* これ以降,complex 変数名; と型宣言すれば,その変数名のcomplex型を使用できる */
/* complex sum (a+b) */
complex sum(complex a, complex b)
{
complex ans;
ans.real = a.real + b.real;
ans.imag = a.imag + b.imag;
return(ans);
}
/* complex subtraction (a-b) */
complex sub(complex a, complex b)
{
complex ans;
ans.real = a.real - b.real;
ans.imag = a.imag - b.imag;
return(ans);
}
/* complex multiplication (a*b) */
complex mul(complex a, complex b)
{
complex ans;
ans.real = a.real*b.real - a.imag*b.imag;
ans.imag = a.real*b.imag + a.imag*b.real;
return(ans);
}
/* complex division (a/b) */
complex div(complex a, complex b)
{
double tmp;
complex ans;
tmp = b.real*b.real + b.imag*b.imag;
ans.real = (a.real*b.real + a.imag*b.imag)/tmp;
ans.imag = (a.imag*b.real - a.real*b.imag)/tmp;
return(ans);
}
/* show complex number */
void show(const char * text, complex a)
{
if(a.imag < 0)
printf("%s %f - %fi\n", text, a.real, -1.*a.imag);
else
printf("%s %f + %fi\n", text, a.real, a.imag);
}
int main(void)
{
complex a = {1, 1}; /* 構造体による変数の,型宣言文,および同時に初期化 */
complex b;
complex ans ;
b.real = 1.; /* 構造体への代入 */
b.imag = -1.;
show("a = ", a);
show("b = ", b);
ans = sum(a, b);
show("a + b = ", ans);
ans = sub(a, b);
show("a - b = ", ans);
ans = mul(a, b);
show("a * b = ", ans);
ans = div(a, b);
show("a / b = ", ans);
return(0);
}
(重要) 出席登録のための実習問題は,授業時間中に必ず提出して下さい。
[補足]
strcpy()
は,“文字列をコピーせよ”という命令文です。( strcpy() の使い方の詳細は,テキスト299ページを参照)
double pi = 3.14159265358979323846 ;
complex a, b ;
a.real = cos(pi/6.) ;
a.imag = sin(pi/6.) ;
b.real = 2. ;
b.imag = -1. ;
などとして複素数の変数 a, b の値を設定し,それから,b に a を12回掛け算してみてください。(重要) 宿題の締切は次の授業が始まる前までとします。きちんと動作をチェックしてから,提出して下さい。