Namespaces
Variants

std::reduce

От ru.cppreference.net
 
 
Библиотека алгоритмов
Ограниченные алгоритмы и алгоритмы над диапазонами (C++20)
Ограниченные алгоритмы, например ranges::copy, ranges::sort, ...
Операции над последовательностями без изменения    
Пакетные операции
(C++17)
Операции поиска
Операции над последовательностями с изменением
Операции копирования
(C++11)
(C++11)
Операции обмена
Операции преобразования
Операции генерации
Операции удаления
Операции изменения порядка
(до C++17)(C++11)
(C++20)(C++20)
Операции выборки
(C++17)

Операции сортировки и связанные с ними
Операции разделения
(C++11)    

Операции сортировки
Операции бинарного поиска
(на разделённых диапазонах)
Операции над множествами (на отсортированных диапазонах)
Операции слияния (на отсортированных диапазонах)
Операции с кучей
Операции минимума/максимума
(C++11)
(C++17)
Операции лексикографического сравнения
Операции перестановок


Политики выполнения (C++17)
(только для пояснения*)(C++26)

Численные операции
(C++11)
(C++17)
(C++17)    

Специализированные <memory> алгоритмы

Специализированные <random> алгоритмы
Библиотека C









 
 
Определено в заголовке <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)
1) Эквивалентно reduce(first, last, typename std::iterator_traits<InputIt>::value_type{}).
3) Эквивалентно reduce(first, last, init, std::plus<>()).
5) Сворачивает диапазон [first, last), возможно переставленный и агрегированный неопределённым образом, вместе с начальным значением init с помощью op.
2,4,6) То же, что и (1,3,5), но выполняется в соответствии с policy.
Эти перегрузки участвуют в разрешении перегрузки только если значение следующего выражения равно true:

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(начиная с 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 - бинарный FunctionObject , который будет применён в неопределённом порядке к результату разыменования входных итераторов, результатам других op и init .
Требования к типам
-
InputIt должен удовлетворять требованиям LegacyInputIterator .
-
ForwardIt должен удовлетворять требованиям LegacyForwardIterator .

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

1-4) Обобщенная сумма init и элементов диапазона [ first , last ) с использованием std:: plus <> ( ) .
5,6) Обобщённая сумма init и элементов диапазона [ first , last ) с использованием операции op .

Обобщённая сумма группы элементов над бинарной операцией binary_op определяется следующим образом:

  • Если группа содержит только один элемент, сумма равна значению этого элемента.
  • В противном случае выполняет следующие операции в указанном порядке:
  1. Берёт любые два элемента elem1 и elem2 из группы.
  2. Вычисляет binary_op ( elem1, elem2 ) и возвращает результат обратно в группу.
  3. Повторяет шаги 1 и 2 до тех пор, пока в группе не останется только один элемент.

Сложность

Дано N как std:: distance ( first, last ) :

1-4) O(N) применений std:: plus <> ( ) .
5,6) O(N) применений 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 << "сумма: "
                  << result << '\t' << "время: " << ms.count() << " мс\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)    сумма: 10,000,000.7	время: 356.9 мс
std::reduce (seq, double)   сумма: 10,000,000.7	время: 140.1 мс
std::reduce (par, double)   сумма: 10,000,000.7	время: 140.1 мс
std::accumulate (long)      сумма: 100,000,007	время: 46.0 мс
std::reduce (seq, long)     сумма: 100,000,007	время: 67.3 мс
std::reduce (par, long)     сумма: 100,000,007	время: 63.3 мс
// POSIX: g++ -std=c++23 ./example.cpp -ltbb -O3 -DPARALLEL; ./a.out
std::accumulate (double)    сумма: 10,000,000.7	время: 353.4 мс
std::reduce (seq, double)   сумма: 10,000,000.7	время: 140.7 мс
std::reduce (par, double)   сумма: 10,000,000.7	время: 24.7 мс
std::accumulate (long)      сумма: 100,000,007	время: 42.4 мс
std::reduce (seq, long)     сумма: 100,000,007	время: 52.0 мс
std::reduce (par, long)     сумма: 100,000,007	время: 23.1 мс

Смотри также

суммирует или выполняет свёртку диапазона элементов
(шаблон функции)
применяет функцию к диапазону элементов, сохраняя результаты в диапазоне назначения
(шаблон функции & объект функции алгоритма)
применяет вызываемый объект, затем выполняет редукцию в произвольном порядке
(шаблон функции)
выполняет левую свёртку диапазона элементов
(объект функции алгоритма)