Me gustan mucho los vectores. Son ingeniosos y rápidos. Pero sé que existe esta cosa llamada valarray. ¿Por qué usaría un valarray en lugar de un vector? Sé que los valarrays tienen algo de azúcar sintáctica, pero aparte de eso, ¿cuándo son útiles?
159
valarray
aquí y para aquíRespuestas:
Los Valarrays (matrices de valores) están destinados a llevar algo de la velocidad de Fortran a C ++. No haría una gran variedad de punteros para que el compilador pueda hacer suposiciones sobre el código y optimizarlo mejor. (La razón principal por la que Fortran es tan rápido es que no hay ningún tipo de puntero, por lo que no puede haber alias de puntero).
Los Valarrays también tienen clases que le permiten dividirlos de una manera razonablemente fácil, aunque esa parte del estándar podría necesitar un poco más de trabajo. Cambiar su tamaño es destructivo y carecen de iteradores.
Entonces, si se trata de números con los que está trabajando y la conveniencia no es tan importante, use valarrays. De lo contrario, los vectores son mucho más convenientes.
fuente
valarray
es una especie de huérfano que nació en el lugar equivocado en el momento equivocado. Es un intento de optimización, bastante específico para las máquinas que se utilizaron para las matemáticas pesadas cuando se escribió, específicamente, los procesadores vectoriales como los Crays.Para un procesador vectorial, lo que generalmente quería hacer era aplicar una sola operación a una matriz completa, luego aplicar la siguiente operación a toda la matriz, y así sucesivamente hasta que haya hecho todo lo que tenía que hacer.
Sin embargo, a menos que se trate de matrices bastante pequeñas, eso tiende a funcionar mal con el almacenamiento en caché. En la mayoría de las máquinas modernas, lo que generalmente preferiría (en la medida de lo posible) sería cargar parte de la matriz, realizar todas las operaciones que vaya a realizar y luego pasar a la siguiente parte de la matriz.
valarray
también se supone que elimina cualquier posibilidad de alias, lo que (al menos en teoría) permite que el compilador mejore la velocidad porque es más libre de almacenar valores en los registros. En realidad, sin embargo, no estoy del todo seguro de que una implementación real aproveche esto en un grado significativo. Sospecho que es más bien un problema de huevo y gallina: sin el soporte del compilador no se hizo popular, y mientras no sea popular, nadie se tomará la molestia de trabajar en su compilador para soportarlo.También hay una desconcertante (literalmente) variedad de clases auxiliares para usar con valarray. Se obtiene
slice
,slice_array
,gslice
ygslice_array
jugar con las piezas de unvalarray
, y hacerlo actuar como una matriz multidimensional. También puedemask_array
"enmascarar" una operación (por ejemplo, agregar elementos en xay, pero solo en las posiciones donde z no es cero). Para hacer un uso más que trivialvalarray
, debe aprender mucho sobre estas clases auxiliares, algunas de las cuales son bastante complejas y ninguna de las cuales parece (al menos para mí) muy bien documentada.En pocas palabras: si bien tiene momentos de brillantez y puede hacer algunas cosas de manera bastante ordenada, también hay algunas muy buenas razones por las que es (y seguramente seguirá siendo) oscuro.
Editar (ocho años después, en 2017): algunas de las anteriores se han vuelto obsoletas al menos en algún grado. Por ejemplo, Intel ha implementado una versión optimizada de valarray para su compilador. Utiliza las primitivas de rendimiento integrado de Intel (Intel IPP) para mejorar el rendimiento. Aunque la mejora exacta del rendimiento varía indudablemente, una prueba rápida con código simple muestra una mejora de velocidad de 2: 1, en comparación con el código idéntico compilado con la implementación "estándar" de
valarray
.Entonces, aunque no estoy completamente convencido de que los programadores de C ++ comenzarán a usar
valarray
en grandes cantidades, existen al menos algunas circunstancias en las que puede proporcionar una mejora de la velocidad.fuente
Durante la estandarización de C ++ 98, valarray fue diseñado para permitir algún tipo de cálculos matemáticos rápidos. Sin embargo, por esa época, Todd Veldhuizen inventó plantillas de expresión y creó blitz ++ , y se inventaron técnicas similares de meta-plantillas, que hicieron que los valarrays fueran bastante obsoletos incluso antes de que se lanzara el estándar. IIRC, los proponentes originales de valarray lo abandonaron a mitad de camino de la estandarización, lo que (si es cierto) tampoco lo ayudó.
ISTR dice que la razón principal por la que no se eliminó del estándar es que nadie se tomó el tiempo para evaluar el problema a fondo y escribir una propuesta para eliminarlo.
Sin embargo, tenga en cuenta que todo esto se recuerda vagamente por rumores. Tome esto con un grano de sal y espere que alguien corrija o confirme esto.
fuente
Tengo que decir que no creo que
std::valarrays
tenga mucho azúcar sintáctico. La sintaxis es diferente, pero no llamaría a la diferencia "azúcar". La API es rara. La sección sobrestd::valarray
s en The C ++ Programming Language menciona esta API inusual y el hecho de que, dado questd::valarray
se espera que los s estén altamente optimizados, cualquier mensaje de error que reciba mientras los usa probablemente no sea intuitivo.Por curiosidad, hace aproximadamente un año Entré en boxes
std::valarray
en contrastd::vector
. Ya no tengo el código o los resultados precisos (aunque no debería ser difícil escribir el tuyo). El uso de GCC Me hice un poco beneficio en el rendimiento cuando se utilizanstd::valarray
para operaciones matemáticas sencillas, pero no para mis implementaciones para calcular la desviación estándar (y, por supuesto, la desviación estándar no es tan compleja, en lo que va de matemáticas).Sospecho que las operaciones en cada elemento en un( NOTA , siguiendo los consejos de musiphil , he logrado obtener un rendimiento casi idéntico destd::vector
juego grande funcionan mejor con cachés que las operaciones enstd::valarray
s.vector
yvalarray
).Al final, decidí usarlo
std::vector
mientras prestaba mucha atención a cosas como la asignación de memoria y la creación de objetos temporales.Ambos
std::vector
ystd::valarray
almacenan los datos en un bloque contiguo. Sin embargo, acceden a esos datos utilizando diferentes patrones y, lo que es más importante, la APIstd::valarray
fomenta diferentes patrones de acceso que la APIstd::vector
.Para el ejemplo de la desviación estándar, en un paso particular necesitaba encontrar la media de la colección y la diferencia entre el valor de cada elemento y la media.
Para el
std::valarray
, hice algo como:Puede que haya sido más inteligente con
std::slice
ostd::gslice
. Han pasado más de cinco años.Para
std::vector
, hice algo en la línea de:Hoy ciertamente escribiría eso de manera diferente. Si nada más, aprovecharía C ++ 11 lambdas.
Es obvio que estos dos fragmentos de código hacen cosas diferentes. Por un lado, el
std::vector
ejemplo no hace una colección intermedia como lo hace elstd::valarray
ejemplo. Sin embargo, creo que es justo compararlos porque las diferencias están vinculadas a las diferencias entrestd::vector
ystd::valarray
.Cuando escribí esta respuesta, sospeché que restar el valor de los elementos de dos
std::valarray
s (última línea en elstd::valarray
ejemplo) sería menos amigable con el caché que la línea correspondiente en elstd::vector
ejemplo (que también es la última línea).Resulta, sin embargo, que
Hace lo mismo que el
std::vector
ejemplo y tiene un rendimiento casi idéntico. Al final, la pregunta es qué API prefieres.fuente
std::vector
que a jugaría mejor con cachés que astd::valarray
; ambos asignan un único bloque contiguo de memoria para sus elementos.valarray
ejemplo anterior, no tuvo que construir untemp
valarray
objeto, pero podría haberlo hechostd::valarray<double> differences_from_mean = original_values - mean;
, y luego el comportamiento de la memoria caché debería ser similar al delvector
ejemplo. (Por cierto, simean
es realmenteint
, nodouble
, puede que necesitesstatic_cast<double>(mean)
).valarray
. Necesitaré ver si eso mejora el rendimiento. En cuanto amean
serint
: eso fue un error. Originalmente escribí el ejemplo usandoint
s, y luego me di cuenta de quemean
estaría muy lejos de la media real debido al truncamiento. Pero me perdí algunos cambios necesarios en mi primera ronda de ediciones.Se suponía que valarray debía dejar que algo de la calidad del procesamiento de vectores FORTRAN se contagiara en C ++. De alguna manera, el soporte necesario del compilador nunca sucedió realmente.
Los libros de Josuttis contienen algunos comentarios interesantes (algo despectivos) sobre valarray ( aquí y aquí ).
Sin embargo, Intel ahora parece estar revisando valarray en sus recientes versiones del compilador (por ejemplo, vea la diapositiva 9 ); este es un desarrollo interesante dado que su conjunto de instrucciones SIMD SSE de 4 vías está a punto de unirse con instrucciones AVX de 8 vías y Larrabee de 16 vías y en aras de la portabilidad, probablemente sea mucho mejor codificar con una abstracción como valarray que (digamos) intrínsecos.
fuente
Encontré un buen uso para valarray. Es usar valarray al igual que matrices numpy.
Podemos implementar lo anterior con valarray.
Además, necesitamos un script de Python.
fuente
El estándar C ++ 11 dice:
Ver C ++ 11 26.6.1-2.
fuente
Con
std::valarray
usted puede usar la notación matemática estándar como lista para usarv1 = a*v2 + v3
. Esto no es posible con vectores a menos que defina sus propios operadores.fuente
std :: valarray está destinado a tareas numéricas pesadas, como la dinámica de fluidos computacional o la dinámica de estructura computacional, en las que tiene matrices con millones, a veces decenas de millones de elementos, y las itera en un bucle con millones de pasos. Tal vez hoy std :: vector tenga un rendimiento comparable, pero, hace unos 15 años, valarray era casi obligatorio si deseaba escribir un solucionador numérico eficiente.
fuente