ガウス・ジョルダン法の専用の関数を作る場合,どうするか? まず,その入出力と機能 を考える.入力は計算に必要な全ての情報で,過不足が合ってはならない.係数行列の と非同次項の が入力データとなる.そして,出 力は逆行列の と解のベクトル とする.要するに,図のような機能の関数をつくるわけである.
この関数ができると,問題を解く時に必要な係数行列と非同次項を入力さえすれば,逆行 列と解を計算してくれる.ガウス・ジョルダン法の手続きを,関数で実現する方法につい て,次節以降で丁寧に説明する.
いかなるプログラム言語でも,C言語の関数(mainではない)に対応するものがある.同じ ような処理がある場合,1つの独立した処理のブロックとしてまとめ,どこからでもコー ルすることができるようにすると便利である.このような,機能のブロックをサブルーチ ン,C言語では関数と呼ぶ.例えば,sin(x)などである.の計算が必要 な都度,その処理を書いていたのではたまらないので,独立した関数としてその処理を書 くのである.これは,ライブラリーとなっているので,その処理内容は通常は分からない.
この関数に,データを与える変数のことを引数と言う.先ほどの例で言うと, sin(x)のxが引数である.プログラムの中では,sinと言う 名前がついている処理にxを与え,それを処理する.
引数には2種類(実引数と仮引数)があり,それを次のプログラムで説明する. この場合,main関数でコールするときの文,add(x,y)のxと yを実引数と呼ぶ.そして,その処理を書いている関数add(double xin, double yin)のxinとyinを仮引数という.呼ぶ方の変数を実引 数,呼ばれる方の変数を仮引数と言う.
#include <stdio.h> double add(double xin, double yin); /* ========== main関数 =================*/ int main(void) { double x, y, wa; いろいろな処理 wa=add(x,y); いろいろな処理 return 0; } /* ========== 足し算の関数 =================*/ double add(double xin, double yin){ double zout; zout = xin+yin; return zout; }
実引数から仮引数に値を送る方法は,以前学習した通り,C言語では2通りの方法がある.
C言語の場合,通常の変数(配列でない)の場合,値渡しである.これは良くできた仕様で ある.処理する関数が呼び出し側のデータを変えることが無いので,プログラミングの時, 余計な気を使わないですむ.関数の独立性が高いといわれる所以である.実際の例では, 先のaddという関数は,main関数から呼び出されており,main の実引数の値(x,y)の値が,addの仮引数(xin,yin)にコピー される.そこでの処理の結果は,戻り値(返却値)zoutに入れられて,元の関数 に戻す.元の関数のwaに,zoutの値がコピーされるのである.
一方,配列を処理する関数に渡す場合は,アドレス渡しになる.一般に配列のデータは, 通常の変数よりもかなり大きく,それをいちいちコピーしていたら不経済ということが理 由と言われている.
ということで,今回の場合,配列を渡すためアドレス渡しになる.処理する関数でその配 列の値を変えると,コールした関数のその値も変わる.しかし,これは便利なこともある. いちいち戻り値を与える必要が無く,気軽に呼び出した関数に結果を戻せる(FORTRANと同 じ).
従って,図1のような入出 力の関数を実現するための引数の書き方は,次のようにする.
#include <stdio.h> void gaussjordan(double a[][100], double b[100], double inv_a[][100], double x[100]); /* ========== main関数 ==============================================*/ int main(void){ double a[100][100], b[100]; // a[][]係数行列 b[]非同次項 double inv_a[100][100], x[100]; // inv_a[][]逆行列 x[]解 いろいろな処理 gaussjordan(a,b,inv_a,x); いろいろな処理 return 0; } /* ========== ガウスジョルダン法の関数 =============================*/ void gaussjordan(double a[][100], double b[100], double inv_a[][100], double x[100]){ いろいろな処理 inv_a[i][j] = いろいろな計算 b[i] = これも計算 いろいろな処理 }
処理する関数の方は,一番最初のサイズを除いて書く必要がある.これは,例え ばz[10][20][30]の大きさの配列のz[3][5][7]というデータに アクセスする場合を考えれば分かる.このデータがあるアドレスは,
z[3][5][7]のアドレス Zのアドレス+配列1個のデータサイズ | (1) |
実際のプログラムでは,もう少し効率よく配列を使うが,大筋はこの通りである.これで, 関数に値を与える復習は終わり.
int gaussjordan(int n, double a[][100], double b[100], double inv_a[][100], double x[100]);