20

matrix_vector_mult()行列とベクトルを乗算するものを頻繁に使用する必要があります。以下はその実装です。

質問:それを大幅に、少なくとも2回、速くする簡単な方法はありますか?

備考:1)行列のサイズは約300x50です。実行中は変更されません。2)WindowsとLinuxの両方で動作する必要があります。

double vectors_dot_prod(const double *x, const double *y, int n)
{
    double res = 0.0;
    int i;
    for (i = 0; i < n; i++)
    {
        res += x[i] * y[i];
    }
    return res;
}

void matrix_vector_mult(const double **mat, const double *vec, double *result, int rows, int cols)
{ // in matrix form: result = mat * vec;
    int i;
    for (i = 0; i < rows; i++)
    {
        result[i] = vectors_dot_prod(mat[i], vec, cols);
    }
}
4

3 に答える 3

24

これは理論的には優れたコンパイラが単独で実行する必要があることですが、システム(g ++ 4.6.3)で試してみて、4つの乗算を手動で展開することで300x50マトリックスで約2倍の速度を得ました(マトリックスごとに約18usではなくマトリックスあたり34us):

double vectors_dot_prod2(const double *x, const double *y, int n)
{
    double res = 0.0;
    int i = 0;
    for (; i <= n-4; i+=4)
    {
        res += (x[i] * y[i] +
                x[i+1] * y[i+1] +
                x[i+2] * y[i+2] +
                x[i+3] * y[i+3]);
    }
    for (; i < n; i++)
    {
        res += x[i] * y[i];
    }
    return res;
}

ただし、このレベルのマイクロ最適化の結果は、システム間で大きく異なると思います。

于 2012-09-05T20:48:45.223 に答える
5

Zhenyaが言うように、良いBLASまたは行列数学ライブラリを使用してください。

何らかの理由でそれができない場合は、コンパイラがループを展開および/またはベクトル化できるかどうかを確認してください。投稿した関数がインライン化に使用できると仮定すると、呼び出しサイトでの両方が定数であることを確認すると役立つ場合があります

それでも必要なスピードアップが得られない場合は、手動で展開し、拡張機能またはインラインアセンブラを使用してベクトル化することを検討しています。

于 2012-09-05T20:49:38.467 に答える
0

サイズが一定で、事前にわかっている場合は、それをプリコンパイラー変数として渡します。これにより、コンパイラーはより完全に最適化できます。

于 2012-09-05T20:54:18.193 に答える