3

C プログラミング言語での amxn 実数行列の最適な表現を知りたいです。

単一のポインタとしての行列表現の利点は何ですか:

double* A;

この表現を使用すると、メモリを割り当てることができます。

A = (double* )malloc(m * n * sizeof(double));

このような表現では、行列へのアクセスには追加の乗算が必要です。

aij = A[i * m + j];

ダブルポインターとしての行列表現の欠点は何ですか:

double** B;

メモリ割り当てにはループが必要です。

double** B = (double **) malloc(m * sizeof(double*));
for (i = 0; i < m; i++)
    A[i] = (double *) malloc(n * sizeof(double))

このような表現では、直感的なダブル インデックス `bij = B[i][j] を使用できますが、パフォーマンスに影響するいくつかの欠点があります。パフォーマンスの点で最高のプレゼンテーションは何か知りたいです。

これらの行列は、特異値分解などの数値アルゴリズムで使用する必要があります。関数を定義する必要があります。

void svd(Matrix A, Matrix U, Matrix Sigma, Matrix V);

マトリックスを表現する最良の方法を探しています。C で行列を表現する効率的な方法が他にある場合は、お知らせください。

ほとんどの人が単一のポインター表現を使用していることを見てきました。二重配列表現とは対照的に、パフォーマンス上の利点があるかどうかを知りたいですか?

4

2 に答える 2

5

必要なメモリアクセスを見てください。

シングルポインターの場合、次のようになります。

  1. おそらくレジスターから、ポインター (ベースアドレス) を読み取る
  2. おそらくレジスタから、または命令セットにハードコードされた4つの整数を読み取ります。の場合array[i*m+j]、4 つの値はimjおよびsizeof(array[0])です。
  3. 掛けて足す
  4. メモリアドレスにアクセスする

ダブルポインターの場合、次のようになります。

  1. おそらくレジスターから、ポインター (ベースアドレス) を読み取る
  2. おそらくレジスタからインデックスを読み取る
  3. インデックスにポインターのサイズを掛けて加算します。
  4. メモリからベースアドレスをフェッチします (レジスタである可能性は低く、運が良ければキャッシュにある可能性があります)。
  5. おそらくレジスタから別のインデックスを読み取る
  6. オブジェクトのサイズを掛けて足す
  7. メモリアドレスにアクセスする

2 つのメモリ位置にアクセスする必要があるという事実により、おそらくダブル ポインター ソリューションはシングル ポインター ソリューションよりもかなり遅くなります。明らかに、キャッシングは重要です。これが、アクセスがキャッシュに適したものになるように配列にアクセスすることが重要である理由の 1 つです (隣接するメモリ位置にできるだけ頻繁にアクセスするようにします)。

詳細については私の概要を詳しく説明することができます。一部の「乗算」操作はシフト操作などである可能性がありますが、一般的な概念はそのままです。ダブルポインターでは、シングルポインター ソリューションでは 1 回のメモリ アクセスが必要であるのに対して、2 回のメモリ アクセスが必要です。ゆっくりしてください。

于 2013-11-03T10:18:06.890 に答える
0

行優先形式に関するいくつかの記事を次に示します。

http://en.wikipedia.org/wiki/Row-major_order

http://fgiesen.wordpress.com/2011/05/04/row-major-vs-column-major-and-gl-es/

これらは CUDA プログラミングの一般的な構造です。したがって、私の興味。

于 2013-11-03T10:18:10.960 に答える