std::reduce(3)
π
std::reduce β C++ Standard Library (std::reduce(3)) β¨
π NAME π
std::reduce β std::reduce. Thatβs it. The name is the name, and honestly? iconic. π«Ά
π Synopsis π
Defined in header <numeric>
template< class InputIt >
typename std::iterator_traits<InputIt>::value_type
reduce( InputIt first, InputIt last ); (1) (since C++17) (constexpr since C++20)
template< class ExecutionPolicy, class ForwardIt >
typename std::iterator_traits<ForwardIt>::value_type
reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last ); (2) (since C++17)
template< class InputIt, class T >
T reduce( InputIt first, InputIt last, T init ); (3) (since C++17) (constexpr since C++20)
template< class ExecutionPolicy, class ForwardIt, class T >
T reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, T init ); (4) (since C++17)
template< class InputIt, class T, class BinaryOp >
T reduce( InputIt first, InputIt last, T init, BinaryOp op ); (5) (since C++17) (constexpr since C++20)
template< class ExecutionPolicy,
class ForwardIt, class T, class BinaryOp >
T reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, T init, BinaryOp op ); (6) (since C++17)
okay so hereβs the overload tea, bestie:
1)Equivalent toreduce(first, last, typename std::iterator_traits<InputIt>::value_type{}).3)Equivalent toreduce(first, last, init, std::plus<>()).5)Reduces the range[first, last), possibly permuted and aggregated in unspecified manner, along with the initial valueinitoverop.2,4,6)Same as(1,3,5), but executed according topolicy. These overloads participate in overload resolution only ifstd::is_execution_policy_v<std::decay_t<ExecutionPolicy>>istrue. (until C++20)std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>istrue. (since C++20)
Given binary_op as the actual binary operation:
- The result is non-deterministic if the
binary_opis not associative or not commutative (such as floating-point addition). - If any of the following values is not convertible to
T, the program is ill-formed:binary_op(init, *first)binary_op(*first, init)binary_op(init, init)binary_op(*first, *first)
- If any of the following conditions is satisfied, the behavior is undefined:
Tis notMoveConstructible.binary_opmodifies any element of[first, last).binary_opinvalidates any iterator or subrange of[first, last).
πΈ Parameters πΈ
first,lastβ the range of elements to apply the algorithm to.initβ the initial value of the generalized sum.policyβ the execution policy to use. See execution policy for details.opβ binaryFunctionObjectthat will be applied in unspecified order to the result of dereferencing the input iterators, the results of otheropandinit.
π¦ Type requirements π¦
InputItmust meet the requirements ofLegacyInputIterator.ForwardItmust meet the requirements ofLegacyForwardIterator.
β¨ Return value β¨
1-4)The generalized sum ofinitand the elements of[first, last)overstd::plus<>().5,6)The generalized sum ofinitand the elements of[first, last)overop.
The generalized sum of a group of elements over an binary operation binary_op is defined as follows:
- If the group only has one element, the sum is the value of the element.
- Otherwise, performs the following operations in order:
- Takes any two elements
elem1andelem2from the group. - Calculates
binary_op(elem1, elem2)and puts the result back to the group. - Repeats steps 1 and 2 until there is only one element in the group.
- Takes any two elements
π₯ Complexity π₯
Given \(\scriptsize N\)N as std::distance(first, last):
1-4)\(\scriptsize O(N)\)O(N)applications ofstd::plus<>().5,6)\(\scriptsize O(N)\)O(N)applications ofop.
π Exceptions π
The overloads with a template parameter named ExecutionPolicy report errors as follows:
- If execution of a function invoked as part of the algorithm throws an exception and
ExecutionPolicyis one of the standard policies,std::terminateis called. For any otherExecutionPolicy, the behavior is implementation-defined. - If the algorithm fails to allocate memory,
std::bad_allocis thrown.
π§ Notes π§
std::reduce behaves like std::accumulate except the elements of the range may be grouped and rearranged in arbitrary order.
π Example π
side-by-side comparison between std::reduce and std::accumulate:
// Run this code
#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 <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())}; });
}
}
Possible output
// 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
π See also π
accumulateβ sums up or folds a range of elements (function template)transformβ applies a function to a range of elements, storing results in a destination range (function template)transform_reduce(C++17)β applies an invocable, then reduces out of order (function template)ranges::fold_left(C++23)β left-folds a range of elements (niebloid)
mwah π β source: http://cppreference.com Β· version/date: 2024.06.10 Β· manual: std::reduce(3) ππ«Ά
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms