Эффективный способ преобразования 16-разрядного короткого массива в 32-битный массив int?
Каков наиболее эффективный способ преобразования массива беззнаковых коротких чисел (16 бит на значение) в массив чисел без знака (32 бита на значение)?
Ответы
Ответ 1
Скопируйте его.
unsigned short source[]; // …
unsigned int target[]; // …
unsigned short* const end = source + sizeof source / sizeof source[0];
std::copy(source, end, target);
std::copy
внутренне выбирает лучший механизм копирования для заданных типов ввода. Однако в этом случае, возможно, нет лучшего способа, чем копирование элементов по отдельности в цикле.
Ответ 2
Используйте std::copy
в С++:
#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);
И в C используйте ручную петлю (на самом деле вы можете использовать ручной цикл как в C, так и в С++):
int i = 0;
while( i < M ) { uints[i] = ushorts[i]; ++i; }
Ответ 3
Здесь разворачивается цикл, доступный в 64-битных кусках. Это может быть немного быстрее, чем простой цикл, но тестирование - единственный способ узнать.
Предполагая, что N кратно четырем, размер (короткий) равен 16 бит и работает с 64-разрядными регистрами.
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. */
}
ИЗМЕНИТЬ
Итак, я просто протестировал его на SUN M5000 (SPARC64 VII 2.5 GHz) с GCC 3.4.1 в 64-битном режиме на массиве из 4 000 000 элементов. Наивная реализация немного быстрее. Я попытался с SUNStudio 12 и с GCC 4.3, но мне не удалось даже скомпилировать программу из-за размера массива.
EDIT2
Мне удалось собрать его сейчас на GCC 4.3. Оптимизированная версия немного быстрее, чем наивная.
GCC 3.4 GCC 4.3
naive 11.1 ms 11.8 ms
optimized 12.4 ms 10.0 ms
EDIT3
Мы можем заключить, что, что касается C, не беспокойтесь о оптимизированной версии цикла копирования, коэффициент усиления настолько мал, что риск ошибки перевешивает выгоду.
Ответ 4
Что насчет
unsigned short src[N] = ...;
unsigned int dst[N];
for(i=0; i<N; ++i)
dst[i] = src[i];
Для версии С++ ответы Konrad или Nawaz, безусловно, лучше подходят.
Ответ 5
- Инициализировать
int[]
с той же длиной, что и short[]
.
- Итерации по
short[]
, присваивая элементу i
thshort[]
позицию i
thint[]
.
Ответ 6
Во многих архитектурах декремент do-while
может быть быстрее, чем предлагаемые здесь циклы for
и while
. Что-то вроде:
unsigned short ushorts[M];
unsigned int uints[N];
int i = M-1;
do{
uints[i] = ushorts[i];
i--;
} while(i >= 0);
Компилятор может позаботиться о большинстве оптимизаций, таких как разворот цикла, но, как правило, это выше (на многих архитектурах), потому что:
- Вы получаете первую итерацию бесплатно в
do-while
по сравнению с while
или for
- Цикл заканчивается, когда я = 0. Проверка на 0 может сохранить инструкцию, потому что флаг нуля устанавливается автоматически. Если цикл увеличивается и заканчивается, когда я = M, то может потребоваться дополнительная команда сравнения для проверки, если я < М.
Там могут быть и более быстрые способы, такие как выполнение целиком с помощью арифметики указателя. Это может превратиться в забавное упражнение по разборке кода и анализу, чтобы увидеть, что появляется быстрее. Все зависит от архитектуры. К счастью, другие сделали эту работу для вас с помощью std:: copy.
Ответ 7
Просто скопируйте адрес короткого массива для доступа к каждому элементу короткого массива, например pTp32[0...LEN-1].arr[0..1]
:
unsigned short shrtArray[LEN]; //..
union type32
{
short arr[2];
int value;
};
type32 * pTp32 = (type32*)shrtArray;