На некоторых компьютерах переменная типа long
состоит из гораздо большего количества цифр, чем переменная типа int
. Переменная типа double
может представить большие (и меньшие) числа, чем переменная типа int
, но, возможно, с меньшей точностью. В главе 24 мы еще вернемся к вопросу о диапазоне и точности в вычислениях.
init
в качестве аккумулятора представляет собой весьма распространенную идиому, позволяющую задать тип аккумулятора.
void f(vector
{
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
T accumulate(In first, In last, T init, BinOp op)
{
while (first!=last) {
init = op(init, *first);
++first;
}
return init;
}
Здесь можно использовать любую бинарную операцию, получающую два аргумента, тип которых совпадает с типом аккумулятора. Рассмотрим пример.
array
cout << accumulate(a.begin(),a.end(), 1.0, multiplies
Этот фрагмент кода выводит на печать число 35.1384, т.е. 1.0*1.1*2.2*3.3*4.4 (1.0 — начальное значение). Бинарный оператор multiplies
, передаваемый как аргумент, представляет собой стандартный объект-функцию, выполняющий умножение; объект-функция multiplies
перемножает числа типа double
, объект-функция multiplies
перемножает числа типа int
и т.д. Существуют и другие бинарные объекты-функции: plus
(сложение), minus
(вычитание), divides
и modulus
(вычисление остатка от деления). Все они определены в заголовке
(раздел Б.6.2).
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
{
double total = accumulate(vr.begin(),vr.end(),0.0,price);
// ...
}
Мы поленились и использовали для вычисления цены функцию, а не объект-функцию, просто, чтобы показать, что так тоже можно делать. И все же мы рекомендуем использовать объекты функции в следующих ситуациях.
• Если между вызовами необходимо сохранять данные.
• Если они настолько короткие, что их можно объявлять подставляемыми (по крайней мере, для некоторых примитивных операций).
В данном случае мы могли бы использовать объект-функцию, руководствуясь вторым пунктом этого списка.
ПОПРОБУЙТЕ
Определите класс vector
, проинициализируйте его четырьмя записями по своему выбору и вычислите общую стоимость, используя приведенные выше функции.
21.5.3. Алгоритм inner_product