ガウス・ジョルダン法の専用の関数を作る場合、どうするか?。まず、その入 出力と機能を考える。入力は、係数行列の と非同次項の が必要である。 そして、出力は逆行列の と解のベクトル となる。 要するに、図のような機 能の関数をつくるわけである。
この関数ができると、問題を解く時に必要な係数行列と非同次項を入力さえす れば、逆行列と解を計算してくれる。ガウス・ジョルダン 法の手続きを、関数で実現する方法について、次節以降で丁寧に説明する。
いかなるプログラム言語でも、C言語の関数(mainではない)に対応するものが有り、それ は、サブルーチンと呼ばれている。同じような処理がある場合、1つの独立した処理のブ ロックとしてまとめ、どこからでもコールすることができるようにすると便利である。こ のような、機能のブロックをサブルーチンと呼ぶ。例えば、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関数 =================*/ main(){ double x, y, wa; いろいろな処理 wa=add(x,y); いろいろな処理 } /* ========== 足し算の関数 =================*/ 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と同 じ)。
従って、図のような入出 力の関数を実現するための引数の書き方は、
#include <stdio.h> void gaussjordan(double a[][100], double b[100], double inv_a[][100], double x[100]); /* ========== main関数 ==============================================*/ void main(){ double a[100][100], b[100]; double inv_a[100][100], x[100]; いろいろな処理 gaussjordan(a,b,inv_a,x); いろいろな処理 } /* ========== ガウスジョルダン法の関数 =============================*/ void gaussjordan(double a[][100], double b[100], double inv_a[][100], double x[100]){ いろいろな処理 inv_a[i][j] = いろいろな計算 b[i] = これも計算 いろいろな処理 }
となる。処理する関数の方は、一番最初のサイズを除いて書く必要がある。これは、例え ばz[100][200][300]の大きさの配列のz[23][73][36]というデータに アクセスする場合を考えれば分かる。このデータがあるアドレスは、[Zのアド レス+配列1個のデータサイズ ]になる。 したがって、最初の配列のサイズを除いて、配列のサイズがアドレス計算に必要となり、 処理する関数側で明示する必要がある。
実際のプログラムでは、もう少し効率よく配列を使うが、大筋はこの通り である。これで、関数に値を与える復習は終わり。
int gaussjordan(int n, double a[][100], double b[100], double inv_a[][100], double x[100]);