1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

C言語で行列計算

Last updated at Posted at 2023-09-27

アルゴリズム

行列Aと行列Bの積は、以下の手順で行われる。

  1. 行列Aの行番号iを固定して列番号jを動かす。
  2. 行列Bの列番号countを固定して行番号jを動かす

プログラムを書くポイント

for文を二重ループにして計算することを考えると、

for(int i=0;i<N;i++){
    for(int j=0;j<N;j++){
        // ここの中身はiが固定されたまま、jが変化していく
    }
}

このとき、計算するたびに動かしたい行列Aの列番号と行列Bの行番号はjにすることが考えられる。
また、行列Aの行番号はfor文の二重ループの順番通りにアクセスできれば良い。

for(int i=0;i<N;i++){
    for(int j=0;j<N;j++){
        printf("%d", matA[i][j]);
    }
}

// 出力は、2×2の行列の場合
// matA[0][0]
// matA[0][1]
// matA[1][0]
// matA[1][1]
// の順に表示される

一方、行列Bの列番号については要素iとは別で固定してループさせる必要がある。
具体的には変数iを固定したまま、変数jのfor文を行列Bの列数分実行したい。
そこで、変数iを回すfor文の中に、変数jを回すfor文を内包するループを設ける。

プログラム

#include <stdio.h>
// # define N

int main(void){
    // 計算する行列はここで定義
    int N = 2; // 2×2の正方行列とする
    int matA[2][2] = {{1, 2}, {1, 2}};
    int matB[2][2] = {{3, 4}, {4, 1};

    int element = 0; // 計算結果の各要素

    // 以下のコメントアウトではi=0, j=0の時の計算を見てみる。
    
    for(int i=0;i<N;i++){
        int count = 0;
        while(count<N){
            element =0;
            for (int j=0;j<N;j++){
                /*
                計算結果として出力したいのは、
                i=0, j=0, count=0のとき
                    element += matA[0, 0]*matB[0, 0] = 1*3
                i=0, j=1, count=0のとき
                    element += matA[0, 1]*matB[1, 0] = 2*4
                */
                
                element += matA[i][j]*matB[j][count];
            }

            // 変数jのfor文を抜けたら出力
            // 計算結果 element = 計算結果の行列[0][0] = 1*3+2*4 = 11
            // ちなみに変数elementは計算結果の行列[i][count]に相当。
            printf("%d\n", element); 
            count += 1;
        }
    }
}

解説

変数の値を書き下してみる。

i j count
0 0 0
0 1 0
0 0 1
0 1 1
1 0 0
1 1 0
1 0 1
1 1 1

この順番でfor文を回すと、変数iとjが行列Aの要素にアクセスする順番、
変数countと変数jが行列Bの要素にアクセスする順番になっていることが分かる。

改良

上のプログラムだとちょっとわかりにくいので、変数名をいじってもう少し分かりやすくする。

変数名は以下のように設定し直す。

  • 変数countは名前がおかしいので、i, jの次のアルファベットであるkにする。

nrowA = the number of rows of matrix A

  • 行列Aの行数:nrowA
  • 行列Bの列数:ncolB (=nrowA)
  • 行列Aの列数:ncolA
  • 行列Bの行数:nrowB

  • 計算結果の行列:matR
#include <stdio.h>
int main(void){

    // 2×2の正方行列とする
    int nrowA =2;
    int ncolA= 2 ;
    int nrowB = 2;
    
    int matA[2][2] = {{1, 2}, {1, 2}};
    int matB[2][2] = {{3, 4}, {4, 1}};
    int matR[2][2];
    
    for(int i=0;i<nrowA;i++){
        for(int k=0;k<nrowB;k++){
            matR[i][k] = 0;
            for(int j=0;j<ncolA;j++){
                matR[i][k] += matA[i][j]*matB[j][k];
            }
            printf("%d\n", matR[i][k]);
        }
    }

}

感想

深夜テンションでプログラムを作ったので、なんか気持ち悪いプログラムになったかも。数学的にいい感じのインデックス名の付け方とかなかったかな...

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?