C 言語による行列の乗算

CBeginner
オンラインで実践に進む

はじめに

この実験では、C 言語で 2 つの行列を乗算する方法を学びます。この実験は、以下の手順で構成されています。

次元と要素の読み込み: ユーザー入力から 2 つの行列の次元と要素を読み込む方法を学びます。このステップは、行列が乗算可能であることを保証します。

行と列の乗算: 積行列の各要素は、入力行列の対応する行と列を乗算することによって計算される行列乗算アルゴリズムを実装します。

積行列の出力: 最後に、結果の積行列を表示します。

この実験の終わりまでに、C 言語における行列乗算の深い理解を得て、様々なアプリケーションに適用できるようになります。

次元と要素の読み込み

このステップでは、C 言語で行列乗算を行うために、行列の次元と要素を読み込む方法を学びます。ユーザーが 2 つの行列のサイズと値を入力できるようにするプログラムを作成します。

まず、行列乗算プログラム用の新しい C ファイルを作成しましょう。

cd ~/project
nano matrix_multiply.c

次に、行列の次元を読み込むためのコードを追加します。

#include <stdio.h>

#define MAX_SIZE 100

int main() {
    int rows1, cols1, rows2, cols2;

    // 最初の行列の次元を読み込みます
    printf("最初の行列の次元 (行 列) を入力してください:");
    scanf("%d %d", &rows1, &cols1);

    // 2 番目の行列の次元を読み込みます
    printf("2 番目の行列の次元 (行 列) を入力してください:");
    scanf("%d %d", &rows2, &cols2);

    // 行列の乗算が可能かどうかをチェックします
    if (cols1 != rows2) {
        printf("行列の乗算はできません!\n");
        return 1;
    }

    printf("行列の次元は乗算可能です。\n");

    return 0;
}

プログラムをコンパイルして実行します。

gcc matrix_multiply.c -o matrix_multiply
./matrix_multiply

実行例:

最初の行列の次元 (行 列) を入力してください: 2 3
2番目の行列の次元 (行 列) を入力してください: 3 2
行列の次元は乗算可能です。

コードを詳しく見てみましょう。

  • MAX_SIZE を 100 に設定して、行列の次元を制限しています。
  • scanf() を使用して、ユーザー入力から行列の次元を読み込んでいます。
  • 最初の行列の列数と 2 番目の行列の行数を比較して、行列乗算が可能かどうかをチェックしています。
  • 次元が互換性がない場合、プログラムはエラーメッセージを出力します。

次に、行列の要素を読み込むようにコードを修正します。

#include <stdio.h>

#define MAX_SIZE 100

int main() {
    int rows1, cols1, rows2, cols2;
    int matrix1[MAX_SIZE][MAX_SIZE];
    int matrix2[MAX_SIZE][MAX_SIZE];

    // 最初の行列の次元を読み込みます
    printf("最初の行列の次元 (行 列) を入力してください: ");
    scanf("%d %d", &rows1, &cols1);

    // 2番目の行列の次元を読み込みます
    printf("2番目の行列の次元 (行 列) を入力してください: ");
    scanf("%d %d", &rows2, &cols2);

    // 行列の乗算が可能かどうかをチェックします
    if (cols1 != rows2) {
        printf("行列の乗算はできません!\n");
        return 1;
    }

    // 最初の行列の要素を読み込みます
    printf("最初の行列の要素を入力してください:\n");
    for (int i = 0; i < rows1; i++) {
        for (int j = 0; j < cols1; j++) {
            printf("要素 [%d][%d] を入力してください: ", i, j);
            scanf("%d", &matrix1[i][j]);
        }
    }

    // 2番目の行列の要素を読み込みます
    printf("2番目の行列の要素を入力してください:\n");
    for (int i = 0; i < rows2; i++) {
        for (int j = 0; j < cols2; j++) {
            printf("要素 [%d][%d] を入力してください: ", i, j);
            scanf("%d", &matrix2[i][j]);
        }
    }

    printf("行列の読み込みが完了しました。\n");

    return 0;
}

プログラムをコンパイルして実行します。

gcc matrix_multiply.c -o matrix_multiply
./matrix_multiply

実行例:

