Шрифт:
{
while (first!=last) {
init = init + *first;
++first;
}
return init;
}
Получив начальное значение
init
, он просто добавляет к нему каждое значение из последовательности [first:last]
и возвращает сумму. Переменную init
, в которой накапливается сумма, часто называют аккумулятором (accumulator). Рассмотрим пример.
int a[] = { 1, 2, 3, 4, 5 };
cout << accumulate(a, a+sizeof(a)/sizeof(int), 0);
Этот фрагмент кода выводит на экран число 15, т.е. 0+1+2+3+4+5 (0 является начальным значением). Очевидно, что алгоритм
accumulate
можно использовать для всех видов последовательностей.
void f(vector<double>& vd,int* p,int n)
{
double sum = accumulate(vd.begin,vd.end,0.0);
int sum2 = accumulate(p,p+n,0);
}
Тип результата (суммы) совпадает с типом переменной, которую алгоритм
accumulate
использует в качестве аккумулятора. Это обеспечивает высокую степень гибкости которая может играть важную роль. Рассмотрим пример.
void f(int* p,int n)
{
int s1 = accumulate(p, p+n, 0); // суммируем целые числа в int
long sl = accumulate(p, p+n, long(0)); // суммируем целые числа
// в long
double s2 = accumulate(p, p+n, 0.0); // суммируем целые числа
// в double
}
На некоторых компьютерах переменная типа
long
состоит из гораздо большего количества цифр, чем переменная типа int
. Переменная типа double
может представить большие (и меньшие) числа, чем переменная типа int
, но, возможно, с меньшей точностью. В главе 24 мы еще вернемся к вопросу о диапазоне и точности в вычислениях.
init
в качестве аккумулятора представляет собой весьма распространенную идиому, позволяющую задать тип аккумулятора.
void f(vector<double>& vd,int* p,int n)
{
double s1 = 0;
s1 = accumulate(vd.begin,vd.end,s1);
int s2 = accumulate(vd.begin, vd.end,s2); // Ой
float s3 = 0;
accumulate(vd.begin, vd.end, s3); // Ой
}
accumulate
какой-нибудь переменной. В данном примере в качестве инициализатора использовалась переменная s2
, которая сама еще не получила начальное значение до вызова алгоритма; результат такого вызова будет непредсказуем. Мы передали переменную s3
алгоритму accumulate
(по значению; см. раздел 8.5.3), но результат ничему не присвоили; такая компиляция представляет собой простую трату времени. 21.5.2. Обобщение алгоритма accumulate
Итак, основной алгоритм
accumulate
с тремя аргументами выполняет суммирование. Однако существует много других полезных операций, например умножение и вычитание, которые можно выполнять над последовательностями, поэтому в библиотеке STL предусмотрена версия алгоритма accumulate
с четырьмя аргументами, позволяющая задавать используемую операцию.
template<class In, class T, class BinOp>
T accumulate(In first, In last, T init, BinOp op)
{
while (first!=last) {
init = op(init, *first);
++first;
}
return init;
}
Здесь можно использовать любую бинарную операцию, получающую два аргумента, тип которых совпадает с типом аккумулятора. Рассмотрим пример.
array<double,4> a = { 1.1, 2.2, 3.3, 4.4 }; // см. раздел 20.9