Pytanie w sprawie c++ – Obliczanie iloczynu skalarnego dwóch wektorów w C ++

13

Próbuję napisać program z funkcjądouble_product(vector<double> a, vector<double> b) który oblicza iloczyn skalarny dwóch wektorów. Produkt skalarny to

$a_{0}b_{0}+a_{1}b_{1}+...+a_{n-1}b_{n-1}$.

Oto co mam. To bałagan, ale próbuję!

#include <iostream>
#include <vector>

using namespace std;

class Scalar_product
{
    public:
    Scalar_product(vector<double> a, vector<double> b);
};
double scalar_product(vector<double> a, vector<double> b)
{
    double product = 0;
    for (int i = 0; i <= a.size()-1; i++)
        for (int i = 0; i <= b.size()-1; i++)
            product = product + (a[i])*(b[i]);
    return product;
}

int main() {
    cout << product << endl;
    return 0;
}
@ HowardRoark tylkozaakceptować proszę, a ja też cię poproszę. :) gsamaras
@ jakebird451 Szczerze mówiąc nie mam pojęcia, jak to zrobić. Ale to zwraca podwójną. HowardRoark
Pytanie nie jest zbyt jasne. Dostajemy to, że to twoja praca domowa. Ale jakie pytanie próbujesz rozwiązać i dodać trochę szczegółów na temat tego, z którym problemem masz do czynienia? Ankit
@ jakebird451 Chciałem „podwójnie” przepraszam. HowardRoark

Twoja odpowiedź

5   odpowiedzi
40

), powinieneś naprawdę użyć standardowego algorytmu, który został już napisany, aby zrobić dokładnie to, co chcesz:

#include <iostream>
#include <numeric>
#include <vector>

int main() {
    std::vector<double> a {1, 2, 3};
    std::vector<double> b {4, 5, 6};

    std::cout << "The scalar product is: "
              << std::inner_product(std::begin(a), std::end(a), std::begin(b), 0.0);
    return 0;
}

Zwróć uwagę na tobegin(a) iend(a) są nowe w C ++ 11,std::inner_product jest dostępny od C ++ 98. Jeśli używasz C ++ 98 (lub 03), łatwo jest napisać własny odpowiednikbegin iend do pracy z tablicami:

template <class T, size_t N>
T *begin(T (&array)[N]) {
    return array;
}

template <class T, size_t N>
T *end(T (&array)[N]) {
    return array + N;
}

Używając ich, wersja poprzedniego kodu C ++ 98 mogłaby wyglądać mniej więcej tak:

int main() {
    double a[] = {1, 2, 3};
    double b[] = {4, 5, 6};

    std::cout << "The scalar product is: "
              << std::inner_product(begin(a), end(a), begin(b), 0.0);
    return 0;
}

Zauważ, żebegin iend powyżej będzie działać tylko dla tablic, gdziebegin iend w C ++ 11 (i nowszych) będzie również działać dla normalnych typów kolekcji, które definiują.begin() i.end() (chociaż dodawanie przeciążeń jest bardzo trywialne, oczywiście):

template <class Coll>
typename Coll::iterator begin(Coll const& c) { return c.begin(); }

template <class Coll>
typename Coll::iterator end(Coll const& c) { return c.end(); }
12

class zdefiniowałeś. Nie potrzebujesz tego.

W Twoimscalar_product funkcjonować:

double scalar_product(vector<double> a, vector<double> b)
{
    double product = 0;
    for (int i = 0; i <= a.size()-1; i++)
        for (int i = 0; i <= b.size()-1; i++)
            product = product + (a[i])*(b[i]);
    return product;
}

Jest prawie tam. Nie potrzebujesz 2 pętli. Tylko jeden.

double scalar_product(vector<double> a, vector<double> b)
{
    if( a.size() != b.size() ) // error check
    {
        puts( "Error a's size not equal to b's size" ) ;
        return -1 ;  // not defined
    }

    // compute
    double product = 0;
    for (int i = 0; i <= a.size()-1; i++)
       product += (a[i])*(b[i]); // += means add to product
    return product;
}

Teraz dopołączenie ta funkcja, musisz utworzyć 2 obiekty wektorowe w swoimmain(), wypełnij je wartościami (oczywiście ta sama liczba wartości!), a następnie zadzwońscalar_product( first_vector_that_you_create, second_vector_object );

Cóż, o wiele bardziej niebezpieczne byłoby dodanie wartości, która może wystąpić w wyniku prawidłowego działania. Wtedy możesz nawet nie wiedzieć, że istnieje błąd, jednak dodanie liczby, która nie jest dozwolona, ​​może spowodować błąd lub wyjątek później, co pozwoli użytkownikowi wiedzieć, że coś jest nie tak. Jednak dodanie ASSERT jest prawdopodobnie lepsze, +1 patrik
Śledzenie NaN, które nie było wynikiem operacji podziału, spodziewam się być podwójnie trudne. bobobobo
Obsługa błędów w tej implementacji jest niebezpieczna. -1 nie oznacza niezdefiniowanego w produkcie skalarnym. Ten może się czasem bardzo dobrze pojawić. Jest tam wydrukowane ostrzeżenie, ale można to łatwo zignorować, zwłaszcza w przypadku dużych programów, w których tekst może być ukryty lub jeśli jest dużo drukowanego tekstu. Spróbuj zamiast tegonumeric_limits <double> :: quiet_NaN (); Które zwracają nan. patrik
Ja bymnigdy, zawsze, dobrowolnieprzedstaw NaN do mojego programu. NaN jest toksyczny (NaN * liczba = NaN, NaN + liczba = NaN), więc rozprzestrzenia się w całym programie i odkrywagdzie wyprodukowano NaN jest rzeczywiście trudne (chyba że twój debugger może natychmiast przerwać produkcję NaN). Powiedział, że tajemnicze -1 może nie być łatwe do śledzenia jako tajemnicze 0, więc mogę zmienić to -1 na 0. Jeśli nie monitorujesz regularnie tekstu wyjściowego swojego programu, prawdopodobnie też dodam ASSERT w ten stan. Alenigdy zwróć NaN. bobobobo
0

