2

私はC++に比較的慣れていないので、配列を引数として渡したり返したりする方法をまだ混乱させています。c = A * b次のようなシグネチャを持つ単純な行列ベクトル積関数を書きたいと思います

times(A, b, c, m, n)

ここAで、 は 2 次元配列、bは入力配列、cは結果配列、mおよびnは の次元ですA。ではなく、mとで配列の次元を指定したい。nA

(並列) 関数の本体は

int i, j;
double sum;

#pragma omp parallel for default(none) private(i, j, sum) shared(m, n, A, b, c)
for (i = 0; i < m; ++i) {
    sum = 0.0;
    for (j = 0; j < n; j++) {
        sum += A[i][j] * b[j];
    }
    c[i] = sum;
}
  1. このような関数の正しい署名は何ですか?
  2. ここで、関数で結果配列 c を作成し、それを返したいとします。これどうやってするの?
4

3 に答える 3

2

したがって、「あなたはむしろそうすべきだ」という答えの代わりに(あなたはむしろむしろそうすべきなので、私はそれを残しておきます)、ここに「あなたが求めたもの」の答えがあります.

配列データを保持するために使用std::vectorします (O(1) 移動機能があるため) std::array(これにより、間接処理が節約されますが、移動にコストがかかります)。 std::vectormalloc'd (およびrealloc'd) バッファーstd::arrayの C++ の「改善」であり、 はchar foo[27];スタイル バッファーの C++ の「改善」です。

std::vector<double> times(std::vector<double> const& A, std::vector<double> const& b, size_t m, size_t n)
{
  std::vector<double> c;
  Assert(A.size() = m*n);
  c.resize(n);

  // .. your code goes in here.
  // Instead of A[x][y], do A[x*n+y] or A[y*m+x] depending on if you want column or
  // row-major order in memory.
  return std::move(c); // O(1) copy of the std::vector out of this function
}

std::vector をパラメーターとして受け取るのではなく、それを返すように、署名を少し変更したことに気付くでしょう。私はできるのでこれをしました、そしてそれはよりきれいに見えます!

本当にc関数に渡す必要がある場合は、std::vector<double>&-- への参照として渡しstd::vectorます。

于 2012-11-02T15:52:41.267 に答える
2

これはあなたが使用すべき答えです...したがって、これを解決する良い方法は、structまたはを作成しclassて配列をラップすることです(まあ、データのバッファ-私はを使用しますstd::vector)。のような署名の代わりに、次のようなtimes(A, b, c, m, n)構文を使用します。

Matrix<4,4> M;
ColumnMatrix<4> V;
ColumnMatrix<4> C = M*V;

ここで、M の幅/高さは<4,4>数値です。

Matrix クラスの簡単なスケッチは次のようになります (やや不完全 -- たとえば、const アクセスがないなど)。

template<size_t rows, size_t columns>
class Matrix
{
private:
  std::vector<double> values;
public:
  struct ColumnSlice
  {
    Matrix<rows,columns>* matrix;
    size_t row_number;
    double& operator[](size_t column) const
    {
      size_t index = row_number * columns + column;
      Assert(matrix && index < matrix->values.size());
      return matrix->values[index];
    }
    ColumnSlice( Matrix<rows,columns>* matrix_, size_t row_number_ ):
      matrix(matrix_), row_number(row_number_)
    {}
  };
  ColumnSlice operator[](size_t row)
  {
    Assert(row < rows); // note: zero based indexes
    return ColumnSlice(this, row);
  }
  Matrix() {values.resize(rows*columns);}
  template<size_t other_columns>
  Matrix<rows, other_columns> operator*( Matrix<columns, other_columns> const& other ) const
  {
    Matrix<rows, other_columns> retval;
    // TODO: matrix multiplication code goes here
    return std::move(retval);
  }
};

template<size_t rows>
using ColumnMatrix = Matrix< rows, 1 >;

template<size_t columns>
using RowMatrix = Matrix< 1, columns >;

上記は、コンパイラにない可能性のある C++0x 機能を使用しており、これらの機能がなくても実行できます。

このすべてのポイントは?数学のように見え、C++ で正しいことを行う数学を持つことができますが、それは非常に効率的であり、それが「適切な」C++ の方法です。

std::vector慣れている場合は、C++ のいくつかの機能 (配列メモリ管理の処理など) を使用して、C に似た方法でプログラミングすることもできます。しかし、それはこの質問に対する別の答えです。:)

(注: 上記のコードはコンパイルされておらず、完全な Matrix 実装でもありません。ただし、テンプレート ベースの Matrix 実装が世の中に出回っています。)

于 2012-11-02T15:30:41.090 に答える
0

通常のベクトルと行列の乗算は次のとおりです。

friend Vector operator*(const Vector &v, const Matrix &m);

ただし、ディメンションを個別に渡したい場合は、次のようになります。

friend Vector mul(const Vector &v, const Matrix &m, int size_x, int size_y);

Vector と Matrix は 1 次元と 2 次元の配列になるため、次のようになります。

struct Vector { float *array; };
struct Matrix { float *matrix; };
于 2012-11-02T15:52:13.043 に答える