Accumulate c что это
A generalized numeric operation that accumulates all elements within a range into a single value
Synopsis
Description
accumulate() applies a binary operation to init and each value in the range [start,finish) . The result of each operation is returned in init . This process aggregates the result of performing the operation on every element of the sequence into a single value.
The accumulator acc is initialized with the value init and modified with acc = acc + *i or acc = binary_op(acc, *i) for each interator i , in order, in the range [start, finish) .
Complexity
accumulate() performs exactly finish-start applications of the binary operation, operator+ by default.
Example
// // accum.cpp // #include <numeric> // for accumulate #include <vector> // for vector #include <functional> // for multiplies #include <iostream> // for cout int main () < // Typedef for convenience. typedef std::vector<int, std::allocator<int> > vector; // Initialize a vector using an array of integers. const vector::value_type arr[] = < 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 >; vector v1 (arr, arr + sizeof arr / sizeof *arr); // Accumulate sums and products. vector::value_type sum = std::accumulate (v1.begin (), v1.end (), 0); vector::value_type prod = std::accumulate (v1.begin (), v1.end (), 1, std::multiplies<vector::value_type>()); // Output the results. std::cout << «For the series: «; for (vector::iterator i = v1.begin (); i != v1.end (); ++i) std::cout << *i << » «; std::cout << «where N = » << v1.size () << «\nThe sum = (N * N + N) / 2 = » << sum << «\nThe product = N! sec7″>
Standards Conformance
ISO/IEC 14882:1998 — International Standard for Information Systems — Programming Language C++, Section 26.4.1
std::accumulate
Computes the sum of the given value init and the elements in the range [first, last) . The first version uses operator+ to sum up the elements, the second version uses the given binary function op , both applying std::move to their operands on the left hand side (since C++20) .
op must not have side effects.
op must not invalidate any iterators, including the end iterators, nor modify any elements of the range involved, nor *last.
Parameters
| first, last | — | the range of elements to sum |
| init | — | initial value of the sum |
| op | — | binary operation function object that will be applied. The binary operator takes the current accumulation value a (initialized to init ) and the value of the current element b . |
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 Type1 must be such that an object of type T can be implicitly converted to Type1 . The type Type2 must be such that an object of type InputIt can be dereferenced and then implicitly converted to Type2 . The type Ret must be such that an object of type T can be assigned a value of type Ret .
Return value
Notes
std::accumulate performs a left fold. In order to perform a right fold, one must reverse the order of the arguments to the binary operator, and use reverse iterators.
std::accumulate
Вычисляет сумму заданного значения init и элементов в диапазоне [first, last) . Первая версия использует operator+ для суммирования элементов, вторая версия использует заданную двоичную функцию op , обе применяют std::move к своим операндам с левой стороны (начиная с C ++ 20).
op не должно иметь побочных эффектов.
op не должен делать недействительными какие-либо итераторы, включая конечные итераторы, а также изменять какие-либо элементы задействованного диапазона или *last.
Parameters
| first, last | — | диапазон элементов в сумме |
| init | — | начальная стоимость суммы |
| op | — | объект бинарной операции, который будет применен. Двоичный оператор принимает текущее значение накопления a (инициализированное для init ) и значение текущего элемента b . |
Подпись функции должна быть эквивалентна следующей:
Ret fun(const Type1 &a, const Type2 &b);
Подпись не должна иметь const & .
Тип Type1 должен быть таким, чтобы объект типа T мог быть неявно преобразован в Type1 . Тип Type2 должен быть таким, чтобы объект типа InputIt мог быть разыменован, а затем неявно преобразован в Type2 . Тип Ret должен быть таким, чтобы объекту типа T можно было присвоить значение типа Ret .
Return value
Notes
std::accumulate выполняет левый сгиб. Чтобы выполнить правильное свертывание, необходимо изменить порядок аргументов в бинарном операторе и использовать обратные итераторы.
Understanding std::accumulate
I want to know why std::accumulate (aka reduce) 3rd parameter is needed. For those who do not know what accumulate is, it’s used like so:
Call to accumulate is equivalent to:
There is also optional 4th parameter, which allow to replace addition with any other operation.
Rationale that I’ve heard is that if you need let say not to add up, but multiply elements of a vector, we need other (non-zero) initial value:
But why not do like Python — set initial value for V.begin() , and use range starting from V.begin()+1 . Something like this:
This will work for any op. Why is 3rd parameter needed at all?
5 Answers 5
You’re making a mistaken assumption: that type T is of the same type as the InputIterator .
But std::accumulate is generic, and allows all different kinds of creative accumulations and reductions.
Example #1: Accumulate salary across Employees
Here’s a simple example: an Employee class, with many data fields.
You can’t meaningfully «accumulate» a set of employees. That makes no sense; it’s undefined. But, you can define an accumulation regarding the employees. Let’s say we want to sum up all the monthly pay of all employees. std::accumulate can do that:
So in this example, we’re accumulating an int value over a collection of Employee objects. Here, the accumulation sum isn’t the same type of variable that we’re actually summing over.
Example #2: Accumulating an average
You can use accumulate for more complex types of accumulations as well — maybe want to append values to a vector; maybe you have some arcane statistic you’re tracking across the input; etc. What you accumulate doesn’t have to be just a number; it can be something more complex.
For example, here’s a simple example of using accumulate to calculate the average of a vector of ints:
Example #3: Accumulate a running average
Another reason you need the initial value is because that value isn’t always the default/neutral value for the calculation you’re making.
Let’s build on the average example we’ve already seen. But now, we want a class that can hold a running average — that is, we can keep feeding in new values, and check the average so far, across multiple calls.
This is a case where we absolutely rely on being able to set that initial value for std::accumulate — we need to be able to initialize the accumulation from different starting points.
In summary, std::accumulate is good for any time you’re iterating over an input range, and building up one single result across that range. But the result doesn’t need to be the same type as the range, and you can’t make any assumptions about what initial value to use — which is why you must have an initial instance to use as the accumulating result.