że chcesz stworzyć klasę specjalnie dla wektorów. Klasa I wykonana w moim przykładzie jest dostosowana do wektorów trójwymiarowych, ale w razie potrzeby można ją zmienić na inną. Klasa posiada i, j, k, ale może również prowadzić produkty skalarne oparte na innych wektorach MathVector. Drugi wektor jest przekazywany za pośrednictwem odwołania C ++. Trudno wywnioskować, o co chodziło, ale myślę, że to może na to odpowiedzieć.

#include <iostream>

using namespace std;

class MathVector
{
private:
    double i,j,k;
public:
    MathVector(double i,double j,double k)
    {
        this->i=i;
        this->j=j;
        this->k=k;
    }
    double getI(){return i;}
    double getJ(){return j;}
    double getK(){return k;}
    double scalar(MathVector &other)
    {
        return (i*other.getI())+(j*other.getJ())+(k*other.getK());
    }
};

int main(int argc, char **argv)
{
    MathVector a(1,2,5), b(2,4,1);

    cout << a.scalar(b) << endl;

    return 0;
}
3

które działają, pozwólcie mi rozwinąć kolejną odmianę, aby wprowadzić kilka koncepcji, które powinny pomóc w napisaniu lepszego kodu:

class są potrzebne tylko do spakowania danychfunkcja powinna jak najszybciej sprawdzić swoje warunki wstępne, należy je udokumentowaćfunkcja powinna mieć warunki końcowe, powinny być udokumentowaneponowne wykorzystanie kodu jest podstawą programów, które można konserwować

Pamiętając o tym:

// Takes two vectors of the same size and computes their scalar product
// Returns a positive value
double scalar_product(std::vector<double> const& a, std::vector<double> const& b)
{
    if (a.size() != b.size()) { throw std::runtime_error("different sizes"); }

    return std::inner_product(a.begin(), a.end(), b.begin(), 0.0);
} // scalar_product

Możesz zdecydować się na użycieinner_product algorytm bezpośrednio, ale spójrzmy prawdzie w oczy:

wymaga czterech argumentów, nie dwóchnie sprawdza, czy jego argumenty są tego samego rozmiaru

więc lepiej go owinąć.

Uwaga: użyłemconst& wskazać kompilatorowi, aby nie kopiował wektorów.

1

który powinieneś mieć. Widzę, że użyłeś klasy w swoim kodzie, którego tak naprawdę nie potrzebujesz tutaj. Daj mi znać, jeśli pytanie wymagało użycia klasy.

Jak jesteś nowy i ten kod może cię przestraszyć. Więc postaram się to wyjaśnić, kiedy pójdę. Poszukaj komentarzy w kodzie, aby zrozumieć, co się robi i zapytać, czy nie rozumiesz.

//Scalar.cpp
#include <stdlib.h>
#include <iostream>
#include <vector>

using namespace std;

/**
This function returns the scalar product of two vectors "a" and "b"
*/
double scalar_product(vector<double> a, vector<double> b)
{
    //In C++, you should declare every variable before you use it. So, you declare product and initialize it to 0.
    double product = 0;
    //Here you check whether the two vectors are of equal size. If they are not then the vectors cannot be multiplied for scalar product.
    if(a.size()!=b.size()){
        cout << "Vectors are not of the same size and hence the scalar product ,cannot be calculated" << endl;
        return -1;  //Note: This -1 is not the answer, but just a number indicating that the product is not possible. Some pair of vectors might actually have a -1, but in that case you will not see the error above.
    }

    //you loop through the vectors. As bobo also pointed you do not need two loops.
    for (int i = 0; i < a.size(); i++)
    {
        product = product + a[i]*b[i];
    }

    //finally you return the product
    return product;
}


 //This is your main function that will be executed before anything else.
int main() {
    //you declare two vectors "veca" and "vecb" of length 2 each
    vector<double> veca(2);
    vector<double> vecb(2);

    //put some random values into the vectors
    veca[0] = 1.5;
    veca[1] = .7;
    vecb[0] = 1.0;
    vecb[1] = .7;

    //This is important! You called the function you just defined above with the two parameters as "veca" and "vecb". I hope this cout is simple!
    cout << scalar_product(veca,vecb) << endl;
}

Jeśli używasz IDE, po prostu skompiluj i uruchom. Jeśli używasz linii poleceń w systemie uniksowym z kompilatorem g ++, to właśnie zrobisz (gdzie Scalar.cpp jest plikiem zawierającym kod):

g++ Scalar.cpp -o scalar

Aby go uruchomić, po prostu wpisz

./scalar

Powinieneś wziąć1.99 jako wynik powyższego programu.

Powiązane pytania