std::partial_sum(3)
π std::partial_sum(3) β your C++ Standard Libary bestie π
okay so this is the std::partial_sum(3) page from the C++ Standard Libary manual (yes, that spelling is on the page, donβt come for me π). Itβs giving niche algorithm realness, and weβre gonna get through it together, bestie π
.
πΈ NAME πΈ
std::partial_sum - std::partial_sum
Thatβs literally the whole NAME section. Minimalism ate. Periodt π.
β¨ Synopsis β¨
Defined in header <numeric>.
template< class InputIt, class OutputIt >
OutputIt partial_sum( InputIt first, InputIt last, OutputIt d_first );
(1)βconstexprsince C++20.
template< class InputIt, class OutputIt, class BinaryOp >
OutputIt partial_sum( InputIt first, InputIt last, OutputIt d_first, BinaryOp op );
(2)βconstexprsince C++20.
π«Ά What (1) does, step by step π«Ά
- If
[first, last)is empty, it does nothing. - Otherwise, it performs the following operations in order:
- Creates an accumulator
acc, whose type is the value type ofInputIt, and initializes it with*first. - Assigns
accto*d_first. - For each integer
iin[1, std::distance(first, last)), performs the following operations in order:
a. Computes acc + *iter (until C++11) / std::move(acc) + *iter (since C++11), where iter is the next ith iterator of first.
b. Assigns the result to acc.
c. Assigns acc^[1] to *dest, where dest is the next ith iterator of d_first.
^[1] The actual value to be assigned is the result of the assignment in the previous step. We assume the assignment result is acc here.
π« What (2) does π«
Same as (1), but computes op(acc, *iter) (until C++11) / op(std::move(acc), *iter) (since C++11) instead.
Given binary_op as the actual binary operation:
- If any of the following conditions is satisfied, the program is ill-formed:
- The value type of
InputItis not constructible from*first. accis not writable tod_first.- The result of
binary_op(acc, *iter)(until C++11) /binary_op(std::move(acc), *iter)(since C++11) is not implicitly convertible to the value type ofInputIt.
- The value type of
- Given
d_lastas the iterator to be returned, if any of the following conditions is satisfied, the behavior is undefined:binary_opmodifies any element of[first, last)or[d_first, d_last).binary_opinvalidates any iterator or subrange in[first, last]or[d_first, d_last].
π Parameters π
first,lastβ the range of elements to sum.d_firstβ the beginning of the destination range; may be equal tofirst.opβ binary operation function object that will be applied.
The signature of the function should be equivalent to the following:
Ret fun(const Type1 &a, const Type2 &b);
- The signature does not need to have
const &. - The type
Type1must be such that an object of typestd::iterator_traits<InputIt>::value_typecan be implicitly converted toType1. - The type
Type2must be such that an object of typeInputItcan be dereferenced and then implicitly converted toType2. - The type
Retmust be such that an object of typeInputItcan be dereferenced and assigned a value of typeRet.
π¦ Type requirements π¦
InputItmust meet the requirements ofLegacyInputIterator.OutputItmust meet the requirements ofLegacyOutputIterator.
π Return value π
Iterator to the element past the last element written, or d_first if [first, last) is empty.
π₯ Complexity π₯
Given (\scriptsize N)N as std::distance(first, last):
- Exactly (\scriptsize N-1)N-1 applications of
operator+. - Exactly (\scriptsize N-1)N-1 applications of the binary function
op.
π Possible implementation π
bestie, hereβs the exact juice π§:
partial_sum (1)
template<class InputIt, class OutputIt>
constexpr // since C++20
OutputIt partial_sum(InputIt first, InputIt last, OutputIt d_first)
{
if (first == last)
return d_first;
typename std::iterator_traits<InputIt>::value_type sum = *first;
*d_first = sum;
while (++first != last)
{
sum = std::move(sum) + *first; // std::move since C++11
*++d_first = sum;
}
return ++d_first;
// or, since C++14:
// return std::partial_sum(first, last, d_first, std::plus<>());
}
partial_sum (2)
template<class InputIt, class OutputIt, class BinaryOp>
constexpr // since C++20
OutputIt partial_sum(InputIt first, InputIt last,
OutputIt d_first, BinaryOp op)
{
if (first == last)
return d_first;
typename std::iterator_traits<InputIt>::value_type acc = *first;
*d_first = acc;
while (++first != last)
{
acc = op(std::move(acc), *first); // std::move since C++11
*++d_first = acc;
}
return ++d_first;
}
π Notes π
acc was introduced because of the resolution of LWG issue 539. The reason of using acc rather than directly summing up the results (i.e. *(d_first + 2) = (*first + *(first + 1)) + *(first + 2);) is because the semantic of the latter is confusing if the following types mismatch:
- the value type of
InputIt - the writable type(s) of
OutputIt - the types of the parameters of
operator+orop - the return type of
operator+orop
acc serves as the intermediate object to store and provide the values for each step of the computation:
- its type is the value type of
InputIt - it is written to
d_first - its value is passed to
operator+orop - it stores the return value of
operator+orop
enum not_int { x = 1, y = 2 };
char i_array[4] = {100, 100, 100, 100};
not_int e_array[4] = {x, x, y, y};
int o_array[4];
// OK: uses operator+(char, char) and assigns char values to int array
std::partial_sum(i_array, i_array + 4, o_array);
// Error: cannot assign not_int values to int array
std::partial_sum(e_array, e_array + 4, o_array);
// OK: performs conversions when needed
// 1. creates βaccβ of type char (the value type)
// 2. the char arguments are used for long multiplication (char ->
long)
// 3. the long product is assigned to βaccβ (long -> char)
// 4. βaccβ is assigned to an element of βo_arrayβ (char -> int)
// 5. go back to step 2 to process the remaining elements in the input
range
std::partial_sum(i_array, i_array + 4, o_array,
std::multiplies<long>{});
π Example π
Run this code:
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main()
{
std::vector<int> v(10, 2); // v = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
std::cout << "The first " << v.size() << " even numbers are: ";
// write the result to the cout stream
std::partial_sum(v.cbegin(), v.cend(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
// write the result back to the vector v
std::partial_sum(v.cbegin(), v.cend(),
v.begin(), std::multiplies<int>());
std::cout << "The first " << v.size() << " powers of 2 are: ";
for (int n : v)
std::cout << n << ' ';
std::cout << '\n';
}
π Output π
The first 10 even numbers are: 2 4 6 8 10 12 14 16 18 20
The first 10 powers of 2 are: 2 4 8 16 32 64 128 256 512 1024
π§ Defect reports π§
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
- LWG 242 β applied to C++98. Behavior as published:
opcould not have side effects. Correct behavior: it cannot modify the ranges involved. - LWG 539 β applied to C++98. Behavior as published: the type requirements needed for the result evaluations and assignments to be valid were missing. Correct behavior: added.
- LWG 2055 β applied to C++11. Behavior as published:
accwas not moved while being accumulated. Correct behavior: it is moved (P0616R0).
π See also π
adjacent_differenceβ computes the differences between adjacent elements in a range (function template).accumulateβ sums up or folds a range of elements (function template).inclusive_scan(C++17) β similar tostd::partial_sum, includes thei^th input element in thei^th sum (function template).exclusive_scan(C++17) β similar tostd::partial_sum, excludes thei^th input element from thei^th sum (function template).
source/version: http://cppreference.com, 2024.06.10 β mwah π
π¦ 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