std::transform_reduce
Определён в заголовочном файле <numeric> | ||
|---|---|---|
template< class InputIt1, class InputIt2, class T >
T transform_reduce( InputIt1 first1, InputIt1 last1,
InputIt2 first2, T init );
| (1) | (начиная с C++17) (constexpr начиная с C++20) |
template< class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class T >
T transform_reduce( ExecutionPolicy&& policy,
ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2, T init );
| (2) | (начиная с C++17) |
template< class InputIt1, class InputIt2, class T,
class BinaryOp1, class BinaryOp2 >
T transform_reduce( InputIt1 first1, InputIt1 last1,
InputIt2 first2, T init,
BinaryOp1 reduce, BinaryOp2 transform );
| (3) | (начиная с C++17) (constexpr начиная с C++20) |
template< class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class T,
class BinaryOp1, class BinaryOp2 >
T transform_reduce( ExecutionPolicy&& policy,
ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2, T init,
BinaryOp1 reduce, BinaryOp2 transform );
| (4) | (начиная с C++17) |
template< class InputIt, class T,
class BinaryOp, class UnaryOp >
T transform_reduce( InputIt first, InputIt last, T init,
BinaryOp reduce, UnaryOp transform );
| (5) | (начиная с C++17) (constexpr начиная с C++20) |
template< class ExecutionPolicy,
class ForwardIt, class T,
class BinaryOp, class UnaryOp >
T transform_reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, T init,
BinaryOp reduce, UnaryOp transform );
| (6) | (начиная с C++17) |
transform_reduce(first1, last1, first2, init,
std::plus<>(), std::multiplies<>())
, фактически распараллеленной версии стандартного std::inner_product.transform к каждой паре элементов диапазонов [first1, last1) и диапазона из std::distance(first1, last1) элементов, начиная с first2, а затем сводит результаты (возможно, переставленные и объединённые неопределённым образом) вместе с начальным значением init по reduce.reduce не является ассоциативным или коммутативным (например, сложение чисел с плавающей точкой).T, программа некорректна: reduce(init, init)reduce(init, transform(*first1, *first2))reduce(transform(*first1, *first2), init)reduce(transform(*first1, *first2), transform(*first1, *first2))
last2 — это std::distance(first1, last1)-й следующий итератор для first2. Если выполняется хотя бы одно из следующих условий, поведение не определено: -
Tне удовлетворяет требованиям MoveConstructible. -
transformилиreduceизменяет какой-либо элемент[first1,last1)или[first2,last2). -
transformилиreduceделает недействительным какой-либо итератор или поддиапазон[first1,last1]или[first2,last2].
transform к каждому элементу диапазона [first, last), а затем сводит результаты (возможно, переставленные и объединённые неопределённым образом) вместе с начальным значением init по reduce.reduce не является ассоциативным или коммутативным (например, сложение чисел с плавающей точкой).T, программа некорректна: reduce(init, init)reduce(init, transform(*first))reduce(transform(*first), init)reduce(transform(*first), transform(*first))
-
Tне удовлетворяет требованиям MoveConstructible. -
transformилиreduceизменяет какой-либо элемент[first,last). -
transformилиreduceделает недействительным какой-либо итератор или поддиапазон[first,last].
policy.true: |
| (до C++20) |
|
| (начиная с C++20) |
Параметры
| first1, last1 | - | пара итераторов, задающих диапазон элементов, используемых в качестве левого операнда transform |
| first2 | - | начало диапазона элементов, используемых в качестве правого операнда transform |
| first, last | - | пара итераторов, задающих диапазон элементов, используемых в качестве операнда transform |
| init | - | начальное значение обобщённой суммы |
| policy | - | используемая политика выполнения |
| reduce | - | бинарный FunctionObject, который будет применяться в неопределённом порядке к результатам transform, результатам других reduce и init. |
| transform | - | унарный или бинарный FunctionObject, который будет применяться к каждому элементу входного диапазона (диапазонов). Возвращаемый тип должен быть допустим в качестве входных данных для reduce. |
| Требования к типам | ||
-InputIt1, InputIt2, InputIt должен удовлетворять требованиям LegacyInputIterator. |
||
-ForwardIt1, ForwardIt2, ForwardIt должен удовлетворять требованиям LegacyForwardIterator. |
||
Возвращаемое значение
init и values по std::plus<>(), где values — это значения, преобразованные с помощью std::multiplies<>(); каждое значение получается преобразованием пары элементов из двух входных диапазонов.init и values по reduce, где values — это значения, преобразованные с помощью transform; каждое значение получается преобразованием пары элементов из двух входных диапазонов.init и values по reduce, где values — это значения, преобразованные с помощью transform; каждое значение получается преобразованием элемента входного диапазона.Обобщённая сумма группы элементов относительно бинарной операции binary_op определяется следующим образом:
- Если группа содержит только один элемент, сумма равна значению этого элемента.
- В противном случае выполняются следующие действия по порядку:
- Из группы выбираются любые два элемента
elem1иelem2. - Вычисляется
binary_op(elem1, elem2), и результат помещается обратно в группу. - Шаги 1 и 2 повторяются, пока в группе не останется только один элемент.
Сложность
Пусть \(\scriptsize N\)N — это std::distance(first1, last1) (или std::distance(first, last) для перегрузок (5,6)):
std::plus<>() и std::multiplies<>() соответственно.reduce и transform соответственно.Исключения
Перегрузки с параметром шаблона с именем ExecutionPolicy сообщают об ошибках следующим образом:
- Если выполнение функции, вызванной в рамках алгоритма, приводит к исключению, а
ExecutionPolicyявляется одной из стандартных политик, вызываетсяstd::terminate. Для любого другогоExecutionPolicyповедение определяется реализацией. - Если алгоритму не удаётся выделить память, генерируется
std::bad_alloc.
Примечания
transform никогда не применяется к init.
Если first == last или first1 == last1, возвращается init без изменений.
Пример
transform_reduce можно использовать для распараллеливания std::inner_product. Для получения преимуществ параллельного выполнения некоторым системам может потребоваться дополнительная поддержка. Например, в GNU/Linux необходимо установить Intel TBB и передать компилятору gcc/clang параметр -ltbb.
#if PARALLEL
#include <execution>
#define PAR std::execution::par,
#else
#define PAR
#endif
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <locale>
#include <numeric>
#include <vector>
// to parallelize non-associate accumulative operation, you'd better choose
// transform_reduce instead of reduce; e.g., a + b * b != b + a * a
void print_sum_squared(long const num)
{
std::cout.imbue(std::locale{"en_US.UTF8"});
std::cout << "num = " << num << '\n';
// create an immutable vector filled with pattern: 1,2,3,4, 1,2,3,4 ...
const std::vector<long> v{[n = num * 4] {
std::vector<long> v;
v.reserve(n);
std::generate_n(std::back_inserter(v), n,
[i = 0]() mutable { return 1 + i++ % 4; });
return v;
}()};
auto squared_sum = [](auto sum, auto val) { return sum + val * val; };
auto sum1 = std::accumulate(v.cbegin(), v.cend(), 0L, squared_sum);
std::cout << "accumulate(): " << sum1 << '\n';
auto sum2 = std::reduce(PAR v.cbegin(), v.cend(), 0L, squared_sum);
std::cout << "reduce(): " << sum2 << '\n';
auto sum3 = std::transform_reduce(PAR v.cbegin(), v.cend(), 0L, std::plus{},
[](auto val) { return val * val; });
std::cout << "transform_reduce(): " << sum3 << "\n\n";
}
int main()
{
print_sum_squared(1);
print_sum_squared(1'000);
print_sum_squared(1'000'000);
}
Возможный вывод:
num = 1 accumulate(): 30 reduce(): 30 transform_reduce(): 30 num = 1,000 accumulate(): 30,000 reduce(): -7,025,681,278,312,630,348 transform_reduce(): 30,000 num = 1,000,000 accumulate(): 30,000,000 reduce(): -5,314,886,882,370,003,032 transform_reduce(): 30,000,000 // Compile-options for parallel execution on POSIX: // g++ -O2 -std=c++17 -Wall -Wextra -pedantic -DPARALLEL ./example.cpp -ltbb -o tr; ./tr
См. также
| суммирует или сворачивает диапазон элементов (шаблон функции) |
|
| применяет функцию к диапазону элементов и сохраняет результаты в целевом диапазоне (шаблон функции и функциональный объект алгоритма) |
|
|
(C++20) | |
|
(C++17) | аналогичен std::accumulate, за исключением того, что порядок выполнения не фиксирован (шаблон функции) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/transform_reduce