C言語で行列の四則演算(足し算,引き算,掛け算,割り算)を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
行列の四則演算(足し算,引き算,掛け算,割り算)
C言語で行列の四則演算(足し算,引き算,掛け算,割り算)を紹介します.
行列の四則演算でよく利用される2次元配列でコードを実装します.
行列の足し算と引き算
行列AとBによる足し算(A + B)と引き算(A - B)は下式になります.
\begin{eqnarray*}
A + B &:=& [a_{ij} + b_{ij}]\ \ \ (i = 1, ..., m)\ (j = 1, ..., n) \\
A - B &:=& [a_{ij} - b_{ij}]\ \ \ (i = 1, ..., m)\ (j = 1, ..., n)
\end{eqnarray*}
3*3行列AとBの足し算と引き算の例は以下になります.
\begin{eqnarray*}
A + B &=&
\begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9 \\
\end{bmatrix}
+
\begin{bmatrix}
1 & 1 & 1 \\
2 & 2 & 2 \\
3 & 3 & 3 \\
\end{bmatrix}
=
\begin{bmatrix}
2 & 3 & 4 \\
6 & 7 & 8 \\
10 & 11 & 12 \\
\end{bmatrix} \\
A - B &=&
\begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9 \\
\end{bmatrix}
-
\begin{bmatrix}
1 & 1 & 1 \\
2 & 2 & 2 \\
3 & 3 & 3 \\
\end{bmatrix}
=
\begin{bmatrix}
0 & 1 & 2 \\
2 & 3 & 4 \\
4 & 5 & 6 \\
\end{bmatrix}
\end{eqnarray*}
3*3行列AとBの足し算と引き算のコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #define N 3 void print_matrix(int a[N][N]) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%d ", a[i][j]); } printf("\n"); } } int main(void) { int a[N][N] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; int b[N][N] = {{1, 1, 1}, {2, 2, 2}, {3, 3, 3}}; int add[N][N], sub[N][N]; int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { add[i][j] = a[i][j] + b[i][j]; sub[i][j] = a[i][j] - b[i][j]; } } printf("A:\n"); print_matrix(a); printf("B:\n"); print_matrix(b); printf("A + B:\n"); print_matrix(add); printf("A - B:\n"); print_matrix(sub); return 0; } |
実行結果は以下になります.
例で紹介した足し算と引き算の結果と同じです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ gcc matrices_add_sub.c $ a.out A: 1 2 3 4 5 6 7 8 9 B: 1 1 1 2 2 2 3 3 3 A + B: 2 3 4 6 7 8 10 11 12 A - B: 0 1 2 2 3 4 4 5 6 |
行列の掛け算
行列AとBによる掛け算(A*B)は下式になります.
\begin{eqnarray*}
A * B &:=& [c_{ij}]\ \ \ (i = 1, ..., m)\ (j = 1, ..., n) \\
c_{ij} &=& \sum_{k=1}^m a_{ik} b_{kj}
\end{eqnarray*}
3*3行列AとBの掛け算の例は以下になります.
\begin{eqnarray*}
A + B &=&
\begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9 \\
\end{bmatrix}
*
\begin{bmatrix}
3 & 6 & 9 \\
2 & 5 & 8 \\
1 & 4 & 7 \\
\end{bmatrix} \\
&=&
\begin{bmatrix}
1 * 3 + 2 * 2 + 3 * 1 & 1 * 6 + 2 * 5 + 3 * 4 & 1 * 9 + 2 * 8 + 3 * 7 \\
4 * 3 + 5 * 2 + 6 * 1 & 4 * 6 + 5 * 5 + 6 * 4 & 4 * 9 + 5 * 8 + 6 * 7 \\
7 * 3 + 8 * 2 + 9 * 1 & 7 * 6 + 8 * 5 + 9 * 4 & 7 * 9 + 8 * 8 + 9 * 7 \\
\end{bmatrix} \\
&=&
\begin{bmatrix}
10 & 28 & 46 \\
28 & 73 & 118 \\
46 & 118 & 190 \\
\end{bmatrix}
\end{eqnarray*}
3*3行列AとBの掛け算のコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #define N 3 void print_matrix(int a[N][N]) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%d ", a[i][j]); } printf("\n"); } } int main(void) { int a[N][N] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; int b[N][N] = {{3, 6, 9}, {2, 5, 8}, {1, 4, 7}}; int mul[N][N]; int i, j, k; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { mul[i][j] = 0; for (k = 0; k < N; k++) { mul[i][j] += a[i][k] * b[k][j]; } } } printf("A * B:\n"); print_matrix(mul); return 0; } |
実行結果は以下になります.
例で紹介した掛け算の結果と同じです.
1 2 3 4 5 6 |
$ gcc matrices_mul.c $ a.out A * B: 10 28 46 28 73 118 46 118 190 |
行列の割り算(逆行列の掛け算)
行列の割り算はありません.
ただし,逆行列を掛け算することで割り算相当の処理を代替します.
逆行列\(A^{-1}\)とは,正則行列\(A\)と掛け算をした時に単位行列\(E\)(対角成分は1,他は全て0)になる行列のことです.
これを満たす\(A^{-1}\)を\(A\)の逆行列と呼びます.
つまり,正則行列\(A\),逆行列\(A^{-1}\),単位行列\(E\)の関係は下式になります.
$$AA^{-1} = E = A^{-1}A$$
2*2行列の逆行列
2*2行列\(A\)と逆行列\(A^{-1}\)は下式になります.
\begin{eqnarray*}
A &=&
\begin{bmatrix}
a_{11} & a_{12} \\
a_{21} & a_{22} \\
\end{bmatrix} \\
A^{-1} &=&
\frac{1}{a_{11} a_{22} - a_{12} a_{21}}
\begin{bmatrix}
a_{22} & -a_{12} \\
-a_{21} & a_{11} \\
\end{bmatrix}
\end{eqnarray*}
ここで,\(A\)が正則行列になり,逆行列\(A^{-1}\)を持つのは\(a_{11} a_{22} -a_{12} a_{21} \ne 0\)の時のみです.
※\(a_{11} a_{22} -a_{12} a_{21} = 0\)の時,\(A^{-1}\)の分母は0になってしまいます.
2*2行列\(A\)の逆行列\(A^{-1}\)の例は以下になります.
\begin{eqnarray*}
A &=&
\begin{bmatrix}
1 & 2 \\
3 & 4 \\
\end{bmatrix} \\
A^{-1} &=&
\frac{1}{1 * 4 - 2 * 3}
\begin{bmatrix}
4 & -2 \\
-3 & 1 \\
\end{bmatrix}
=
\begin{bmatrix}
-2 & 1 \\
1.5 & -0.5 \\
\end{bmatrix}
\end{eqnarray*}
2*2行列\(A\)の逆行列\(A^{-1}\)を計算するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <float.h> #include <math.h> #define N 2 void print_matrix(double a[N][N]) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%lf ", a[i][j]); } printf("\n"); } } int main(void) { double a[N][N] = {{1.0, 2.0}, {3.0, 4.0}}; double b[N][N]; double det = a[0][0] * a[1][1] - a[0][1] * a[1][0]; if (fabs(det) <= DBL_EPSILON) { fprintf(stderr, "Error: cannot find inverse matrix.\n"); exit(1); } b[0][0] = a[1][1] / det; b[0][1] = -a[0][1] / det; b[1][0] = -a[1][0] / det; b[1][1] = a[0][0] / det; printf("A:\n"); print_matrix(a); printf("A^{-1}:\n"); print_matrix(b); return 0; } |
実行結果は以下になります.
例で紹介した2*2行列の逆行列の結果と同じです.
1 2 3 4 5 6 7 8 |
$ gcc matrices_inverse_2x2.c $ a.out A: 1.000000 2.000000 3.000000 4.000000 A^{-1}: -2.000000 1.000000 1.500000 -0.500000 |
3*3行列の逆行列
3*3行列\(A\)と逆行列\(A^{-1}\)は下式になります.
\begin{eqnarray*}
A &=&
\begin{bmatrix}
a_{11} & a_{12} & a_{13} \\
a_{21} & a_{22} & a_{23} \\
a_{31} & a_{32} & a_{33} \\
\end{bmatrix} \\
A^{-1} &=&
\frac{1}{a_{11} a_{22} a_{33} + a_{12} a_{23} a_{31} + a_{13} a_{21} a_{32} - a_{13} a_{22} a_{31} - a_{12} a_{21} a_{33} - a_{11} a_{23} a_{32}} \\
\\
&& *
\begin{bmatrix}
a_{22} a_{33} - a_{23} a_{32} & - (a_{12} a_{33} - a_{13} a_{32}) & a_{12} a_{23} - a_{13} a_{22} \\
- (a_{21} a_{33} - a_{23} a_{31}) & a_{11} a_{33} - a_{13} a_{31} & - (a_{11} a_{23} - a_{13} a_{21}) \\
a_{21} a_{32} - a_{22} a_{31} & - (a_{11} a_{32} - a_{12} a_{31}) & a_{11} a_{22} - a_{12} a_{21} \\
\end{bmatrix} \\
\end{eqnarray*}
3*3行列\(A\)の逆行列\(A^{-1}\)の例は以下になります.
\begin{eqnarray*}
A &=&
\begin{bmatrix}
1 & 2 & 3 \\
6 & 5 & 4 \\
8 & 7 & 9 \\
\end{bmatrix} \\
A^{-1} &=&
\frac{1}{1 * 5 * 9 + 2 * 4 * 8 + 3 * 6 * 7 - 3 * 5 * 8 - 2 * 6 * 9 - 1 * 4 * 7} \\
\\
&& *
\begin{bmatrix}
5 * 9 - 4 * 7 & - (2 * 9 - 3 * 7) & 2 * 4 - 3 * 5 \\
- (6 * 9 - 4 * 8) & 1 * 9 - 3 * 8 & - (1 * 4 - 3 * 6) \\
6 * 7 - 5 * 8 & - (1 * 7 - 2 * 8) & 1 * 5 - 2 * 6 \\
\end{bmatrix} \\
&=&
\begin{bmatrix}
-0.809524 & -0.142857 & 0.333333 \\
1.047619 & 0.714286 & -0.666667 \\
-0.095238 & -0.428571 & 0.333333 \\
\end{bmatrix} \\
\end{eqnarray*}
3*3行列\(A\)の逆行列\(A^{-1}\)を計算するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <float.h> #include <math.h> #define N 3 void print_matrix(double a[N][N]) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%lf ", a[i][j]); } printf("\n"); } } int main(void) { double a[N][N] = {{1.0, 2.0, 3.0}, {6.0, 5.0, 4.0}, {8.0, 7.0, 9.0}}; double b[N][N]; double det = a[0][0] * a[1][1] * a[2][2] + a[0][1] * a[1][2] * a[2][0] + a[0][2] * a[1][0] * a[2][1] - a[0][2] * a[1][1] * a[2][0] - a[0][1] * a[1][0] * a[2][2] - a[0][0] * a[1][2] * a[2][1]; if (fabs(det) <= DBL_EPSILON) { fprintf(stderr, "Error: cannot find inverse matrix.\n"); exit(1); } b[0][0] = (a[1][1] * a[2][2] - a[1][2] * a[2][1]) / det; b[0][1] = - (a[0][1] * a[2][2] - a[0][2] * a[2][1]) / det; b[0][2] = (a[0][1] * a[1][2] - a[0][2] * a[1][1]) / det; b[1][0] = - (a[1][0] * a[2][2] - a[1][2] * a[2][0]) / det; b[1][1] = (a[0][0] * a[2][2] - a[0][2] * a[2][0]) / det; b[1][2] = - (a[0][0] * a[1][2] - a[0][2] * a[1][0]) / det; b[2][0] = (a[1][0] * a[2][1] - a[1][1] * a[2][0]) / det; b[2][1] = - (a[0][0] * a[2][1] - a[0][1] * a[2][0]) / det; b[2][2] = (a[0][0] * a[1][1] - a[0][1] * a[1][0]) / det; printf("A:\n"); print_matrix(a); printf("A^{-1}:\n"); print_matrix(b); return 0; } |
実行結果は以下になります.
例で紹介した3*3行列の逆行列の結果と同じです.
1 2 3 4 5 6 7 8 9 10 |
$ gcc matrices_inverse_3x3.c $ a.out A: 1.000000 2.000000 3.000000 6.000000 5.000000 4.000000 8.000000 7.000000 9.000000 A^{-1}: -0.809524 -0.142857 0.333333 1.047619 0.714286 -0.666667 -0.095238 -0.428571 0.333333 |
まとめ
C言語で行列の四則演算(足し算,引き算,掛け算,割り算)を紹介しました.
行列の四則演算でよく利用される2次元配列でコードを実装しました.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!