На некоторых компьютерах переменная типа long состоит из гораздо большего количества цифр, чем переменная типа int. Переменная типа double может представить большие (и меньшие) числа, чем переменная типа int, но, возможно, с меньшей точностью. В главе 24 мы еще вернемся к вопросу о диапазоне и точности в вычислениях.

  Использование переменной init в качестве аккумулятора представляет собой весьма распространенную идиому, позволяющую задать тип аккумулятора.

void f(vector& 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), но результат ничему не присвоили; такая компиляция представляет собой простую трату времени.

<p id="AutBody_Root399"><strong>21.5.2. Обобщение алгоритма accumulate()</strong></p>

Итак, основной алгоритм 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 a = { 1.1, 2.2, 3.3, 4.4 };   // см. раздел 20.9

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& vr)

{

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

  // ...

}

Мы поленились и использовали для вычисления цены функцию, а не объект-функцию, просто, чтобы показать, что так тоже можно делать. И все же мы рекомендуем использовать объекты функции в следующих ситуациях.

• Если между вызовами необходимо сохранять данные.

• Если они настолько короткие, что их можно объявлять подставляемыми (по крайней мере, для некоторых примитивных операций).

В данном случае мы могли бы использовать объект-функцию, руководствуясь вторым пунктом этого списка.

ПОПРОБУЙТЕ

Определите класс vector, проинициализируйте его четырьмя записями по своему выбору и вычислите общую стоимость, используя приведенные выше функции.

<p id="AutBody_Root400"><strong>21.5.3. Алгоритм inner_product</strong></p>
Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже