ガウス・ジョルダン法の専用の関数を作る場合、どうするか?。まず、その入 出力と機能を考えます。入力は、係数行列のと非同次項のが必要です。 そして、出力は逆行列の と解のベクトル となります。 要するに、図1のような機 能のC言語の関数が欲しいわけです。
この関数ができると、問題を解く時に必要な係数行列と非同次項を入力さえす れば、逆行列と解を計算してくれます。この関数、実際はガウス・ジョルダン 法の手続きをC言語でいかにして実現するかは、次節以降に述べます。
いかなるプログラム言語でも、C言語の関数(mainではない)に対応するものが 有ります。FORTRANでは、サブルーチンと呼ばれるものです。同じような 処理がある場合、1つの独立した処理のブロックとしてまとめ、どこからでも コールすることができるようにすると便利です。例えば、sin(x)など もこれにあたります。の計算が必要な都度、その処理を書いていたの ではたまりませんので、独立した関数としてその処理が書かれているわけです。 これは、ライブラリーとなっているので、その処理内容は通常はわかりません。
この関数にデータを与える変数のことを引数と言います。先ほどの例で言うと、 C言語の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 = x+y; return(zout); }
その実引数から仮引数に値を送る方法は、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関数 ==============================================*/ 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]);