Простое и быстрое умножение матричных векторов в C/С++

Мне нужно частое использование matrix_vector_mult(), которое умножает матрицу на вектор, а ниже - его реализация.

Вопрос: Есть ли простой способ сделать это значительно, по крайней мере, в два раза быстрее?

Примечания: 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);
    }
}

Ответ 1

Это то, что теоретически хороший компилятор должен делать сам по себе, однако я попытался с моей системой (g++ 4.6.3) и получил примерно в два раза больше скорости на матрице 300x50 вручную, развернув 4 умножения (около 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;
}

Я ожидаю, однако результаты этого уровня микро-оптимизации будут сильно различаться между системами.

Ответ 2

Как говорит Женя, просто используйте хорошую библиотеку BLAS или матричную математику.

Если по какой-то причине вы не можете этого сделать, посмотрите, может ли ваш компилятор развернуть и/или векторизовать ваши циклы; убедившись, что строки и столбцы являются константами на сайте вызова, могут помочь, предполагая, что функции, которые вы опубликовали, доступны для вложения

Если вы все еще не можете получить ускорение, которое вам нужно, вы смотрите на ручное разворачивание и векторизация с помощью расширений или встроенного ассемблера.

Ответ 3

Если размер является постоянным и известен заранее, передайте его как переменную прекомпилятора, что позволит компилятору оптимизировать более полно.