このページでは、C言語での「余因子展開を利用した行列式の求め方」について解説していきます。
下記のページで行列式の求め方を解説しましたが、ここで解説したのは3次以下の行列式の求め方のみでした。
【C言語】3次以下の行列式の求め方このページで紹介する余因子展開を利用すれば、理論的にはどんな次数の行列式であっても求めることができるようになります!もちろん4次の正方行列(4×4 の行列)の行列式も求められますし、10次の正方行列の行列式を求めることも可能です!
また、C言語での行列の扱い方については下記ページで解説していますので、そもそもC言語で行列を扱う方法をご存知ない方は、事前に下記ページを読んでいただくことをオススメします。
【C言語】行列の扱い方今回は上記ページの ポインタで行列を扱う で紹介している関数を利用し、ポインタで行列を扱っていきます。
Contents
余因子展開を利用した行列式の求め方
まずはいつも通り、数学的観点から余因子展開を利用した行列式の求め方のおさらいをしていきたいと思います。
余因子
まず余因子についておさらいしていきたいと思います。
余因子 \(A_{ij}\) は、”正方行列 \(A\) の \(i\) 行目と \(j\) 列目を取り除いた正方行列” の行列式に \((-1)^{i + j}\) を掛けたものとなります。
例えば下記のような3次の正方行列 \(A\) においては、
$$ A = \left ( \begin{array}{ccc} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \end{array} \right ) $$
余因子 \(A_{23}\) は下記となります。
$$ A_{23} = (-1)^{2 + 3} \begin{vmatrix} a_{11} & a_{12} \\ a_{31} & a_{32} \end{vmatrix} $$
特に下記部分は、
$$ \begin{vmatrix} a_{11} & a_{12} \\ a_{31} & a_{32} \end{vmatrix} $$
下の図より、元々の正方行列 \(A\) から2行目と3列目を取り除いた行列の行列式となっていることが確認できると思います。
この余因子を利用すれば、行列式を簡単に求めることができます。
スポンサーリンク
余因子展開を利用した行列式の算出
さらに、”ある行” or “ある列” に対する全ての成分と余因子との積を足し合わせた結果は、元々の行列の行列式に等しいという特性があります。
例えば、前述で示した3次の正方行列 \(A\) を2行目に対する全ての成分と余因子との積を足し合わせる計算は下記の式で表すことができます。
$$ a_{21} A_{21} + a_{22} A_{22} + a_{23} A_{23} $$
そして、上式の結果が、元々の正方行列 \(A\) の行列式となります。
$$ \begin{vmatrix} A \end{vmatrix} = a_{21} A_{21} + a_{22} A_{22} + a_{23} A_{23} $$
このように、行列式を “ある行” or “ある列” に対する全ての成分と余因子との積を足し合わせる式に展開することを余因子展開と言います。同じ行 or 同じ列に対して展開するのであれば、どの行 or どの列に対して展開しても同じ結果が得られます。
さらに、余因子 \(A_{ij}\) は、”正方行列 \(A\) の \(i\) 行目と \(j\) 列目を取り除いた” 正方行列の行列式に \((-1)^{i + j}\) を掛けたものですので、上式は次の式に変形することが可能です。
$$ \begin{vmatrix} A \end{vmatrix} = a_{21} (-1)^{2 + 1} \begin{vmatrix} a_{12} & a_{13} \\ a_{32} & a_{33} \end{vmatrix} + a_{22} (-1)^{2 + 2} \begin{vmatrix} a_{11} & a_{13} \\ a_{31} & a_{33} \end{vmatrix} + a_{23} (-1)^{2 + 3} \begin{vmatrix} a_{11} & a_{12} \\ a_{31} & a_{32} \end{vmatrix} $$
ここで思い出して欲しいのが、元々の正方行列 \(A\) が3次の正方行列であったという点です。
それに対し、上記の余因子展開を利用した計算式の右辺に注目すれば分かる通り、右辺で求める必要がある行列式は2次の正方行列のもののみです。すなわち、2次の行列式のみから3次の行列式を求めることができています。
ここが行列式算出次に余因子展開を利用する一番のポイントで、余因子展開を利用した場合、次数を1つ落とした行列式から行列式を算出することが可能です。
4次の行列式の算出
ですので、余因子展開を利用すれば、4次の行列式は「3次の行列式」さえ解ければ算出可能ということになります。
例えば下記のような4次の正方行列 \(A\) であれば、
$$ A = \left ( \begin{array}{cccc} a_{11} & a_{12} & a_{13} & a_{14} \\ a_{21} & a_{22} & a_{23} & a_{24} \\ a_{31} & a_{32} & a_{33} & a_{34} \\ a_{41} & a_{42} & a_{43} & a_{44} \end{array} \right ) $$
1 列目に対して余因子展開すれば、下記の式で行列式を求めることができます。
$$ \begin{vmatrix} A \end{vmatrix} = a_{11} (-1)^{1 + 1} \begin{vmatrix} a_{22} & a_{23} & a_{24} \\ a_{32} & a_{33} & a_{34} \\ a_{42} & a_{43} & a_{44} \end{vmatrix} + a_{21} (-1)^{2 + 1} \begin{vmatrix} a_{12} & a_{13} & a_{14} \\ a_{32} & a_{33} & a_{34} \\ a_{42} & a_{43} & a_{44} \end{vmatrix} \\ + a_{31} (-1)^{3 + 1} \begin{vmatrix} a_{12} & a_{13} & a_{14} \\ a_{22} & a_{23} & a_{24} \\ a_{42} & a_{43} & a_{44} \end{vmatrix} + a_{41} (-1)^{4 + 1} \begin{vmatrix} a_{12} & a_{13} & a_{14} \\ a_{22} & a_{23} & a_{24} \\ a_{32} & a_{33} & a_{34} \end{vmatrix} $$
あとは右辺の各項に現れる3次の行列式を解き、その結果を利用して上記の右辺を解けば良いだけです。
3次の行列式の解き方については下記ページで解説していますので、それを利用すればすぐに解くことができるはずです。
【C言語】3次以下の行列式の求め方え?3次の行列式の計算式がややこしくて使いたくない?
であれば、各項の3次の行列式それぞれに対してさらに余因子展開を利用して次数を落としてやれば良いです。
これで2次の行列式の計算を行えば良いだけですね!
え?2次の行列式の計算式を記述するのもめんどくさい?
であれば、先ほどの余因子展開で現れた2次の行列式それぞれに対してさらに余因子展開を利用して次数を落としてやれば良いです。
これで計算する必要があるのは1次の行列式だけであり、1次の場合は行列の成分そのものが行列式となるのでもう自明ですね!
こんな感じで、一度の余因子展開では次数が1下がるのみですが、それを段階的に繰り返すことで次数をさらに下げることができます。
そして、あなたが行列式を計算できる次数まで下がった時に、行列式を計算してやれば良いだけです。
N次の行列式の算出
ですので、5次以上の行列式についても同様で、余因子展開を段階的に繰り返していけば、計算する必要のある行列式の次数を3以下まで下げることができます。
あとは、その行列式を計算式に当てはめて解いてやれば行列式を解くことができます。
なので、余因子展開が扱えれば、理論上はどんな次数の行列式も求めることができるようになったことになります!ただ、あくまでも理論上の話で、次数が大きいほど計算量が多くなるので、次数が大きいと時間がかかりすぎて行列式を解くことはできません。
それでも10次程度の行列式であれば1秒くらいで解くことはできると思います(もちろんプログラムを実行する PC のスペックにもよります)。
また、余因子展開すればするほど式はどんどん複雑になっていくことになりますが、プログラムの場合は再帰呼び出しを利用すればすんなり解くことができるので安心してください!
スポンサーリンク
余因子展開を利用した行列式の算出の実装方法
続いて「余因子展開を利用した行列式の算出を行うプログラム」のC言語での実装について解説していきたいと思います。
前述の通り、再帰呼び出しを利用して行列式を算出していきたいと思います。
行列式を求める関数の準備
まず最初に、行列式を求める関数として下記を用意します。
int det(int **mat, int n) {
}
まだ空関数ですが、以降の解説の中で、この det
関数を「n
次の正方行列 mat
の行列式を返却する関数」として作成していきたいと思います。
n
は 1
以上の自然数を想定しており、mat
は下記ページの ポインタで行列を扱う で紹介している createMatrix
関数により作成される行列であることを想定した関数となっています(createMatrix
関数で作成しなくても、n
次の正方行列を指す int **
型のポインタであれば引数 mat
に指定可能です)。
1次の行列式を求める
まずは det
関数で1次の行列式を求められるようにしていきたいと思います。
1次の行列式の求め方は下記ページでも解説していますが、
【C言語】3次以下の行列式の求め方1次の正方行列の成分は1つのみであり、その成分そのものが行列式となります。
したがって、det
関数を下記のように変更すれば、det
関数で1次の正方行列 mat
の行列式を求めることができるようになります。
int det(int **mat, int n) {
if (n == 1) {
/* 1次の行列式を算出して返却 */
return mat[0][0];
}
}
スポンサーリンク
N
次の行列式を求める
ここからがいよいよ本番で、余因子展開を利用して N
次の正方行列の行列式を解けるように det
関数を変更していきます。
余因子を求める
まずは、1つの余因子を求めることを考えていきたいと思います。
余因子展開を利用した行列式の求め方 で解説した通り、余因子 \(A_{ij}\) は「正方行列 \(A\) の \(i\) 行目と \(j\) 列目を取り除いた正方行列の行列式に \((-1)^{i + j}\) を掛けたもの」となります。
ここで「正方行列 \(A\) の \(i\) 行目と \(j\) 列目を取り除いた正方行列」を作成することを考えたいと思います。
この正方行列を s_mat
とすれば、det
関数では引数 mat
で正方行列 \(A\) が与えられるため、次のような処理により、上記の正方行列 s_mat
を作成することができます。
/* i行とj列の成分を除いた行列を作成 */
num_r = 0;
for (r = 0; r < n; r++) {
if (r == i) {
/* i行目の成分は行列に格納しない */
continue;
}
num_c = 0;
for (c = 0; c < n; c++) {
if (c == j) {
/* j行目の成分は行列に格納しない */
continue;
}
/* 行列にi行とj列の成分以外を格納 */
s_mat[num_r][num_c] = mat[r][c];
/* 行列に格納した個数(列方向)をカウントアップ */
num_c++;
}
/* 行列に格納した個数(行方向)をカウントアップ */
num_r++;
}
上記のループ処理の中では、行を表す添字 r
が i
以外の場合と列を表す添字 c
が j
以外の場合のみ mat
の成分を s_mat
に格納する処理を行なっています。そのため、上記の処理が完了した際には、s_mat
は正方行列 mat
の i
行目とj
列目を取り除いた正方行列となります。
この正方行列 s_mat
は、行・列とも mat
よりも 1
少ないので、n - 1
次の正方行列となります。
さらに、余因子とは、この正方行列の行列式に \((-1)^{i + j}\) を掛けたものとなります。
まず \((-1)^{i + j}\) とは、結局は \(i + j\) が偶数の時に \(1\) になり、奇数の時に \(-1\) になる計算式です。
また、現状 n - 1
次の行列式を解く関数が存在しないですが、その関数名を仮で n-1次行列式
としておくことにすれば、余因子 \(A_{ij}\) は下記により求めることができることになります。
/* 符号を算出 */
if ((i + j) % 2 == 0) {
sign = 1;
} else {
sign = -1;
}
/* (i,j) に対する余因子を求める */
cofactor_i_j = sign * n-1次行列式(s_mat);
この cofactor_i_j
が、行列 mat
の (i
, j
) に対する余因子となります。
n-1次行列式
の関数が用意できていないので現状ではコンパイルが通りませんので、n-1次行列式
の部分は後から差し替えて対応します。
数学で扱う行列の成分の添字が \(1\) から始まるのに対し、C言語の配列で扱う添字は 0
から始まります
そのことを考慮すれば、\((-1)^{i + j}\) と同等の処理を行うための判断式である ((i + j) % 2 == 0)
は ((i + 1 + j + 1) % 2 == 0)
と書いた方が正確かもしれませんが、いずれにせよ必ず結果は必ず一緒になるため、上記では ((i + j) % 2 == 0)
により判断を行うようにしています
余因子展開を利用して行列式を求める
余因子を求められるようになったので、次は余因子展開を利用して n
次の正方行列 mat
の行列式を求めるようにしていきたいと思います。
余因子展開を利用した行列式の求め方 で解説した通り、余因子展開とは “ある行” or “ある列” に対する全ての成分と余因子との積を足し合わせることであり、この結果が行列式の結果と一致します。
今回は、この余因子展開を 0
列目に対して行うようにしたいと思います。
この場合、余因子展開を利用した行列式の算出は、列を表す添字 j
を 0
に固定した状態で i
を 0
から n - 1
まで変化させながら 余因子を求める で紹介した処理により各因子 cofactor_i_j
を求め、その求めた cofactor_i_j
と行列 mat
の成分 mat[i][j]
を足し合わせていくことにより実現することができます。
具体的には下記の処理により、n
次の正方行列 mat
の行列式 det
を求めることができます。
/* 展開する列を設定 */
j = 0;
/* n次の行列式を一旦0にセット */
det_n = 0;
/* j列に対して余因子展開 */
for (i = 0; i < n; i++) {
/* cofactor_i_jを求める */
/* (i,j)に対する余因子と(i,j)成分を掛けたものを足し合わせる */
det_n += mat[i][j] * cofactor_i_j;
}
上記のループ処理完了後の det_n
が det
関数で返却すべき行列式となります。
余因子展開を利用して行列式を求める関数
ここまでの解説を全て踏まえ、さらに変数宣言や行列の作成等も行うようにすれば、det
関数は下記のようになります。
int det(int **mat, int n) {
int **s_mat = NULL;
int i, j; /* 余因子を求める行と列 */
int r, c; /* 行と列 */
int num_r, num_c; /* 行列に成分を格納した個数(行と列) */
int det_n; /* n次の行列式の算出結果 */
int cofactor_i_j; /* (i,j)余因子 */
int sign; /* 余因子展開した項の符号 */
if (n == 1) {
/* 1次の行列式を算出して返却 */
return mat[0][0];
}
/* n-1次の正方行列を作成 */
s_mat = createMatrix(n - 1, n - 1);
if (s_mat == NULL) {
printf("malloc error\n");
return 0;
}
/* 展開する列を設定 */
j = 0;
/* n次の行列式を一旦0にセット */
det_n = 0;
/* j列に対して余因子展開 */
for (i = 0; i < n; i++) {
/* i行とj列の成分を除いた行列を作成 */
num_r = 0;
for (r = 0; r < n; r++) {
if (r == i) {
/* i行目の成分は行列に格納しない */
continue;
}
num_c = 0;
for (c = 0; c < n; c++) {
if (c == j) {
/* j行目の成分は行列に格納しない */
continue;
}
/* 行列にi行とj列の成分以外を格納 */
s_mat[num_r][num_c] = mat[r][c];
/* 行列に格納した個数(列方向)をカウントアップ */
num_c++;
}
/* 行列に格納した個数(行方向)をカウントアップ */
num_r++;
}
/* 符号を算出 */
if ((i + j) % 2 == 0) {
sign = 1;
} else {
sign = -1;
}
/* (i,j)に対する余因子を求める */
cofactor_i_j = sign * n-1次の行列式(s_mat);
/* (i,j)に対する余因子と(i,j)成分を掛けたものを足し合わせる */
det_n += mat[i][j] * cofactor_i_j;
}
/* 行列を削除 */
deleteMatrix(s_mat, n - 1);
/* n次の行列式を返却 */
return det_n;
}
行列をポインタで扱うため、s_mat
は2次元配列ではなくポインタのポインタとして変数宣言しています。
そのため、下記ページで紹介している createMatrix
関数を実行することで行列の作成(行列用のメモリの確保)を行なっています。
createMatrix
関数の中では malloc
関数を利用してメモリを確保しているため、行列を使い終わった際にはメモリを解放する必要があります。
これを行なっているのが、return
直前に実行している deleteMatrix
関数となります。
この関数についても上記ページで紹介しています。
わざわざポインタで扱う理由は、次に説明する再帰呼び出しが関係しています。
det
関数の再起呼び出しを行う
ただし、先ほど紹介した det
関数は不完全で、n - 1
次の行列式を求める関数の呼び出しが行われていません。
/* (i,j)に対する余因子を求める */
cofactor_i_j = sign * n-1次の行列式(s_mat);
この n - 1
次の行列式を求める関数は、上記を次のように書き換えることで完成します。
/* (i,j)に対する余因子を求める */
cofactor_i_j = sign * det(s_mat, n - 1);
すなわち、det
関数の中から第2引数に n - 1
を指定して det
関数自身を実行することで、n - 1
次の行列式を求めます。このように、関数の中から関数自身を呼び出すことを再帰呼び出しと言います。
そして、上記のように変更することで det
関数も完成したことになり、これにより N
次の行列式を求めることが可能になりました!
ただし、N
が大きいと時間がかかりすぎて関数が終わらなくなったりメモリが足りなくなって行列式が上手く求められない場合があったりするので注意してください。この方法だと、現在の PC のスペックだと N = 12
くらいが限界かなぁという印象です。
また、行列式の算出先となる変数の型が int
なので、N
が大きいとオーバーフローが発生するので注意してください。N
が 5
程度であっても行列の成分の値が大きいとオーバーフローが発生して上手く行列式が求められません。必要に応じて変数の型を long
や long long
等に変更してやる必要があります。
det
関数で N
次の行列式が求められる理由
実装の仕方の最後の解説として、上記の det
関数で N
次の行列式が求められる理由を簡単に解説しておきます。
まず、det
関数で 1
次の行列式が求められることは納得していただけると思います。det
関数では下記の処理を行なっているので、1
次の行列式は下記部分で求めることができます。
if (n == 1) {
/* 1次の行列式を算出して返却 */
return mat[0][0];
}
また、2
次の行列式について考えると、余因子展開を利用した行列式の求め方 で解説した通り、余因子展開を利用すれば行列式は1次下げた状態の行列式から求めることができるため、この 2
次の行列式を求めるためには 1
次の行列式さえ求めれば良いことになります。
さらに、2
次の行列式を求める際には引数 n
が 2
になっていますので、下記では det
関数で 1
次の行列式を求めることになります。
cofactor_i_j = sign * det(s_mat, n - 1);
前述の通り、det
関数では 1
次の行列式を求めることが可能ですので、結果的に det
関数は 2
次の行列式も求めることも可能ということになります。
3
次の行列式の場合も同様ですね!
3
次の行列式は余因子展開を利用すれば 2
次の行列式から求めることができます。
n = 3
の状態で下記のように det
関数を実行すれば 2
次の行列式を求めることになりますが、前述の通り、det
関数は 2
次の行列式を求めることが可能です。
cofactor_i_j = sign * det(s_mat, n - 1);
したがって、det
関数は 3
次の行列式も求めることも可能ということになります。
あとは同様で、N
次の行列式は余因子展開を利用すれば N - 1
次の行列式から求めることができ、さらに n = N
の状態で下記のように det
関数を実行すれば N - 1
次の行列式が求められますので、結果的に det
関数は N
次の行列式も求めることが可能ということになります。
cofactor_i_j = sign * det(s_mat, n - 1);
おそらく 余因子展開を利用した行列式の求め方 の解説を読んだ時の印象よりも、det
関数がシンプルだったと思った方も多いのではないかと思います。
ポイントは再帰呼び出しで、この再帰呼び出しを利用すれば「難しい問題」を簡単に解けることが多いです。
下記ページで迷路を例に再帰呼び出しの解説をしていますので、興味がある方は下記ページを読んでみていただければと思います。迷路も再帰呼び出しを利用すれば簡単に解けます!
【C言語】「再帰呼び出しの動き・メリット・書き方」を迷路を解いて理解するただ、1点注意があって、再帰呼び出しは難しい問題を簡単に解く素晴らしい手法ではあるのですが、スタックオーバーフローが発生しやすいので注意してください。発生するとプログラムが異常終了する可能性が高いです。
特に、再帰呼び出しを行う関数内で大きな配列などを変数宣言すると、よりスタックオーバーフローが発生しやすくなります。
その対策の意味も含めて、行列は det
関数内で配列として宣言するのではなく、createMatrix
関数の中で malloc
関数を利用して行列に必要なメモリを確保し、行列はポインタで扱うようにしています。
それでも PC にメモリが足りない場合や求める行列の次数が大きいとメモリ不足になって malloc
関数でエラーが発生してしまう可能性はあるので注意してください。
この場合は、下記のエラーメッセージが表示されます。このメッセージが出た場合は表示される行列式がデタラメな値になるので注意してください(メモリが足りないと計算できない)。
malloc error
余因子展開を利用した行列式の算出プログラムの例
最後に、先ほど解説した det
関数を呼び出す部分も含め、余因子展開を利用した行列式の算出プログラムのソースコード全体を載せておきます。
#include <stdio.h&g;t
#include <stdlib.h>
#define N 4 /* 正方行列の次数 */
/**************************************
* m行n列の行列用のメモリを確保(成分の型はint)
* m:行列の行数
* n:行列の列数
* 返却値:確保したメモリの先頭アドレス(失敗時はNULL)
**************************************/
int **createMatrix(unsigned int m, unsigned int n) {
int **mat;
unsigned int i, j;
if (n == 0 || m == 0) {
printf("n or m is 0\n");
return NULL;
}
/* m行分のポインタ格納用のメモリを確保 */
mat = malloc(sizeof(int *) * m);
if (mat == NULL) {
return NULL;
}
for (i = 0; i < m; i++) {
/* 1行分ずつメモリを確保する */
/* n列分のint型のデータが格納できるメモリを確保 */
mat[i] = malloc(sizeof(int) * n);
if (mat[i] == NULL) {
printf("malloc error\n");
for (j = 0; j < i; j++) {
free(mat[i]);
}
free(mat);
return NULL;
}
}
return mat;
}
/**************************************
* 行列用のメモリを解放
* m:行列の行数
* 返却値:なし
**************************************/
void deleteMatrix(int **mat, unsigned int m) {
unsigned int i;
for (i = 0; i < m; i++) {
free(mat[i]);
}
free(mat);
}
int det(int **mat, int n) {
int **s_mat = NULL;
int i, j; /* 余因子を求める行と列 */
int r, c; /* 行と列 */
int num_r, num_c; /* 行列に成分を格納した個数(行と列) */
int det_n; /* n次の行列式の算出結果 */
int cofactor_i_j; /* (i,j)余因子 */
int sign; /* 余因子展開した項の符号 */
if (n == 1) {
/* 1次の行列式を算出して返却 */
return mat[0][0];
}
/* n-1次の正方行列を作成 */
s_mat = createMatrix(n - 1, n - 1);
if (s_mat == NULL) {
printf("malloc error\n");
return 0;
}
/* 展開する列を設定 */
j = 0;
/* n次の行列式を一旦0にセット */
det_n = 0;
/* j列に対して余因子展開 */
for (i = 0; i < n; i++) {
/* i行とj列の成分を除いた行列を作成 */
num_r = 0;
for (r = 0; r < n; r++) {
if (r == i) {
/* i行目の成分は行列に格納しない */
continue;
}
num_c = 0;
for (c = 0; c < n; c++) {
if (c == j) {
/* j行目の成分は行列に格納しない */
continue;
}
/* 行列にi行とj列の成分以外を格納 */
s_mat[num_r][num_c] = mat[r][c];
/* 行列に格納した個数(列方向)をカウントアップ */
num_c++;
}
/* 行列に格納した個数(行方向)をカウントアップ */
num_r++;
}
/* 符号を算出 */
if ((i + j) % 2 == 0) {
sign = 1;
} else {
sign = -1;
}
/* (i,j)に対する余因子を求める */
cofactor_i_j = sign * det(s_mat, n - 1);
/* (i,j)に対する余因子と(i,j)成分を掛けたものを足し合わせる */
det_n += mat[i][j] * cofactor_i_j;
}
/* 行列を削除 */
deleteMatrix(s_mat, n - 1);
/* n次の行列式を返却 */
return det_n;
}
int main(void) {
int **mat;
/* N次の正方行列を作成 */
mat = createMatrix(N, N);
if (mat == NULL) {
return 0;
}
/* 行列の各成分を格納 */
mat[0][0] = 2; mat[0][1] = 1; mat[0][2] = 5; mat[0][3] = 3;
mat[1][0] = 3; mat[1][1] = 0; mat[1][2] = 1; mat[1][3] = 6;
mat[2][0] = 1; mat[2][1] = 4; mat[2][2] = 3; mat[2][3] = 3;
mat[3][0] = 8; mat[3][1] = 2; mat[3][2] = 0; mat[3][3] = 1;
/* 行列式を求めて表示 */
printf("%d\n", det(mat, N));
/* 不要になった行列を削除 */
deleteMatrix(mat, N);
return 0;
}
実行すれば、下記のように det
関数で求められた行列式が表示されます。
-742
また、main
関数で mat
に格納する成分を変更してやれば他の行列の行列式を求めることもできますし、ソースコード先頭部分の N
の定義値を変更すれば他の次数の行列式も求めることができます。
ただし、前述の通り、オーバーフローが発生する可能性もありますし、N
が大きいと処理時間がかかりすぎて関数が終了しなくなる可能性もあるので注意してください。
まとめ
このページでは、C言語での「余因子展開を利用した行列式の求め方」について解説しました!
余因子展開を利用すれば、行列式を次数を1つ下げた行列式の解より求めることができます。ですので、4次の行列式は3次の行列式の解から求めることができ、3次の行列式さえ解くことができれば、4次の行列式も解くことができることになります。
さらに余因子展開を段階的に繰り返すことで、解く必要のある行列式の次数をどんどん下げていくことができ、大きな次数の行列式も3次の行列式 or 2次の行列式 or 1次の行列式を解くことで求めることができるようになります!
余因子展開を利用した行列式の算出は、手で計算するとめちゃめちゃ大変ですが、プログラムは割と簡単に作成することができます。
で、このプログラムを作成する時にポイントになるのが再帰呼び出しです。
余因子展開を利用した行列式の算出は、再帰呼び出しの動作を理解したり便利さを実感したりするのにも良い題材だと思いますので、このページで解説した内容はぜひ理解していってください!
ただ、今回紹介した余因子展開を利用した行列式の算出は処理速度的には遅く、高速に行列式を求めたい場合は行列の基本変形を利用して行列式を算出するのが良いと思います。
「行列の基本変形を利用した行列式の求め方」については下記ページで解説していますので、興味のある方はぜひこちらのページも読んでみていただければと思います!
【C言語】行列の基本変形を利用した行列式の求め方