ガウス・ジョルダン法の専用の関数を作る場合,どうするか? まず,その入出力と機能
を考える.入力は計算に必要な全ての情報で,過不足が合ってはならない.係数行列の
と非同次項の
が入力データとなる.そして,出
力は逆行列の
と解のベクトル
とする.要するに,図
のような機能の関数をつくるわけである.
この関数ができると,問題を解く時に必要な係数行列と非同次項を入力さえすれば,逆行 列と解を計算してくれる.ガウス・ジョルダン法の手続きを,関数で実現する方法につい て,次節以降で丁寧に説明する.
いかなるプログラム言語でも,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]のアドレス |
(1) |
実際のプログラムでは,もう少し効率よく配列を使うが,大筋はこの通りである.これで, 関数に値を与える復習は終わり.
int gaussjordan(int n, double a[][100], double b[100], double inv_a[][100], double x[100]);