c++ - una - suma de vectores visual basic
¿Una manera eficiente de convertir una matriz corta de 16 bits en una matriz int de 32 bits? (7)
- Inicialice un
int[]
con la misma longitud que elshort[]
. - Iterar sobre el
short[]
, asignando el elementoi
th delshort[]
a lai
th posición delint[]
.
¿Cuál es la forma más eficiente de convertir una matriz de números cortos sin firmar (16 bits por valor) en una matriz de números de entradas sin firmar (32 bits por valor)?
Aquí un bucle desenrollado accediendo en trozos de 64 bits. Puede ser un poco más rápido que el simple bucle, pero las pruebas son la única forma de saberlo.
Suponiendo que N es un múltiplo de cuatro, ese tamaño de (corto) es de 16 bits y el trabajo con registros de 64 bits funciona.
typedef union u {
uint16_t us[4];
uint32_t ui[2];
uint64_t ull;
} u_t;
ushort_t src[N] = ...;
uint_t dst[N];
u_t *p_src = (u_t *) src;
u_t *p_dst = (u_t *) dst;
uint_t i;
u_t tmp, tmp2;
for(i=0; i<N/4; i++) {
tmp = p_src[i]; /* Read four shorts in one read access */
tmp2.ui[0] = tmp.us[0]; /* The union trick avoids complicated shifts that are furthermore dependent on endianness. */
tmp2.ui[1] = tmp.us[1]; /* The compiler should take care of optimal assembly decomposition. */
p_dst[2*i] = tmp2; /* Write the two first ints in one write access. */
tmp2.ui[0] = tmp.us[2];
tmp2.ui[1] = tmp.us[3];
p_dst[2*i+1] = tmp2; /* Write the 2 next ints in 1 write access. */
}
EDITAR
Así que lo probé en SUN M5000 (SPARC64 VII 2.5 GHz) con GCC 3.4.1 en modo de 64 bits en una matriz de 4,000,000 elementos. La implementación ingenua es un poco más rápida. Lo intenté con SUNStudio 12 y con GCC 4.3, pero ni siquiera he podido compilar el programa debido al tamaño de la matriz.
EDIT2
Logré compilarlo ahora en GCC 4.3. La versión optimizada es un poco más rápida que la ingenua.
GCC 3.4 GCC 4.3
naive 11.1 ms 11.8 ms
optimized 12.4 ms 10.0 ms
EDITAR3
Podemos concluir que, en lo que respecta a C, no se moleste con una versión optimizada del bucle de copia, la ganancia es tan baja que el riesgo de error supera el beneficio.
Cópialo.
unsigned short source[]; // …
unsigned int target[]; // …
unsigned short* const end = source + sizeof source / sizeof source[0];
std::copy(source, end, target);
std::copy
internamente el mejor mecanismo de copia para los tipos de entrada dados. En este caso, sin embargo, probablemente no haya mejor manera que copiar los elementos individualmente en un bucle.
En muchas arquitecturas, una reducción de do-while
puede ser más rápida que los bucles for
y while propuestos aquí. Algo como:
unsigned short ushorts[M];
unsigned int uints[N];
int i = M-1;
do{
uints[i] = ushorts[i];
i--;
} while(i >= 0);
El compilador puede ocuparse de la mayoría de las optimizaciones, como el desenrollado de bucles, pero en general lo anterior es más rápido (en muchas arquitecturas) porque:
- Obtiene la primera iteración de forma gratuita en un
do-while
inactividad en comparación con unwhile
ofor
- El bucle termina cuando i = 0. La comprobación de 0 puede guardar una instrucción porque el indicador de cero se establece automáticamente. Si el bucle se incrementó y terminó cuando i = M, entonces puede necesitar una instrucción de comparación adicional para probar si i <M.
También puede haber formas más rápidas, como hacerlo completamente con aritmética de punteros. Esto podría convertirse en un divertido ejercicio de desensamblar el código y analizarlo para ver qué aparece más rápido. Todo depende de la arquitectura. Afortunadamente, otros han hecho este trabajo por ti con std :: copy.
Qué pasa
unsigned short src[N] = ...;
unsigned int dst[N];
for(i=0; i<N; ++i)
dst[i] = src[i];
Para una versión en C ++, las respuestas de Konrad o Nawaz son seguramente las más adecuadas.
Simplemente copie la dirección de la matriz corta para acceder a cada elemento de la matriz corta, como pTp32[0...LEN-1].arr[0..1]
:
unsigned short shrtArray[LEN]; //..
union type32
{
short arr[2];
int value;
};
type32 * pTp32 = (type32*)shrtArray;
Use std::copy
en C ++:
#include<algorithm> //must include
unsigned short ushorts[M]; //where M is some const +ve integer
unsigned int uints[N]; //where N >= M
//...fill ushorts
std::copy(ushorts, ushorts+M, uints);
Y en C, use el bucle manual (de hecho, puede usar el bucle manual tanto en C como en C ++):
int i = 0;
while( i < M ) { uints[i] = ushorts[i]; ++i; }