2010-07-30 8 views
21

La pregunta es bastante tonta, pero tengo que hacerlo de una manera muy eficiente: se repetirá una vez más en mi código. Tengo una función que devuelve un vector, y tengo que agregar los valores devueltos a otro vector, elemento por elemento. Muy sencillo:¿Cómo agregar elemento por elemento de dos vectores STL?

vector<double> result; 
vector<double> result_temp 
for(int i=0; i< 10; i++) result_temp.push_back(i); 

result += result_temp //I would like to do something like that. 
for(int i =0; i< result_temp.size();i++)result[i] += result_temp[i]; //this give me segfault 

La operación matemática que estoy tratando de hacer es

u [i] = u [i] + V [i] para todos los i

¿Qué se puede hacer ?

Gracias

Editar: añaden una inicialización simple, ya que no es el punto. ¿Cómo debe inicializarse el resultado?

+5

¿Le publicar algo de código compilables? "Esto me da un segfault" no es particularmente útil sin ver cómo esos vectores se inicializan. El problema más probable es que uno de los vectores sea más largo que el otro. Es realmente difícil saber dónde está el código incorrecto sin ver todo el código :-) –

+0

http://www.boost.org/doc/libs/1_43_0/libs/numeric/ublas/doc/operations_overview.htm – Anycorn

Respuesta

28

Si está intentando agregar un vector a otro, puede usar algo como lo siguiente. Estos son de uno de mis bibliotecas de servicios públicos - dos operator+= sobrecargas para std::vector: uno añade un elemento a la vector, la otra anexa toda una vector:

template <typename T> 
std::vector<T>& operator+=(std::vector<T>& a, const std::vector<T>& b) 
{ 
    a.insert(a.end(), b.begin(), b.end()); 
    return a; 
} 

template <typename T> 
std::vector<T>& operator+=(std::vector<T>& aVector, const T& aObject) 
{ 
    aVector.push_back(aObject); 
    return aVector; 
} 

Si usted está tratando de realizar una suma (es decir , crear un nuevo vector que contiene las sumas de los elementos de dos otros vector s), se puede usar algo como lo siguiente:

#include <algorithm> 
#include <functional> 

template <typename T> 
std::vector<T> operator+(const std::vector<T>& a, const std::vector<T>& b) 
{ 
    assert(a.size() == b.size()); 

    std::vector<T> result; 
    result.reserve(a.size()); 

    std::transform(a.begin(), a.end(), b.begin(), 
        std::back_inserter(result), std::plus<T>()); 
    return result; 
} 

podría implementar de manera similar una sobrecarga operator+=.

+0

Gracias, pero no estoy tratando de añadir un valor al final del vector, estoy tratando de sumar el valor existente de los elementos del vector con los valores de otro vector. El tamaño de los vectores siempre es fijo. – Ivan

+2

@Ivan: ver la edición; No estaba del todo seguro de lo que estabas buscando hasta que vi tu comentario en respuesta a la respuesta de Greg. –

+2

@James Ignora mi comentario original - ahora tienes código relevante Y relevante :) –

0

Estoy con @James McNellis - este código parece correcto, siempre y cuando result y result_temp tengan la misma longitud.

Además, ¿por qué declaraste result, pero usa la variable result_v? ¿Es así como se escribe realmente el código? Si es así, es un problema

1

Primero debe inicializar result a todos los ceros; acaba de declarar que la variable en realidad no asigna ningún elemento.

Prueba esto:

vector<double> result(10); // default-initialize to 10 elements 
vector<double> result_temp; 
for(int i=0; i< 10; i++) 
    result_temp.push_back(i); 

for(int i =0; i< result_temp.size();i++) 
    result[i] += result_temp[i]; 
0

El código parece estar bien, pero mi primera inclinación sería alterar cualquier código que se está llenando el vector con los valores a añadir a los valores en el primer vector de tomar en una referencia a el primer vector y añádalo directamente en lugar de crear un nuevo vector que se devuelva. Eso es solo ineficiente.

Si no puede modificar la función de esa manera, quizás pueda modificarla de modo que haga referencia a un vector que borre y luego inserte los valores para que no esté copiando vectores. Eso puede llegar a ser costoso si lo haces mucho.

Otro nitpick Si está tratando de obtener esto lo más rápido posible, debe usar preincremento con iteradores en lugar de post-incremento. El temporal que crea el incremento posterior no se puede optimizar cuando se trata de operadores sobrecargados en lugar de tipos incorporados. Entonces, sigues creando y destruyendo una iteración temporal de tu ciclo.EDITAR: Como se señaló en los comentarios, usted está usando índices aquí en lugar de iteradores (obviamente no estaba prestando suficiente atención), por lo que este consejo no se aplica aquí. Sin embargo, en los casos en que son utilizando iteradores, sigue siendo válido.

