Pregunta sobre c++ – Cálculo del producto escalar de dos vectores en C ++

13

Estoy tratando de escribir un programa con una funcióndouble_product(vector<double> a, vector<double> b) que calcula el producto escalar de dos vectores. El producto escalar es

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

Esto es lo que tengo. Es un desastre, pero lo estoy intentando!

#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 sí, no compilará. Veo demasiados errores allí. Publicaré el código corregido pronto. No te preocupes :) Ankit
@Ankit cuando lo ejecuto, no se compila. Mi código está todo desordenado. :( HowardRoark
@HowardRoark Tengo la pregunta ahora. ¿Qué pasa cuando lo ejecutas? ¿Está enfrentando algún error o está recibiendo la respuesta incorrecta para algún caso de muestra? Ankit
¡Quiero hablar con todos ustedes por ayudarme! ¡Ustedes son geniales! HowardRoark

Tu respuesta

5   la respuesta
40

escribirlo es tarea), debería usar el algoritmo estándar que ya está escrito para hacer exactamente lo que quiere:

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

Tenga en cuenta que mientrasbegin(a) yend(a) son nuevos en C ++ 11,std::inner_product ha estado disponible desde C ++ 98. Si está utilizando C ++ 98 (o 03), es bastante fácil escribir su propio equivalente debegin yend para trabajar con matrices sin embargo:

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

Usando estos, una versión de C ++ 98 del código anterior podría verse así:

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

Tenga en cuenta que elbegin yend Lo anterior solo funcionará para matrices, donde elbegin yend en C ++ 11 (y posterior) también funcionará para los tipos de recopilación normales que definen un.begin() y.end() (aunque es trivial agregar sobrecargas para manejarlas también, por supuesto):

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(); }
1

código, que realmente no necesita aquí. Déjame saber si la pregunta requiere que uses la clase.

Como eres nuevo y este código podría asustarte. Por lo tanto, voy a tratar de explicar esto a medida que avanzo. Busque los comentarios en el código para entender lo que se está haciendo y pregunte si no entiende.

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

Si está utilizando un IDE, simplemente compile y ejecute. Si está utilizando la línea de comandos en un sistema basado en Unix con el compilador g ++, esto es lo que hará (donde Scalar.cpp es el archivo que contiene el código):

g++ Scalar.cpp -o scalar

Para ejecutarlo simplemente escribe

./scalar

Usted debe obtener1.99 como la salida del programa anterior.

3

permítame hacer una nueva variación para presentar un par de conceptos que le ayudarán a escribir mejor código:

class Solo son necesarios para empaquetar datos juntos.una función debe verificar sus condiciones lo más pronto posible, estas deben documentarseUna función debe tener postcondiciones, esas deben ser documentadas.La reutilización de código es la piedra angular de los programas mantenibles.

Con eso en mente:

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

Podrías decidir usar elinner_product algoritmo directamente pero seamos sinceros:

requiere cuatro argumentos, no dosNo comprueba que sus argumentos sean del mismo tamaño.

así que es mejor envolverlo.

Nota: yo utilicéconst& Indicar al compilador que no copie los vectores.

12

class usted ha definido No lo necesitas.

En tusscalar_product función:

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

Ya casi está ahí. No necesitas 2 bucles. Solo uno.

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

Ahora allamada Esta función, necesita crear 2 objetos vectoriales en sumain(), llénelos con valores, (¡el mismo número de valores, por supuesto!) y luego llamescalar_product( first_vector_that_you_create, second_vector_object );

Rastrear un NaN que no fue el resultado de una operación de división, espero que sea doblemente difícil. bobobobo
me gustaríaNuncasiempre jamás voluntariamenteintroducir NaN en mi programa NaN es tóxico (número NaN * = NaN, número NaN + = NaN), por lo que se propaga a lo largo de su programa y se da cuentadónde el NaN que se produjo es realmente difícil (a menos que su depurador pueda interrumpir inmediatamente la producción de NaN). Dicho esto, un -1 misterioso podría no ser fácil de rastrear como un 0 misterioso, así que podría cambiar ese -1 a un 0. Si no monitoreas la salida de texto de tu programa con regularidad, probablemente también agregaré un ASSERT en esa condicion PeroNunca devuelve NaN. bobobobo
Bueno, sería mucho más peligroso agregar un valor que pueda ocurrir por una operación correcta. Entonces es posible que ni siquiera sepa que hay un error allí; sin embargo, al agregar un número que no está permitido como nan, puede causar un error o una excepción más adelante, lo que permite al usuario saber que algo está mal. Sin embargo, agregar un ASSERT es probablemente mejor, +1 patrik
El manejo de errores en esta implementación es peligroso. -1 no significa indefinido en el producto escalar. Ese uno puede muy bien aparecer a veces. Hay una advertencia impresa por ahí, pero esto puede ser fácilmente ignorado, especialmente para programas grandes donde el texto puede estar oculto, o si hay una gran cantidad de texto impreso. Intenta en su lugarnumeric_limits <double> :: quiet_NaN (); Que vuelven nan. patrik
0

lase que hice en mi ejemplo está adaptada a vectores tridimensionales, pero puede cambiarla a otra si lo desea. La clase tiene i, j, k pero también puede realizar productos escalares basados ​​en otros MathVectors. El otro vector se pasa a través de una referencia de C ++. Es difícil deducir cuál era la pregunta, pero creo que esto podría responderla.

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

Preguntas relacionadas