18

I am trying to write a program with a function double_product(vector<double> a, vector<double> b) that computes the scalar product of two vectors. The scalar product is

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

Here is what I have. It is a mess, but I am trying!

#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
  • 281
  • 1
  • 2
  • 6
  • 1
    Is there actually a question here? – Michael Anderson Jun 06 '12 at 04:07
  • You question is not very clear. We get it that its your homework. But what question are you are trying to solve and add a little detail about what problem you are facing? – Ankit Jun 06 '12 at 04:08
  • @jakebird451 I meant "double" sorry. – HowardRoark Jun 06 '12 at 04:09
  • You are trying to construct a class for a scalar product? Shouldn't this be a function or a method of a custom mathematical vector class? Your constructor should not return an double. – jakebird451 Jun 06 '12 at 04:11
  • @Ankit The exact question is: Write a function double scalar_product(vector < double > a, vector< double > b) that computes the scalar product of two vectors. The scalar product is a_(0)b_(0)+a_(1)b_(1)+...+a_(n-1)b_(n-1). – HowardRoark Jun 06 '12 at 04:12
  • @jakebird451 I honestly have no idea how to do this. But it does return a double. – HowardRoark Jun 06 '12 at 04:14
  • @HowardRoark I got the question now. What happens when you run it? Are you facing some error or you are getting the wrong answer for some sample case? – Ankit Jun 06 '12 at 04:16
  • @Ankit when I run it, it doesn't compile. My code is all messed up. :( – HowardRoark Jun 06 '12 at 04:18
  • Also, you have not called the functions you defined. Also, I do not see the variable `product` defined. Have you just started learning C++? or the code is some abridged version of the original code you had. – Ankit Jun 06 '12 at 04:19
  • @HowardRoark yes it won't compile. I see too many errors there. I will post the corrected code soon. Don't worry :) – Ankit Jun 06 '12 at 04:20
  • @Ankit Yes I am new to C++, but I am trying. I just started learning it. This is nothing like math. haha. THANK YOU! I would really appreciate it! – HowardRoark Jun 06 '12 at 04:22
  • I want to talk all of you for helping me! You guys are great! – HowardRoark Jun 07 '12 at 08:53
  • @HowardRoark just **accept** please, and then I will upvote you as well. :) – gsamaras Nov 20 '16 at 21:50

5 Answers5

46

Unless you need to do this on your own (e.g., writing it is homework), you should really use the standard algorithm that's already written to do exactly what you want:

#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;
}

Note that while begin(a) and end(a) are new in C++11, std::inner_product has been available since C++98. If you are using C++ 98 (or 03), it's pretty easy to write your own equivalent of begin and end to work with arrays though:

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;
}

Using these, a C++ 98 version of the previous code could look something like this:

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;
}

Note that the begin and end above will only work for arrays, where the begin and end in C++11 (and later) will also work for normal collection types that define a .begin() and .end() (though it's trivial to add overloads to handle those as well, of course):

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(); }
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
12

You can delete the class you have defined. You don't need it.

In your scalar_product function:

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;
}

It's almost there. You don't need 2 loops. Just one.

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;
}

Now to call this function, you need to create 2 vector objects in your main(), fill them with values, (the same number of values of course!) and then call scalar_product( first_vector_that_you_create, second_vector_object );

bobobobo
  • 64,917
  • 62
  • 258
  • 363
  • 1
    The error handling in this implementation is dangerous. -1 does not stand for undefined in the scalar product. That one may very well appear sometimes. There is a warning printed out there, but this can easily be disregarded, especially for large programs where text the text output may be hidden, or if there are a lot of printed text. Try instead *numeric_limits::quiet_NaN();* Which return nan. – patrik Jan 30 '14 at 18:01
  • 1
    I would _never_, ever, ever, voluntarily [introduce NaN](http://stackoverflow.com/a/18283170/111307) into my program. NaN is toxic (NaN*number=NaN, NaN+number=NaN), so it propagates throughout your program, and figuring out _where_ the NaN was produced is actually hard (unless your debugger can break immediately on NaN production). That said, a mysterious -1 might not easy to track as a mysterious 0, so I might change that -1 to a 0. If you don't monitor the text output of your program regularly, I'd probably also add an ASSERT into that condition. But __never__ return NaN. – bobobobo Feb 18 '14 at 10:34
  • Tracking a NaN that was not the result of a division operation I would expect to be doubly hard. – bobobobo Feb 18 '14 at 10:35
  • 2
    Well, it would be much more dangerous to add a value that may occur by a correct operation. Then you may not even know there is an error there, however, by adding a number that is not allowed like nan, may cause an error or exception later, which let the user know something is wrong. However, adding an ASSERT is probably better, +1 – patrik Feb 18 '14 at 11:22
3

While you have been presented many solutions that work, let me spin up another variation to introduce a couple of concepts that should help you writing better code:

  • class are only needed to pack data together
  • a function should check its preconditions as soon as possible, those should be documented
  • a function should have postconditions, those should be documented
  • code reuse is the cornerstone of maintenable programs

With that in mind:

// 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

You could decide to use the inner_product algorithm directly but let's face it:

  • it requires four arguments, not two
  • it does not check for its arguments being of the same size

so it's better to wrap it.

Note: I used const& to indicate to the compiler not to copy the vectors.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
0

You seem to want to make a class specifically for vectors. The class I made in my example is tailored to 3 dimensional vectors, but you can change it to another if desired. The class holds i,j,k but also can conduct a scalar products based on other MathVectors. The other vector is passed in via a C++ reference. It is hard to deduce what the question was, but I think this might answer it.

#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;
}
jakebird451
  • 2,288
  • 4
  • 30
  • 45
0

Here is the code that you should have. I see you have used class in your code, which you do not really need here. Let me know if the question required you to use class.

As you are new and this code might scare you. So, I will try to explain this as I go. Look for comments in the code to understand what is being done and ask if you do not understand.

//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;
}

If you are using an IDE then just compile and run. If you are using command-line on a Unix-based system with g++ compiler, this is what you will do (where Scalar.cpp is the file containing code):

g++ Scalar.cpp -o scalar

To run it simply type

./scalar

You should get 1.99 as the output of the above program.

Ankit
  • 6,772
  • 11
  • 48
  • 84