Aparte de eso, si está tratando de agregar todos los elementos de dos vectores juntos, lo que tiene es probablemente una solución tan eficiente como la que va a obtener. Hay mejores formas si lo que le preocupa es insertar los elementos de un vector en otro, pero si solo está agregando sus valores, lo que tiene se ve bien. Yo esperaría que el uso de cualquier algoritmo STL sea tan rápido como sea posible y probablemente más lento debido a las llamadas a funciones adicionales, pero probablemente tendrías que perfilarlo para estar seguro.

+1

"debe usar el preincremento con iteradores en lugar de un incremento posterior". Es cierto, pero él no está utilizando iteradores, está usando un índice entero. Es difícil hacer un caso de rendimiento entre el incremento previo y posterior para eso ;-) –

+0

Ah, buena captura. No estaba prestando suficiente atención. Raramente utilicé índices en lugar de iteradores y mi reacción visceral al incremento posterior es muy negativa. Creo firmemente en usar siempre el incremento previo a menos que necesite un incremento posterior. De esta forma, nunca tendrá que preocuparse de si el temporal se optimizará o no. Sin embargo, es cierto en este caso que el compilador no debería tener problemas para optimizarlo y que el incremento posterior sería tan eficiente como el preincremento. –

+0

Sí, incluso aparte de posibles problemas de rendimiento, prefiero el preincremento también, pero por la controvertida razón de que creo que es más claro y legible. "Incremento i" se deletrea, "++ i". Pocos están de acuerdo. –

25

Parece que el problema está accediendo a valores de result que no existen. tzaman muestra cómo inicializar resultado de 10 elementos, cada uno con valor 0.

Ahora tiene que llamar a la función transform (de <algoritmo>), aplicando el objeto plus función (de <funcional>):

std::transform(result.begin(), result.end(), result_temp.begin(), 
       result.begin(), std::plus<double>()); 

Esto itera sobre result y result_temp, aplica plus que agrega dobles, y escribe la suma de nuevo en result.

0

Si su código está segfaulting, entonces ese es un problema de corrección, no un problema de eficiencia.

para lograr la "T [i] = u [i] + V [i] para todos los i", me gustaría hacer básicamente lo que hizo:

assert(u.size() == v.size()); // will fail with your initialization code, since 
           // your "result" has size 0, not size 10. 
           // perhaps do u.resize(v.size()); 
for (size_t i = 0; i < u.size(); ++i) { 
    u[i] += v[i]; 
} 

Si realmente se preocupan por el rendimiento de su programa (es decir, ha escrito una versión básica y es tan lenta que su programa no cumple con ciertos requisitos, y ha demostrado que este es el código donde se emplea la mayor parte del tiempo), puede intentar:

  • activando muchas optimizaciones en su compilador (en realidad, generalmente lo hago de manera predeterminada incluso cuando no hay un problema de rendimiento),
  • utilizando iteradores en lugar de índices (rara vez hace mucha diferencia, pero es bastante fácil comparar los dos),
  • desenrollando el ciclo un poco (puede hacer una diferencia de velocidad que valga la pena, pero eso es bastante sensible al caso particular, fomenta los errores de codificación).
  • buscando instrucciones SIMD específicas de la plataforma en lugar de C++. A continuación, utilice ensamblador integrado o intrínseco del compilador para esas instrucciones.

Sin embargo, no tiene que preocuparse por el rendimiento antes de que su código sea correcto ;-). "Hacer que funcione, que sea justo, que sea rápido" es un lema razonable, aunque a menudo no es necesario ir tan lejos como el paso 3.

std::valarray en realidad tiene exactamente el operator+= desea. Antes de reemplazar todos sus vectores con valarrays, tenga en cuenta que esto no significa necesariamente que sea "más eficiente" que un simple bucle. No sé cuán seriamente los implementadores toman valarray. Siempre puedes mirar la fuente en tu implementación.Tampoco sé por qué la funcionalidad aritmética de datos múltiples de valarray no se definió como parte de vector, pero generalmente hay una razón.

+0

Como el lema. – Vincent

6

Un ejemplo concreto de la respuesta de Jon Reid:

std::array<double,3> a = {1, 2, 3}; 
std::array<double,3> b = {4, 5, 6}; 
std::transform(a.begin(), a.end(), b.begin(), a.begin(),std::plus<double>()); 
ASSERT_TRUE(a[0] == 5); 
ASSERT_TRUE(a[1] == 7); 
ASSERT_TRUE(a[2] == 9); 
Cuestiones relacionadas