C++ で 2つの行列を乗算する

胡金庫 2023年10月12日
C++ で 2つの行列を乗算する

この記事では、C++ で 2つの行列を乗算する方法のいくつかの方法について説明します。

C++ でシリアル実装を使用して 2つの行列を乗算する

行列の乗算は、幅広いエンジニアリングソリューションで最も一般的に使用される演算の 1つです。したがって、さまざまなハードウェアプラットフォームでパフォーマンスを向上させるためのさまざまなアルゴリズムがあります。これらのアルゴリズムは、行列の乗算を高速化するために、並行プログラミングと行列タイリングを利用することがよくあります。ただし、この場合、明示的な最適化を行わずにシリアルに実行する単純なアルゴリズムを実装します。

最初に、操作する行列の割り当てと初期化に役立ついくつかのユーティリティ関数を実装する必要があります。プログラマーが ROW および COL 定数整数を変更して行列の次元を指定できるように、コードを実装していることに注意してください。allocateMatrix 関数は、配列の配列を割り当て、要素をゼロ値で初期化します。次に、initilizeMatrix 関数が呼び出され、範囲-[0, 100) の乱数が生成され、それらが行列要素として格納されます。行列要素を cout ストリームに出力して計算結果を検証する関数もあることに注意してください。

multiplyMatrix 関数は、単純なトリプルネストされた for ループを実装して、2つの行列を乗算し、結果を事前に割り当てられた 3 番目の行列に格納します。結果の行列の次元は、最初の行列の行と 2 番目の行列の列から取得されます。ループの順序は、乗算のパフォーマンスにとって非常に重要であることに注意してください。たとえば、最も内側の for ステートメントを中央に移動すると、ほぼ保証されたパフォーマンスの向上が期待されます。パフォーマンスの向上は、ほとんどすべての最新の CPU にあるキャッシュメモリによって引き起こされます。キャッシュメモリはメインメモリよりも高速であり、データが取得されるときに連続したメモリブロックを格納します。したがって、次のデータ取得はキャッシュ自体から提供できます。

#include <iomanip>
#include <iostream>
#include <vector>

using std::cout;
using std::endl;
using std::setw;
using std::vector;

constexpr int ROW = 2;
constexpr int COL = 3;

void initilizeMatrix(int **m, int row, int col) {
  for (auto i = 0; i < row; ++i) {
    for (auto j = 0; j < col; ++j) {
      m[i][j] = rand() % 100;
    }
  }
}

void printMatrix(int **m, int row, int col) {
  for (auto i = 0; i < row; ++i) {
    for (auto j = 0; j < col; ++j) {
      cout << setw(5) << m[i][j] << "; ";
    }
    cout << endl;
  }
}

int **allocateMatrix(int row, int col) {
  int **matrix = new int *[row];
  for (int i = 0; i < row; ++i) {
    matrix[i] = new int[col]{0};
  }
  return matrix;
}

int deallocateMatrix(int **matrix, int row) {
  for (int i = 0; i < row; ++i) {
    delete matrix[i];
  }
  delete[] matrix;
  return 0;
}

int **multiplyMatrix(int **m1, int row1, int col1, int **m2, int row2,
                     int col2) {
  if (col1 != row2) return nullptr;

  auto ret = allocateMatrix(row1, col2);

  int i, j, k;

  for (i = 0; i < row1; i++) {
    for (j = 0; j < col2; j++) {
      for (k = 0; k < col1; k++) {
        ret[i][j] += m1[i][k] * m2[k][j];
      }
    }
  }

  return ret;
}

int main() {
  int **matrix1 = allocateMatrix(ROW, COL);
  int **matrix2 = allocateMatrix(COL, ROW);

  initilizeMatrix(matrix1, ROW, COL);
  initilizeMatrix(matrix2, COL, ROW);

  printMatrix(matrix1, ROW, COL);
  cout << endl;
  printMatrix(matrix2, COL, ROW);

  auto result = multiplyMatrix(matrix1, ROW, COL, matrix2, COL, ROW);

  cout << endl;
  printMatrix(result, ROW, ROW);

  deallocateMatrix(matrix1, ROW);
  deallocateMatrix(matrix2, COL);
  deallocateMatrix(result, ROW);

  return EXIT_SUCCESS;
}

出力:

83;    86;    77;
15;    93;    35;

86;    92;
49;    21;
62;    27;

16126; 11521;
8017;  4278;

最後に、プログラムが終了する前に、マトリックスによって使用されているすべてのメモリリソースを解放することが重要です。deallocateMatrix 関数は、オブジェクト内の各要素を削除するために行列ポインターとその中の行を受け取るように実装されています。multiplyMatrix 関数スコープで割り当てられた結果行列も明示的に割り当て解除する必要があることに注意してください。

著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C++ Math