std:: reduce
|
Definiert in Header
<numeric>
|
||
|
template
<
class
InputIt
>
typename
std::
iterator_traits
<
InputIt
>
::
value_type
|
(1) |
(seit C++17)
(constexpr seit C++20) |
|
template
<
class
ExecutionPolicy,
class
ForwardIt
>
typename
std::
iterator_traits
<
ForwardIt
>
::
value_type
|
(2) | (seit C++17) |
|
template
<
class
InputIt,
class
T
>
T reduce ( InputIt first, InputIt last, T init ) ; |
(3) |
(seit C++17)
(constexpr seit C++20) |
|
template
<
class
ExecutionPolicy,
class
ForwardIt,
class
T
>
T reduce
(
ExecutionPolicy
&&
policy,
|
(4) | (seit C++17) |
|
template
<
class
InputIt,
class
T,
class
BinaryOp
>
T reduce ( InputIt first, InputIt last, T init, BinaryOp op ) ; |
(5) |
(seit C++17)
(constexpr seit C++20) |
|
template
<
class
ExecutionPolicy,
class
ForwardIt,
class
T,
class
BinaryOp
>
|
(6) | (seit C++17) |
[
first
,
last
)
, möglicherweise permutiert und auf nicht spezifizierte Weise aggregiert, zusammen mit dem Anfangswert
init
über
op
.
|
std:: is_execution_policy_v < std:: decay_t < ExecutionPolicy >> ist true . |
(bis C++20) |
|
std:: is_execution_policy_v < std:: remove_cvref_t < ExecutionPolicy >> ist true . |
(seit C++20) |
Gegeben binary_op als die tatsächliche binäre Operation:
- Das Ergebnis ist nicht deterministisch, wenn die binary_op nicht assoziativ oder nicht kommutativ ist (wie beispielsweise die Gleitkomma-Addition).
-
Wenn einer der folgenden Werte nicht in
Tkonvertierbar ist, ist das Programm fehlerhaft:
-
- binary_op ( init, * first )
- binary_op ( * first, init )
- binary_op ( init, init )
- binary_op ( * first, * first )
- Wenn eine der folgenden Bedingungen erfüllt ist, ist das Verhalten undefiniert:
-
-
Tist nicht MoveConstructible . -
binary_op
modifiziert irgendein Element von
[first,last). -
binary_op
macht irgendeinen Iterator oder Teilbereich von
[first,last]ungültig.
-
Inhaltsverzeichnis |
Parameter
| first, last | - | das Paar von Iteratoren, das den Bereich der Elemente definiert, auf die der Algorithmus angewendet werden soll |
| init | - | der Anfangswert der generalisierten Summe |
| policy | - | die zu verwendende Ausführungsrichtlinie |
| op | - | binäres FunctionObject , das in nicht spezifizierter Reihenfolge auf das Ergebnis der Dereferenzierung der Eingabeiteratoren, die Ergebnisse anderer op und init angewendet wird. |
| Typanforderungen | ||
-
InputIt
muss die Anforderungen von
LegacyInputIterator
erfüllen.
|
||
-
ForwardIt
muss die Anforderungen von
LegacyForwardIterator
erfüllen.
|
||
Rückgabewert
[
first
,
last
)
über
std::
plus
<>
(
)
.
[
first
,
last
)
über
op
.
Die verallgemeinerte Summe einer Gruppe von Elementen über eine binäre Operation binary_op ist wie folgt definiert:
- Wenn die Gruppe nur ein Element hat, ist die Summe der Wert des Elements.
- Andernfalls werden die folgenden Operationen in dieser Reihenfolge ausgeführt:
- Nimmt zwei beliebige Elemente elem1 und elem2 aus der Gruppe.
- Berechnet binary_op ( elem1, elem2 ) und fügt das Ergebnis zurück in die Gruppe ein.
- Wiederholt die Schritte 1 und 2, bis nur noch ein Element in der Gruppe vorhanden ist.
Komplexität
Gegeben N als std:: distance ( first, last ) :
Ausnahmen
Die Überladungen mit einem Template-Parameter namens
ExecutionPolicy
melden Fehler wie folgt:
-
Wenn die Ausführung einer als Teil des Algorithmus aufgerufenen Funktion eine Exception wirft und
ExecutionPolicyeiner der Standard-Policies ist, wird std::terminate aufgerufen. Für jede andereExecutionPolicyist das Verhalten implementierungsdefiniert. - Wenn der Algorithmus keinen Speicher allokieren kann, wird std::bad_alloc geworfen.
Hinweise
std::reduce
verhält sich wie
std::accumulate
, außer dass die Elemente des Bereichs in beliebiger Reihenfolge gruppiert und neu angeordnet werden können.
Beispiel
Gegenüberstellung von
std::reduce
und
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 << "Summe: " << result << '\t' << "Zeit: " << 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())}; }); } }
Mögliche Ausgabe:
// POSIX: g++ -std=c++23 ./example.cpp -ltbb -O3; ./a.out std::accumulate (double) Summe: 10.000.000,7 Zeit: 356,9 ms std::reduce (seq, double) Summe: 10.000.000,7 Zeit: 140,1 ms std::reduce (par, double) Summe: 10.000.000,7 Zeit: 140,1 ms std::accumulate (long) Summe: 100.000.007 Zeit: 46,0 ms std::reduce (seq, long) Summe: 100.000.007 Zeit: 67,3 ms std::reduce (par, long) Summe: 100.000.007 Zeit: 63,3 ms // POSIX: g++ -std=c++23 ./example.cpp -ltbb -O3 -DPARALLEL; ./a.out std::accumulate (double) Summe: 10.000.000,7 Zeit: 353,4 ms std::reduce (seq, double) Summe: 10.000.000,7 Zeit: 140,7 ms std::reduce (par, double) Summe: 10.000.000,7 Zeit: 24,7 ms std::accumulate (long) Summe: 100.000.007 Zeit: 42,4 ms std::reduce (seq, long) Summe: 100.000.007 Zeit: 52,0 ms std::reduce (par, long) Summe: 100.000.007 Zeit: 23,1 ms
Siehe auch
|
summiert oder faltet eine Reihe von Elementen
(Funktions-Template) |
|
|
wendet eine Funktion auf einen Elementbereich an und speichert Ergebnisse in einem Zielbereich
(Funktions-Template) |
|
|
(C++17)
|
wendet ein Aufrufbares an und reduziert dann außerhalb der Reihenfolge
(Funktions-Template) |
|
(C++23)
|
faltet einen Elementbereich von links
(Algorithmus-Funktionsobjekt) |