std::reduce
| Défini dans l'en-tête <numeric>
|
||
template< class InputIt >
typename std::iterator_traits<InputIt>::value_type
reduce( InputIt first, InputIt last );
|
(1) | (depuis C++17) (constexpr depuis C++20) |
template< class ExecutionPolicy, class ForwardIt >
typename std::iterator_traits<ForwardIt>::value_type
reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last );
|
(2) | (depuis C++17) |
template< class InputIt, class T >
T reduce( InputIt first, InputIt last, T init );
|
(3) | (depuis C++17) (constexpr depuis C++20) |
template< class ExecutionPolicy, class ForwardIt, class T >
T reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, T init );
|
(4) | (depuis C++17) |
template< class InputIt, class T, class BinaryOp >
T reduce( InputIt first, InputIt last, T init, BinaryOp op );
|
(5) | (depuis C++17) (constexpr depuis C++20) |
template< class ExecutionPolicy,
class ForwardIt, class T, class BinaryOp >
T reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, T init, BinaryOp op );
|
(6) | (depuis C++17) |
reduce(first, last, typename std::iterator_traits<InputIt>::value_type{}).reduce(first, last, init, std::plus<>()).[first, last), éventuellement permutée et agrégée de manière non spécifiée, avec la valeur initiale init sur op.policy.true :
|
|
(jusqu'à C++20) |
|
|
(depuis C++20) |
Soit binary_op l'opération binaire effective :
- Le résultat est non déterministe si le
binary_opn'est pas associatif ou n'est pas commutatif (comme l'addition en virgule flottante).
- Si l'une des valeurs suivantes n'est pas convertible en
T, le programme est mal formé :
binary_op(init, *first)binary_op(*first, init)binary_op(init, init)binary_op(*first, *first)
- Si l'une des conditions suivantes est satisfaite, le comportement est indéfini :
Tn'est pas MoveConstructible.binary_opmodifie tout élément de[first,last).binary_opinvalide tout itérateur ou sous-plage de[first,last].
Paramètres
| first, last | - | la paire d'itérateurs définissant l'intervalle des éléments auxquels appliquer l'algorithme |
| init | - | la valeur initiale de la somme généralisée |
| policy | - | la politique d'exécution à utiliser |
| op | - | le FunctionObject binaire qui sera appliqué dans un ordre non spécifié au résultat de la déréférenciation des itérateurs d'entrée, aux résultats d'autres op et init . |
| Exigences de type | ||
-
InputIt
doit satisfaire aux exigences de
LegacyInputIterator
.
|
||
-
ForwardIt
doit satisfaire aux exigences de
LegacyForwardIterator
.
|
||
Valeur de retour
[
first
,
last
)
sur
op
.
La somme généralisée d'un groupe d'éléments sur une opération binaire binary_op est définie comme suit :
- Si le groupe ne contient qu'un seul élément, la somme est la valeur de cet élément.
- Sinon, effectue les opérations suivantes dans l'ordre :
- Prend deux éléments quelconques elem1 et elem2 du groupe.
- Calcule binary_op ( elem1, elem2 ) et replace le résultat dans le groupe.
- Répète les étapes 1 et 2 jusqu'à ce qu'il ne reste qu'un seul élément dans le groupe.
Complexité
Étant donné N comme std:: distance ( first, last ) :
Exceptions
Les surcharges avec un paramètre de modèle nommé
ExecutionPolicy
signalent les erreurs comme suit :
-
Si l'exécution d'une fonction invoquée dans le cadre de l'algorithme lève une exception et que
ExecutionPolicyfait partie des politiques standard , std::terminate est appelé. Pour tout autreExecutionPolicy, le comportement est défini par l'implémentation. - Si l'algorithme ne parvient pas à allouer de la mémoire, std::bad_alloc est levé.
Notes
std::reduce
se comporte comme
std::accumulate
sauf que les éléments de la plage peuvent être groupés et réorganisés dans un ordre arbitraire.
Exemple
Comparaison côte à côte entre
std::reduce
et
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 [nom, résultat] = 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 << nom << "somme : " << résultat << '\t' << "temps : " << 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())}; }); } }
Sortie possible :
// POSIX: g++ -std=c++23 ./example.cpp -ltbb -O3; ./a.out std::accumulate (double) somme : 10,000,000.7 temps : 356.9 ms std::reduce (seq, double) somme : 10,000,000.7 temps : 140.1 ms std::reduce (par, double) somme : 10,000,000.7 temps : 140.1 ms std::accumulate (long) somme : 100,000,007 temps : 46.0 ms std::reduce (seq, long) somme : 100,000,007 temps : 67.3 ms std::reduce (par, long) somme : 100,000,007 temps : 63.3 ms // POSIX: g++ -std=c++23 ./example.cpp -ltbb -O3 -DPARALLEL; ./a.out std::accumulate (double) somme : 10,000,000.7 temps : 353.4 ms std::reduce (seq, double) somme : 10,000,000.7 temps : 140.7 ms std::reduce (par, double) somme : 10,000,000.7 temps : 24.7 ms std::accumulate (long) somme : 100,000,007 temps : 42.4 ms std::reduce (seq, long) somme : 100,000,007 temps : 52.0 ms std::reduce (par, long) somme : 100,000,007 temps : 23.1 ms
Voir aussi
| additionne ou plie une plage d'éléments (modèle de fonction) | |
| applique une fonction à une plage d'éléments, stocke les résultats dans une plage de destination (modèle de fonction & objet fonction d'algorithme) | |
(C++20) |
|
(C++17) |
applique un invocable, puis réduit dans le désordre (modèle de fonction) |
(C++23) |
plie à gauche une plage d'éléments (objet fonction d'algorithme) |