最初の行列の次元 (行 列) を入力してください:2 3
2 番目の行列の次元 (行 列) を入力してください:3 2
最初の行列の要素を入力してください:
要素 [0][0] を入力してください:1
要素 [0][1] を入力してください:2
要素 [0][2] を入力してください:3
要素 [1][0] を入力してください:4
要素 [1][1] を入力してください:5
要素 [1][2] を入力してください:6
2 番目の行列の要素を入力してください:
要素 [0][0] を入力してください:7
要素 [0][1] を入力してください:8
要素 [1][0] を入力してください:9
要素 [1][1] を入力してください:10
要素 [2][0] を入力してください:11
要素 [2][1] を入力してください:12
行列の読み込みが完了しました。

行列の行と列の乗算

このステップでは、最初の行列の行と 2 番目の行列の列を乗算することで行列乗算を実行する方法を学びます。前のコードを拡張して行列乗算アルゴリズムを実装します。

matrix_multiply.c ファイルを更新して行列乗算機能を追加します。

cd ~/project
nano matrix_multiply.c

以前のコードを以下の実装に置き換えます。

#include <stdio.h>

#define MAX_SIZE 100

int main() {
    int rows1, cols1, rows2, cols2;
    int matrix1[MAX_SIZE][MAX_SIZE];
    int matrix2[MAX_SIZE][MAX_SIZE];
    int result[MAX_SIZE][MAX_SIZE];

    // 最初の行列の次元を読み込みます
    printf("最初の行列の次元 (行 列) を入力してください: ");
    scanf("%d %d", &rows1, &cols1);

    // 2番目の行列の次元を読み込みます
    printf("2番目の行列の次元 (行 列) を入力してください: ");
    scanf("%d %d", &rows2, &cols2);

    // 行列の乗算が可能かどうかをチェックします
    if (cols1 != rows2) {
        printf("行列の乗算はできません!\n");
        return 1;
    }

    // 最初の行列の要素を読み込みます
    printf("最初の行列の要素を入力してください:\n");
    for (int i = 0; i < rows1; i++) {
        for (int j = 0; j < cols1; j++) {
            printf("要素 [%d][%d] を入力してください: ", i, j);
            scanf("%d", &matrix1[i][j]);
        }
    }

    // 2番目の行列の要素を読み込みます
    printf("2番目の行列の要素を入力してください:\n");
    for (int i = 0; i < rows2; i++) {
        for (int j = 0; j < cols2; j++) {
            printf("要素 [%d][%d] を入力してください: ", i, j);
            scanf("%d", &matrix2[i][j]);
        }
    }

    // 行列を乗算します
    for (int i = 0; i < rows1; i++) {
        for (int j = 0; j < cols2; j++) {
            result[i][j] = 0;
            for (int k = 0; k < cols1; k++) {
                result[i][j] += matrix1[i][k] * matrix2[k][j];
            }
        }
    }

    // 結果行列を出力します
    printf("\n結果行列:\n");
    for (int i = 0; i < rows1; i++) {
        for (int j = 0; j < cols2; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
    }

    return 0;
}

プログラムをコンパイルして実行します。

gcc matrix_multiply.c -o matrix_multiply
./matrix_multiply

実行例:

最初の行列の次元 (行 列) を入力してください: 2 3
2番目の行列の次元 (行 列) を入力してください: 3 2
最初の行列の要素を入力してください:
要素 [0][0] を入力してください: 1
要素 [0][1] を入力してください: 2
要素 [0][2] を入力してください: 3
要素 [1][0] を入力してください: 4
要素 [1][1] を入力してください: 5
要素 [1][2] を入力してください: 6
2番目の行列の要素を入力してください:
要素 [0][0] を入力してください: 7
要素 [0][1] を入力してください: 8
要素 [1][0] を入力してください: 9
要素 [1][1] を入力してください: 10
要素 [2][0] を入力してください: 11
要素 [2][1] を入力してください: 12

結果行列:
58 64
139 154

行列乗算アルゴリズムを詳しく見てみましょう。

  • 外側の 2 つのループ ij は、結果行列を反復処理します。
  • 内側のループ k は、最初の行列の行 i と 2 番目の行列の列 j の内積を実行します。
  • result[i][j] は、対応する要素の積の合計によって計算されます。
  • ネストされたループは、結果行列の各要素が正しく計算されることを保証します。

行列乗算に関する重要な点:

  • 最初の行列の列数は、2 番目の行列の行数と一致する必要があります。
  • 結果の行列の次元は (最初の行列の行数) × (2 番目の行列の列数) になります。

積行列の出力

この最終ステップでは、行列乗算プログラムをさらに強化して、より堅牢な出力機能とエラー処理を追加します。行列を出力する関数を作成し、全体的なユーザーエクスペリエンスを向上させます。

matrix_multiply.c ファイルを以下の改良された実装で更新します。

cd ~/project
nano matrix_multiply.c

以前のコードをこの包括的なバージョンに置き換えます。

#include <stdio.h>

#define MAX_SIZE 100

// 行列を出力する関数
void printMatrix(int matrix[MAX_SIZE][MAX_SIZE], int rows, int cols, const char* matrixName) {
    printf("\n%s 行列:\n", matrixName);
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%5d ", matrix[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int rows1, cols1, rows2, cols2;
    int matrix1[MAX_SIZE][MAX_SIZE];
    int matrix2[MAX_SIZE][MAX_SIZE];
    int result[MAX_SIZE][MAX_SIZE];

    // 最初の行列の次元を読み込みます
    printf("最初の行列の次元 (行 列) を入力してください: ");
    scanf("%d %d", &rows1, &cols1);

    // 2番目の行列の次元を読み込みます
    printf("2番目の行列の次元 (行 列) を入力してください: ");
    scanf("%d %d", &rows2, &cols2);

    // 行列の乗算が可能かどうかをチェックします
    if (cols1 != rows2) {
        printf("行列の乗算はできません!\n");
        printf("最初の行列の列数(%d)は、2番目の行列の行数(%d)と一致する必要があります。\n", cols1, rows2);
        return 1;
    }

    // 最初の行列の要素を読み込みます
    printf("最初の行列の要素を入力してください:\n");
    for (int i = 0; i < rows1; i++) {
        for (int j = 0; j < cols1; j++) {
            printf("要素 [%d][%d] を入力してください: ", i, j);
            scanf("%d", &matrix1[i][j]);
        }
    }

    // 2番目の行列の要素を読み込みます
    printf("2番目の行列の要素を入力してください:\n");
    for (int i = 0; i < rows2; i++) {
        for (int j = 0; j < cols2; j++) {
            printf("要素 [%d][%d] を入力してください: ", i, j);
            scanf("%d", &matrix2[i][j]);
        }
    }

    // 入力行列を出力します
    printMatrix(matrix1, rows1, cols1, "最初の入力");
    printMatrix(matrix2, rows2, cols2, "2番目の入力");

    // 行列を乗算します
    for (int i = 0; i < rows1; i++) {
        for (int j = 0; j < cols2; j++) {
            result[i][j] = 0;
            for (int k = 0; k < cols1; k++) {
                result[i][j] += matrix1[i][k] * matrix2[k][j];
            }
        }
    }

    // 積行列を出力します
    printMatrix(result, rows1, cols2, "積");

    return 0;
}

プログラムをコンパイルして実行します。

gcc matrix_multiply.c -o matrix_multiply
./matrix_multiply

実行例:

最初の行列の次元 (行 列) を入力してください: 2 3
2番目の行列の次元 (行 列) を入力してください: 3 2
最初の行列の要素を入力してください:
... (入力例省略)

最初の入力行列:
    1     2     3
    4     5     6

2番目の入力行列:
    7     8
    9    10
   11    12

積行列:
   58    64
  139   154

このバージョンの主な改善点:

  • 整形式で行列を出力する printMatrix() 関数を作成しました。
  • 行列乗算の互換性に関するより詳細なエラーメッセージを追加しました。
  • 積行列を表示する前に入力行列を出力します。
  • 整列された行列出力のために %5d を使用しています。
  • 明瞭で読みやすい出力形式を提供しています。

出力関数の説明:

  • printMatrix() は行列、その次元、および名前を引数として受け取ります。
  • ネストされたループを使用して、各要素を出力します。
  • %5d フォーマット指定子は、各数値が整列のために 5 つのスペースを占めることを保証します。
  • 可読性を向上させるために、各行の後に改行を追加します。

まとめ

この実験では、C 言語で行列の次元と要素を読み込み、行列乗算を実行する方法を学びます。最初に、2 つの行列の次元を読み込み、乗算が可能かどうかをチェックする方法を学びます。次に、2 つの行列の要素を読み込み、2 次元配列に格納する方法を学びます。最後に、実際の行列乗算を実行し、結果の積行列を出力する方法を学びます。