Литмир - Электронная Библиотека
A
A

}

Тип результата (суммы) совпадает с типом переменной, которую алгоритм

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 мы еще вернемся к вопросу о диапазоне и точности в вычислениях.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Использование переменной
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);         // Ой

}

 

Программирование. Принципы и практика использования C++ Исправленное издание - _003.png
 Не забудьте инициализировать аккумулятор и присвоить результат работы алгоритма
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

cout << accumulate(a.begin(),a.end(), 1.0, multiplies<double>());

Этот фрагмент кода выводит на печать число 35.1384, т.е. 1.0*1.1*2.2*3.3*4.4 (1.0 — начальное значение). Бинарный оператор

multiplies<double>()
, передаваемый как аргумент, представляет собой стандартный объект-функцию, выполняющий умножение; объект-функция
multiplies<double>
перемножает числа типа
double
, объект-функция
multiplies<int>
перемножает числа типа
int
и т.д. Существуют и другие бинарные объекты-функции:
plus
(сложение),
minus
(вычитание),
divides
и
modulus
(вычисление остатка от деления). Все они определены в заголовке
<functional>
(раздел Б.6.2).

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Обратите внимание на то, что для умножения чисел с плавающей точкой естественным начальным значением является число
1.0
. Как и в примере с алгоритмом
sort()
(см. раздел 21.4.2), нас часто интересуют данные, хранящиеся в объектах классов, а не обычные данные встроенных типов. Например, мы могли бы вычислить общую стоимость товаров, зная стоимость их единицы и общее количество.

struct Record {

  double unit_price;

  int units;   // количество проданных единиц

  // ...

};

Мы можем поручить какому-то оператору в определении алгоритма

accumulate
извлекать данные units из соответствующего элемента класса
Record
и умножать на значение аккумулятора.

double price(double v,const Record& r)

{

  return v + r.unit_price * r.units; // вычисляет цену

                                     // и накапливает итог

}

void f(const vector<Record>& vr)

{

  double total = accumulate(vr.begin(),vr.end(),0.0,price);

  // ...

291
{"b":"847443","o":1}