Эффективный способ преобразования 16-битного короткого массива в 32-битный массив int? - PullRequest
16 голосов
/ 06 сентября 2011

Каков наиболее эффективный способ преобразования массива чисел без знака (16 бит на значение) в массив чисел без знака (32 бита на значение)?

Ответы [ 7 ]

14 голосов
/ 06 сентября 2011

Скопируйте его.

unsigned short source[]; // …
unsigned int target[]; // …
unsigned short* const end = source + sizeof source / sizeof source[0];
std::copy(source, end, target);

std::copy внутренне выбирает лучший механизм копирования для заданных типов ввода.Однако в этом случае, вероятно, нет лучшего способа, чем индивидуальное копирование элементов в цикле.

9 голосов
/ 06 сентября 2011

Использование std::copy в 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);

А в C используйте ручной цикл (фактически, вы можете использовать ручной цикл как в C, так и в C ++):

int i = 0;
while( i < M ) { uints[i] = ushorts[i]; ++i; }
6 голосов
/ 06 сентября 2011

Здесь развернутый цикл доступа в 64-битных чанках.Это может быть немного быстрее, чем простой цикл, но тестирование - единственный способ узнать.

Если предположить, что N кратно четырем, то sizeof (short) равен 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 ГГц) с 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 неВозникают проблемы с оптимизированной версией цикла копирования, поэтому выигрыш настолько низок, что риск ошибки перевешивает выгоду.

2 голосов
/ 06 сентября 2011

Как насчет

unsigned short src[N] = ...;
unsigned int dst[N];

for(i=0; i<N; ++i)
    dst[i] = src[i];

Для версии C ++ ответы Конрада или Наваза, безусловно, лучше подходят.

1 голос
/ 29 декабря 2011

Просто скопируйте адрес короткого массива, чтобы получить доступ к каждому элементу короткого массива, например pTp32[0...LEN-1].arr[0..1]:

unsigned short shrtArray[LEN]; //..
union type32
{
    short arr[2];
    int value;
};
type32 * pTp32 = (type32*)shrtArray;
1 голос
/ 06 сентября 2011

На многих архитектурах уменьшающийся 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
  • Цикл заканчивается при i = 0. Проверка на 0 может сохранить инструкцию, поскольку флаг нуля устанавливается автоматически.Если цикл увеличивается и заканчивается, когда i = M, то может потребоваться дополнительная инструкция сравнения, чтобы проверить, является ли i

. Также могут быть более быстрые способы, такие как выполнение полностью с арифметикой указателя.,Это может превратиться в забавное упражнение по разборке кода и анализу, чтобы увидеть, что выглядит быстрее.Это все зависит от архитектуры.К счастью, другие сделали эту работу за вас с помощью std :: copy.

1 голос
/ 06 сентября 2011
  1. Инициализируйте int[] той же длины, что и short[].
  2. . Итерируйте по short[], назначив элемент i th short[] до i th позиции int[].
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...