Szablon inner_product
oblicza iloczyn skalarny1) dwóch kolekcji. Działanie iloczynu skalarnego może być stanardowe lub zdefiniowane przez użytkownika.
Biblioteka stl
dostarcza przeciążonej deklaracji inner_product
w dwóch wariantach.
#include <numeric> //lokalizacja inner_porduct template <class InputIterator1, class InputIterator2, class T> T inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init); // wariant pierwszy template <class InputIterator1, class InputIterator2, class T, class BinaryFunction1,class BinaryFunction2> T inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, BinaryFunction1 binary_op1, BinaryFunction2 binary_op2); // wariant drugi
Prostsza z deklaracji inner_product
udostępnia inerfejs do obliczenia zwykłego iloczynu skalarnego, znanego z geometrii euklidesowej.
Funkcja inicjalizuje akumulator a = init, po czym oblicza kolejno w podanych zakresach: a = a + (*it1) ⋅ (*it2)
gdzie it1 ∈ [first1, last1) , it2 ∈ [first2, first2 + last1-first1).
Jeśli zakresy kolekcji nie są równe, do obliczeń brany jest krótszy zakres. Zwracany jest oczywiście wynik działania.
Funckja inner_product
ma złożoność liniową.
Prosty przykład użycia inner_product
, czyli iloczyn skalarny wektorów:
vector<int> v1; vector<int> v2; v1.push_back(1); v1.push_back(2); // v1 = [ 1, 2 ] v2.push_back(2); v2.push_back(3); // v2 = [ 2, 3 ] //inner <= (1 + 1*2 )+ 2*3 = 9 int inner = inner_product(v1.begin(), v1.end(), v2.begin(), 1); // nie jest to "prawdziwy" iloczyn skalarny, bo inicjalizujemy wartością 1 printVector(cout, v2); cout<<"Iloczyn skalarny = "<<inner<<endl; // Iloczyn skalarny = 9
Druga z deklaracji inner_product
jest poszerzona o dwa parametry:
Funkcja inicjalizuje akumulator a = init, po czym oblicza a = binary_op1( a , binary_op2( (*it1) ,(*it2) ) ) dla podanego zekresu kolekcji. Zakresy iteratorów są takie same jak w pierwszym przypadku.
binary_op1 i binary_op2 muszą być funkcjami lub obiektami funkcyjnymi.
Aby wykorzystać inner_product
do obliczania własnego iloczynu skalarnego należy zdefiniować własne operacje binary_op1 i binary_op2. Najłatwiej to zrobić posługując się szablonem binary_operation. W przykładzie w pliku inner_product.cpp zdefiniowana jest funkcja multiplies_conj
, która mnoży liczbę zespoloną complex przez liczbę sprzężoną z drugą liczbą.
#include <functional> // szablon binary_function template<class _Tp> struct multiplies_conj: public binary_function<_Tp, _Tp, _Tp> {// oblicza specyficzne mnożenie dla liczb zespolonych _Tp operator()(const _Tp& __x, const _Tp& __y) const { // obiekt funkcyjny - przeciążony operator () return __x * conj(__y); // własne działanie - tutaj conj - zwraca liczbę sprzężoną do __y } };
Wykorzystując operację multiplies_conj
oraz operację plus
(również pochodną binary_function) łatwo jest już zdefiniować iloczyn skalarny dla wektorów liczb zespolonych:
#include <complex> // liczby zespolone complex typedef complex<int> ComplexInt; vector<ComplexInt> c1; vector<ComplexInt> c2; c1.push_back(ComplexInt(1, 0)); c1.push_back(ComplexInt(3, 2)); // c1 = [ 1, 3 + 2j] c2.push_back(ComplexInt(4, 5)); c2.push_back(ComplexInt(3, -1)); // c2 = [ 4 + 5j, 3 -j] const ComplexInt complexZero(0, 0); // complex <= 0 + ( 1*(4-5j) + ( (3+2j)*(3+j) ) ) = 4 + 9 - 2 - 5j + 3j + 6j = 11 +4j ComplexInt complexInner = inner_product(c1.begin(), c1.end(), c2.begin(), complexZero, plus<ComplexInt>(), multiplies_conj<ComplexInt>()); //zamiast zwykłego mnożenia - mnożenie przez liczbę sprzężoną cout<<"Iloczyn skalarny = "<<complexInner<<endl; //Iloczyn skalarny = (11,4)
Możliwych zastosowań inner_product
można wymyśleć tyle, ile jest różnych przestrzeni z działaniem iloczynu skalarnego. Wiele problemów, niekoniecznie matematycznych, można wyrazić w postaci obliczania iloczynu skalarnego. Łatwo na przykład zastosować ten sposób obliczeń do porównywania ciągów znaków, do obliczania dopasowania do wzorca. Operacja iloczynu skalarnego jest dość prosta i szybka, dlatego warto z niej skorzystać w swoich projektach.
Fragmenty kodu użyte w artykule znajdują się w pliku inner_product.cpp. Tam też można znaleźć przykład, jak policzyć kąt pomiędzy wektorami przy pomocy funkcji inner_product
.