Namespaces
Variants

std::experimental::parallel:: transform_reduce

From cppreference.net
Определено в заголовочном файле <experimental/numeric>
template < class InputIt, class UnaryOp, class T, class BinaryOp >

T transform_reduce ( InputIt first, InputIt last,

UnaryOp unary_op, T init, BinaryOp binary_op ) ;
(1) (parallelism TS)
template < class ExecutionPolicy,

class InputIt, class UnaryOp, class T, class BinaryOp >
T transform_reduce ( ExecutionPolicy && policy,
InputIt first, InputIt last,

UnaryOp unary_op, T init, BinaryOp binary_op ) ;
(2) (parallelism TS)

Применяет unary_op к каждому элементу в диапазоне [ first , last ) и редуцирует результаты (возможно переставленные и агрегированные неопределённым образом) вместе с начальным значением init с помощью binary_op .

Поведение недетерминировано, если binary_op не является ассоциативным или не коммутативным.

Поведение не определено, если unary_op или binary_op изменяет любой элемент или делает недействительным любой итератор в диапазоне [ first , last ) .

Содержание

Параметры

first, last - диапазон элементов для применения алгоритма
init - начальное значение обобщённой суммы
policy - политика выполнения
unary_op - унарный FunctionObject , который будет применён к каждому элементу входного диапазона. Тип возвращаемого значения должен быть допустимым для ввода в binary_op
binary_op - бинарный FunctionObject , который будет применён в неопределённом порядке к результатам unary_op , результатам других binary_op и init
Требования к типам
-
InputIt должен удовлетворять требованиям LegacyInputIterator .

Возвращаемое значение

Обобщённая сумма init и unary_op ( * first ) , unary_op ( * ( first + 1 ) ) , ... unary_op ( * ( last - 1 ) ) через binary_op , где обобщённая сумма GSUM(op, a 1 , ..., a N ) определяется следующим образом:

  • если N = 1 , a 1 ,
  • если N > 1 , op(GSUM(op, b 1 , ..., b K ), GSUM(op, b M , ..., b N )) где
  • b 1 , ..., b N может быть любой перестановкой a1, ..., aN и
  • 1 < K + 1 = M ≤ N

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

Сложность

O(last - first) применений каждого из unary_op и binary_op .

Исключения

  • Если выполнение функции, вызванной как часть алгоритма, вызывает исключение,
  • если policy является parallel_vector_execution_policy , std::terminate вызывается.
  • если policy является sequential_execution_policy или parallel_execution_policy , алгоритм завершается с exception_list , содержащей все неперехваченные исключения. Если было только одно неперехваченное исключение, алгоритм может повторно выбросить его без обёртки в exception_list . Не определено, какой объём работы алгоритм выполнит перед возвратом после обнаружения первого исключения.
  • если policy имеет другой тип, поведение определяется реализацией.
  • Если алгоритму не удается выделить память (либо для себя, либо для создания exception_list при обработке пользовательского исключения), std::bad_alloc выбрасывается.

Примечания

unary_op не применяется к init .

Если диапазон пуст, init возвращается без изменений.

  • Если policy является экземпляром sequential_execution_policy , все операции выполняются в вызывающем потоке.
  • Если policy является экземпляром parallel_execution_policy , операции могут выполняться в неопределенном количестве потоков, недетерминированно упорядоченных друг относительно друга.
  • Если policy является экземпляром parallel_vector_execution_policy , выполнение может быть как распараллелено, так и векторизовано: границы тела функции не соблюдаются, а пользовательский код может перекрываться и комбинироваться произвольным образом (в частности, это означает, что предоставляемый пользователем Callable не должен захватывать мьютекс для доступа к разделяемому ресурсу).

Пример

transform_reduce может быть использована для распараллеливания std::inner_product :

#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple.hpp>
#include <experimental/execution_policy>
#include <experimental/numeric>
#include <functional>
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
    std::vector<double> xvalues(10007, 1.0), yvalues(10007, 1.0);
    double result = std::experimental::parallel::transform_reduce(
        std::experimental::parallel::par,
        boost::iterators::make_zip_iterator(
            boost::make_tuple(std::begin(xvalues), std::begin(yvalues))),
        boost::iterators::make_zip_iterator(
            boost::make_tuple(std::end(xvalues), std::end(yvalues))),
        [](auto r) { return boost::get<0>(r) * boost::get<1>(r); }
        0.0,
        std::plus<>()
    );
    std::cout << result << '\n';
}

Вывод:

10007

Смотрите также

суммирует или сворачивает диапазон элементов
(function template)
применяет функцию к диапазону элементов, сохраняя результаты в целевом диапазоне
(function template)
(parallelism TS)
аналогично std::accumulate , но без сохранения порядка
(function template)