Есть ли способ поэлементного умножения вектор-вектор с помощью BLAS, GSL или любой другой высокопроизводительной библиотеки?
Поэлементное вектор-векторное умножение в BLAS?
Ответы (4)
(буквально воспринимая название вопроса...)
Да, это можно сделать только с помощью BLAS (хотя это, вероятно, не самый эффективный способ).
Хитрость заключается в том, чтобы рассматривать один из входных векторов как диагональную матрицу:
⎡a ⎤ ⎡x⎤ ⎡ax⎤
⎢ b ⎥ ⎢y⎥ = ⎢by⎥
⎣ c⎦ ⎣z⎦ ⎣cz⎦
Затем вы можете использовать одну из функций умножения матрицы на вектор, которая может принимать диагональную матрицу в качестве входных данных без заполнения, например. SBMV
Пример:
void ebeMultiply(const int n, const double *a, const double *x, double *y)
{
extern void dsbmv_(const char *uplo,
const int *n,
const int *k,
const double *alpha,
const double *a,
const int *lda,
const double *x,
const int *incx,
const double *beta,
double *y,
const int *incy);
static const int k = 0; // Just the diagonal; 0 super-diagonal bands
static const double alpha = 1.0;
static const int lda = 1;
static const int incx = 1;
static const double beta = 0.0;
static const int incy = 1;
dsbmv_("L", &n, &k, &alpha, a, &lda, x, &incx, &beta, y, &incy);
}
// Test
#define N 3
static const double a[N] = {1,3,5};
static const double b[N] = {1,10,100};
static double c[N];
int main(int argc, char **argv)
{
ebeMultiply(N, a, b, c);
printf("Result: [%f %f %f]\n", c[0], c[1], c[2]);
return 0;
}
Result: [1.000000 30.000000 500.000000]
-O2 -fPIC -fstack-protector-strong
. Я предполагаю, что ?sbmv слишком общий и не может оптимально использовать векторизованные инструкции.
- person Witiko; 20.08.2020
Я обнаружил, что MKL имеет целый набор математических операций над вектором в своей библиотеке векторных математических функций (VML), включая v?Mul, который делает то, что я хочу. Он работает с массивами c++, поэтому мне удобнее, чем GSL.
Всегда существует std::valarray1, который определяет поэлементные операции, которые часто (Intel C++ /Quse-intel-optimized-headers
, G++) компилируются в инструкции SIMD, если цель их поддерживает.
Оба этих компилятора также будут выполнять автоматическую векторизацию.
- http://software.intel.com/en-us/articles/getting-code-ready-for-parallel-execution-with-intel-parallel-composer/
- http://gcc.gnu.org/projects/tree-ssa/vectorization.html
В этом случае вы можете просто написать
#define N 10000
float a[N], b[N], c[N];
void f1() {
for (int i = 1; i < N; i++)
c[i] = a[i] + b[i];
}
и посмотрите, как он компилируется в векторизованный код (например, с использованием SSE4)
1 Да, они архаичны и часто считаются устаревшими, но на практике они оба стандартны и очень хорошо подходят для этой задачи.
В GSL gsl_vector_mul
делает свое дело.