0

C++ で線形代数プログラムを作成するときは、Armadillo ライブラリを使用します。これはテンプレートに基づいており、コンパイル時に適切なメモリ バッファが静的に割り当てられるため、必ずしも追加のメモリ割り当てを必要としない任意の長さのベクトルを定義する方法を提供します。コンパイラを使用するとarma::Col<double>::fixed<3>、その場で「新しい型」が作成されるため、ベクターには正確に 3 つの double のバッファーが含まれます。

現在、C で線形代数プログラムに取り組んでおり、GNU Scientific Library (GSL) を使用しています。3D ベクトルをインスタンス化するために、次のようにしgsl_vector_alloc(3)ますgsl_vector*。問題は、この操作によってメモリのごく一部が動的に割り当てられ、プログラムの実行中に何百万回も発生することです。malloc私のプログラムは、数千万回の操作を実行するために多くのリソースを浪費していfreeます。

の内部構造を調べましたgsl_vector:

typedef struct
{
   size_t size;
   size_t stride;
   double * data;
   gsl_block * block;
   int owner;
} gsl_vector;

ライブラリが正しく機能dataするには、ベクトルの最初の要素を指す必要があります。通常は、次のgsl_blockような構造内にあります。

typedef struct
{
   size_t size;
   double * data;
} gsl_block;

data別のポインターが含まれています。したがって、単純な 3D ベクトルをインスタンス化する場合、次の一連のmallocs が発生します。

  1. gsl_vector構造体は'd ( mallocx86_64 では約 40 バイト) です。
  2. gsl_block構造体はmalloc'd (16 バイト) であり、gsl_vector のポインターblockは、割り当てられたばかりの gsl_block のメモリ アドレスに設定されます。
  3. 3 つの倍精度浮動小数点数の配列が'd になり、そのメモリ アドレスが両方のポインター (の 1 つと の 1 つ)にmalloc割り当てられます。datagsl_blockgsl_vector

2 つの を削除することで、パフォーマンスが 40% 向上しましたmallocgsl_vector3 つの double の配列を割り当て、のdataポインターgsl_vectorをこの配列のアドレスに設定するカスタム作成ルーチンを作成しました。gsl_vector次に、 (ポインターではなく)を返します。
しかし、そうしても、何百万ものmalloc(3 * sizeof(double))操作が行われます。

gsl_vector構造体の内部に 3 つの double の配列を「埋め込む」ことができませんでした。ポインタが構造体自体の内部dataにあるものを指している場合(ハック!)、ベクトルが別の場所にコピーされるとポインタが無効になるためです!

何かアイデアはありますか (C++ に切り替えるか、独自の線形代数ライブラリを展開する以外に)? 私はどんな提案にもオープンです。

4

2 に答える 2

0

C は、これを適切に行うには少し原始的すぎます。

GSL の関数を使用する必要がある場合でも、C++ Armadillo のベクトルと行列を使用できる場合があります。

たとえば、.memptr()メンバー関数を介して、ベクトルまたは行列によって使用されるメモリへのポインターを取得できます。これは、固定サイズの行列/ベクトルでも機能します。

別の方法として、ベクトルまたは行列の構築中にポインタを与えることで、すでに割り当てられているメモリ ブロックを使用するように Armadillo に指示することもできます。

于 2013-04-13T16:43:07.560 に答える