雨谷の日和

過去19年で2,600を超えるアニメの第1話だけは見続けた僕のお勧めアニメがハズレなはずがない

Cでの行列式計算(事前メモリ確保での実装)

malloc/freeでの動的なメモリの管理に負荷がかかる(そしてこれはkp氏の指摘にあるように、必要な負荷である)ことから、高速化のためには、必要なメモリ領域を事前に確保しておくと良さそうだということが分かった。
ということで、事前にメモリを確保するようなコードを書き、実測してみよう。

#include
#include

long** array_buf;

long expand(long array[], int dim) {
  int i, j, k, l;
  long value = 0;
  long *subarray;
  if(dim < 2)return array[0];
  subarray = array_buf[dim - 2];
  for(i = 0; i < dim; ++i) {
    l = 0;
    for(j = 0; j < dim; ++j){
      if(j != i){
        for(k = 1; k < dim; ++k)subarray[(l * (dim - 1)) + k - 1] = array[(j * dim) + k];
        ++l;
      }
    }
    if(i % 2 == 0){
      value += (array[i * dim] * expand(subarray, (dim - 1)));
    }else{
      value -= (array[i * dim] * expand(subarray, (dim - 1)));
    }
  }
  return value;
}

int main(){
  int i;
  long value;
  long array[11 * 11] = {
    1, 2, 3, 4, 6, 1, 7, 1, 9, 0, 0, 
    5, 1, 5, 7, 7, 3, 5, 3, 6, 1, 6, 
    7, 6, 4, 8, 4, 6, 1, 7, 1, 4, 8, 
    6, 5, 1, 0, 1, 5, 9, 1, 7, 5, 1, 
    2, 3, 1, 1, 5, 8, 4, 6, 3, 1, 5, 
    3, 1, 0, 3, 2, 9, 4, 8, 0, 3, 1, 
    3, 2, 8, 5, 0, 6, 3, 4, 4, 8, 5, 
    4, 9, 9, 4, 6, 1, 0, 1, 2, 1, 6, 
    9, 7, 6, 1, 6, 4, 5, 2, 9, 4, 4, 
    1, 2, 2, 2, 8, 3, 4, 9, 1, 2, 4, 
    6, 1, 6, 4, 4, 8, 6, 3, 4, 1, 4, 
  };

  array_buf = (long **)malloc(10 * sizeof(long *));
  for(i = 0; i < 10; ++i)array_buf[i] = (long *)malloc(11 * 11 * sizeof(long)); 

  value = expand(array, 11);
  printf("result: %d\n", value);

  for(i = 0; i < 10; ++i)free(array_buf[i]);
  free(array_buf);
  return 0;
}

再帰呼び出しのために、必要なメモリの大きさが分かりにくくなっているが、実はこのアルゴリズムの場合、対象となる行列式の次元数分だけ配列を確保しておけば事足りる。
配列の大きさは元の行列式の要素数よりは多くなり得ないので、今回はそのMAXの分だけ確保しておくこととする。
ただ、これだと確保した分全てが使われるわけではなく、一部は使われないのだが、そこら辺は高速化の代償ということにしておこう。(もちろん、きっちりと必要な分だけを確保する方法もあるし、それはあまり手間の掛かることではない)


次回はこの実行結果と、その考察を書こうと思っている。