Введенное с помощью typedef имя self я использую в примере 11.17 и в последующих примерах; оно представляет собой удобное краткое имя, которое я использую для ссылки на тип текущего класса. Программу значительно легче писать и воспринимать при использовании self вместо имени класса.
11.10. Вычисление скалярного произведения
Имеется два контейнера, содержащих числа, причем они имеют одинаковую длину, и требуется вычислить их скалярное произведение.
Пример 11.19 показывает, как можно вычислить скалярное произведение, используя функцию inner_product из заголовочного файла <numeric>.
Пример 11.19. Расчет скалярного произведения
#include <numeric>
#include <iostream>
#include <vector>
using namespace std;
int main() {
int v1[] = { 1, 2, 3 };
int v2[] = { 4, 6, 8 };
cout << "the dot product of (1,2,3) and (4,6,8) is ";
cout << inner_product(v1, v1 + 3, v2, 0) << endl;
}
Программа примера 11.19 выдает следующий результат.
the dot product of (1,2,3) and (4,6,8) is 40
Скалярное произведение (dot product) является одной из форм обобщенного скалярного произведения (inner product), называемой евклидовым скалярным произведением (Euclidean Inner Product). Функция inner_product объявляется следующим образом.
template<class In, class In2, class T>
T inner_product(In first, In last, In2 first2, T init);
template<class In, class In2, class T, class BinOp, class BinOp2>
T inner_product(In first, In last, In2 first2, T init, BinOp op, BinOp2 op2);
Первый вариант функции inner_product суммирует произведения соответствующих элементов двух контейнеров. Второй вариант функции inner_product позволяет вам самому предоставить операцию над парой чисел и функцию суммирования. В примере 11.20 продемонстрирована простая реализация функции inner_product.
Пример 11.20. Пример реализации функции inner_product()
template<class In, class In2, class T, class BinOp, class BinOp2>
T inner_product(In first, In last, In2 first2, T init, BinOp op, Binop2 op2) {
while (first != last) {
BinOp(init, BinOp2(*first++, *first2++));
}
return init;
}
Благодаря гибкости реализации функции inner_product вы можете ее использовать для многих других целей, а не только для расчета скалярного произведения (например, ее можно использовать для вычисления расстояния между двумя векторами или для вычисления нормы вектора).
Рецепты 11.11 и 11.12.
11.11. Вычисление нормы вектора
Требуется найти норму (т. е. длину) числового вектора.
Можно использовать функцию inner_product из заголовочного файла <numeric> для умножения вектора на самого себя, как показано в примере 11.21.
Пример 11.21. Вычисление нормы вектора
#include <numeric>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
template<typename Iter_T>
long double vectorNorm(Iter_T first, Iter_T last) {
return sqrt(inner_product(first, last, first, 0.0L));
}
int main() {
int v[] = { 3, 4 };
cout << "The length of the vector (3.4) is ";
cout << vectorNorm(v, v + 2) << endl;
}
Программа примера 11.21 выдает следующий результат.
The length of the vector (3,4) is 5
В примере 11.21 функция inner_product из заголовочного файла <numeric> используется для вычисления скалярного произведения числового вектора на самого себя. Квадратный корень полученного значения, как известно, является нормой вектора, или длиной вектора.
Вместо того чтобы в функции vectorNorm выводить тип результата по аргументам, я решил для него использовать тип long double, чтобы терять как можно меньше данных. Если вектор представляет собой набор значений целого типа, маловероятно, что в реальных условиях норма вектора может быть адекватно представлена целым типом.
11.12. Вычисление расстояния между векторами
Требуется найти евклидово расстояние между векторами.
Евклидово расстояние между векторами определяется как квадратный корень суммы квадратов разностей соответствующих элементов. Рассчитать его можно так, как показано в примере 11.22.
Пример 11.22. Расчет расстояния между двумя векторами
#include <cmath>
#include <iostream>
using namespace std;
template<class Iter_T, class Iter2_T>
double vectorDistance(Iter_T first, Iter_T last, Iter2_T first2) {
double ret = 0.0;
while (first != last) {
double dist = (*first++) - (*first2++);
ret += dist * dist;
}
return ret > 0.0 ? sqrt(ret) : 0.0;
}
int main() {
int v1[] = { 1, 5 };
int v2[] = { 4, 9 };
cout << "distance between vectors (1,5) and (4,9) is ";
cout << vectorDistance(v1, v1 + 2, v2) << endl;
}
Программа примера 11.22 выдает следующий результат.
distance between vectors (1,5) and (4,9) is 5
Пример 11.22 реализует прямое решение, которое показывает, как следует писать простую обобщенную функцию в стиле STL. Для расчета расстояний между векторами я мог бы использовать функцию inner_product, однако я не стал использовать функтор, потому что это неоправданно усложнило бы решение. Пример 11.23 показывает, как можно рассчитывать расстояние между векторами, применяя функтор и функцию inner_product из заголовочного файла <numeric>.
Пример 11.23. Расчет расстояния между векторами с использованием функции inner_product