Скалярное произведение комплексных векторов с openMP
Я использую версию openMP, которая не поддерживает Reduce() для сложных аргументов. Мне нужна быстрая функция точечного произведения, как
std::complex< double > dot_prod( std::complex< double > *v1,std::complex< double > *v2,int dim )
{
std::complex< double > sum=0.;
int i;
# pragma omp parallel shared(sum)
# pragma omp for
for (i=0; i<dim;i++ )
{
#pragma omp critical
{
sum+=std::conj<double>(v1[i])*v2[i];
}
}
return sum;
}
Очевидно, этот код не ускоряет проблему, но замедляет ее. Есть ли у вас быстрое решение без использования redu () для сложных аргументов?
3 ответа
Каждый поток может вычислить частную сумму в качестве первого шага, а в качестве второго шага он может быть составлен в конечную сумму. В этом случае критический раздел необходим только на последнем этапе.
std::complex< double > dot_prod( std::complex< double > *v1,std::complex< double > *v2,int dim )
{
std::complex< double > sum=0.;
int i;
# pragma omp parallel shared(sum)
{
std::complex< double > priv_sum = 0.;
# pragma omp for
for (i=0; i<dim;i++ )
{
priv_sum += std::conj<double>(v1[i])*v2[i];
}
#pragma omp critical
{
sum += priv_sum;
}
}
return sum;
}
Попробуйте выполнить умножения параллельно, а затем суммируйте их последовательно:
template <typename T>
std::complex<T> dot_prod(std::complex<T> *a, std::complex<T> *b, size_t dim)
{
std::vector<std::complex<T> > prod(dim); // or boost::scoped_array + new[]
#pragma omp parallel for
for (size_t i=0; i<dim; i++)
// I believe you had these reversed
prod[i] = a[i] * std::conj(b[i]);
std::complex<T> sum(0);
for (size_t i=0; i<dim; i++)
sum += prod[i];
return sum;
}
Конечно, это требует O(тусклой) рабочей памяти.
Почему бы не N потоков вычислить N отдельных сумм. Тогда в конце вам нужно только сложить N сумм, что можно сделать последовательно, так как N довольно мало. Хотя я не знаю, как это сделать с помощью OpenMP, на данный момент (у меня нет никакого опыта с этим), я вполне уверен, что это легко достижимо.