std::reduce
Определён в заголовочном файле <numeric> | ||
|---|---|---|
template< class InputIt >
typename std::iterator_traits<InputIt>::value_type
reduce( InputIt first, InputIt last );
| (1) | (начиная с C++17) (constexpr начиная с C++20) |
template< class ExecutionPolicy, class ForwardIt >
typename std::iterator_traits<ForwardIt>::value_type
reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last );
| (2) | (начиная с C++17) |
template< class InputIt, class T > T reduce( InputIt first, InputIt last, T init ); | (3) | (начиная с C++17) (constexpr начиная с C++20) |
template< class ExecutionPolicy, class ForwardIt, class T >
T reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, T init );
| (4) | (начиная с C++17) |
template< class InputIt, class T, class BinaryOp > T reduce( InputIt first, InputIt last, T init, BinaryOp op ); | (5) | (начиная с C++17) (constexpr начиная с C++20) |
template< class ExecutionPolicy,
class ForwardIt, class T, class BinaryOp >
T reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, T init, BinaryOp op );
| (6) | (начиная с C++17) |
reduce(first, last, typename std::iterator_traits<InputIt>::value_type{}).reduce(first, last, init, std::plus<>()).[first, last), возможно, переставляя и агрегируя элементы неопределённым образом, вместе с начальным значением init по op.policy.true: |
| (до C++20) |
|
| (начиная с C++20) |
Если binary_op является фактической бинарной операцией:
- Результат недетерминирован, если
binary_opне является ассоциативной или коммутативной (например, сложение чисел с плавающей точкой). - Если какое-либо из следующих значений нельзя преобразовать в
T, программа некорректна: binary_op(init, *first)binary_op(*first, init)binary_op(init, init)binary_op(*first, *first)- Если выполняется какое-либо из следующих условий, поведение не определено:
-
Tне удовлетворяет требованиям MoveConstructible. -
binary_opизменяет какой-либо элемент[first,last). -
binary_opделает недействительным любой итератор или поддиапазон[first,last].
Параметры
| first, last | - | пара итераторов, задающая диапазон элементов, к которым применяется алгоритм |
| init | - | начальное значение обобщённой суммы |
| policy | - | политика выполнения, которую следует использовать |
| op | - | бинарный объект-функция, который будет применяться в неопределённом порядке к результату разыменования входных итераторов, результатам других op и init. |
| Требования к типам | ||
-InputIt должен удовлетворять требованиям LegacyInputIterator. |
||
-ForwardIt должен удовлетворять требованиям LegacyForwardIterator. |
||
Возвращаемое значение
init и элементов [first, last) по std::plus<>().init и элементов [first, last) по op.Обобщённая сумма группы элементов с использованием бинарной операции binary_op определяется следующим образом:
- Если группа содержит только один элемент, сумма равна значению этого элемента.
- В противном случае последовательно выполняются следующие операции:
- Из группы выбираются любые два элемента
elem1иelem2. - Вычисляется
binary_op(elem1, elem2), а результат возвращается в группу. - Шаги 1 и 2 повторяются, пока в группе не останется только один элемент.
Сложность
Пусть \(\scriptsize N\)N — это std::distance(first, last):
std::plus<>().op.Исключения
Перегрузки с параметром шаблона с именем ExecutionPolicy сообщают об ошибках следующим образом:
- Если при выполнении функции, вызванной в рамках алгоритма, выбрасывается исключение и
ExecutionPolicyявляется одной из стандартных политик, вызываетсяstd::terminate. Для любой другойExecutionPolicyповедение определяется реализацией. - Если алгоритму не удаётся выделить память, выбрасывается
std::bad_alloc.
Примечания
std::reduce действует так же, как std::accumulate, за исключением того, что элементы диапазона могут группироваться и переставляться в произвольном порядке.
Пример
Сравнение std::reduce и std::accumulate:
#if PARALLEL
#include <execution>
#define SEQ std::execution::seq,
#define PAR std::execution::par,
#else
#define SEQ
#define PAR
#endif
#include <chrono>
#include <iomanip>
#include <iostream>
#include <locale>
#include <numeric>
#include <utility>
#include <vector>
int main()
{
std::cout.imbue(std::locale("en_US.UTF-8"));
std::cout << std::fixed << std::setprecision(1);
auto eval = [](auto fun)
{
const auto t1 = std::chrono::high_resolution_clock::now();
const auto [name, result] = fun();
const auto t2 = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double, std::milli> ms = t2 - t1;
std::cout << std::setw(28) << std::left << name << "sum: "
<< result << '\t' << "time: " << ms.count() << " ms\n";
};
{
const std::vector<double> v(100'000'007, 0.1);
eval([&v]{ return std::pair{"std::accumulate (double)",
std::accumulate(v.cbegin(), v.cend(), 0.0)}; });
eval([&v]{ return std::pair{"std::reduce (seq, double)",
std::reduce(SEQ v.cbegin(), v.cend())}; });
eval([&v]{ return std::pair{"std::reduce (par, double)",
std::reduce(PAR v.cbegin(), v.cend())}; });
}
{
const std::vector<long> v(100'000'007, 1);
eval([&v]{ return std::pair{"std::accumulate (long)",
std::accumulate(v.cbegin(), v.cend(), 0l)}; });
eval([&v]{ return std::pair{"std::reduce (seq, long)",
std::reduce(SEQ v.cbegin(), v.cend())}; });
eval([&v]{ return std::pair{"std::reduce (par, long)",
std::reduce(PAR v.cbegin(), v.cend())}; });
}
}
Возможный вывод:
// POSIX: g++ -std=c++23 ./example.cpp -ltbb -O3; ./a.out std::accumulate (double) sum: 10,000,000.7 time: 356.9 ms std::reduce (seq, double) sum: 10,000,000.7 time: 140.1 ms std::reduce (par, double) sum: 10,000,000.7 time: 140.1 ms std::accumulate (long) sum: 100,000,007 time: 46.0 ms std::reduce (seq, long) sum: 100,000,007 time: 67.3 ms std::reduce (par, long) sum: 100,000,007 time: 63.3 ms // POSIX: g++ -std=c++23 ./example.cpp -ltbb -O3 -DPARALLEL; ./a.out std::accumulate (double) sum: 10,000,000.7 time: 353.4 ms std::reduce (seq, double) sum: 10,000,000.7 time: 140.7 ms std::reduce (par, double) sum: 10,000,000.7 time: 24.7 ms std::accumulate (long) sum: 100,000,007 time: 42.4 ms std::reduce (seq, long) sum: 100,000,007 time: 52.0 ms std::reduce (par, long) sum: 100,000,007 time: 23.1 ms
См. также
| вычисляет сумму или свёртку диапазона элементов (шаблон функции) |
|
| применяет функцию к диапазону элементов, сохраняя результаты в целевом диапазоне (шаблон функции и объект-функция алгоритма) |
|
|
(C++20) | |
|
(C++17) | применяет вызываемый объект, а затем выполняет свёртку в произвольном порядке (шаблон функции) |
|
(C++23) | выполняет свёртку диапазона элементов слева направо (объект-функция алгоритма) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/reduce