Take the 2-minute tour ×

What is the most efficient way to convert an array of unsigned short numbers (16 bits per value) into an array of unsigned ints numbers (32 bits per value)?

share|improve this question
Create a int[] and copy the shorts over? –  Seth Carnegie Sep 6 '11 at 14:00
There is no C/C++. Therefore some answers apply to C and others to C++. –  Christian Rau Sep 6 '11 at 14:04
If you can live with the shorts and don't need to copy at all, that's the most efficient way :) –  pmg Sep 6 '11 at 14:08
What CPU architecture and compiler are you using? –  bdonlan Sep 6 '11 at 14:36
A short is not necessarily 16 bits, and an int is not necessarily 32 bits. This is implementation dependent. –  Peter Mortensen Sep 6 '11 at 16:38
show 1 more comment

7 Answers

up vote 13 down vote accepted

Copy it.

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

std::copy internally choses the best copying mechanism for given input types. In this case, however, there’s probably no better way than copying the elements individually in a loop.

share|improve this answer
It seems to fail works for type-conversion. –  Vladimir Sep 6 '11 at 14:17
@Dair This doesn’t fail – it definitely works. I’ve tested it. –  Konrad Rudolph Sep 6 '11 at 14:21
Also you could use the vector (iterator, iterator) constructor. –  Mark B Sep 6 '11 at 14:39
I doubt that std::copy has internal mechanisms for handling short specifically? Most likely the shorts are promoted to ints, and then you've merely invented a way to copy ints to ints. Also, this will never be the most efficient way on many platforms, as it is forced to compare addresses instead of comparing a counter iterator against a fixed value. –  Lundin Sep 6 '11 at 15:30
As a data point, a simple loop and std::copy both compile to the same code with GCC 4.5.2 on my Core2Duo: A loop using pmovsxwd and movdqu with handling for any reamaing elements. (compiled with -O3 -march=native -mtune=native). –  user786653 Sep 6 '11 at 15:43
show 4 more comments

Use std::copy in 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);

And in C, use manual loop (in fact, you can use manual loop both in C and C++):

int i = 0;
while( i < M ) { uints[i] = ushorts[i]; ++i; }
share|improve this answer
add comment

Here an unrolled loop accessing in 64 bits chunks. It might be a little bit faster than the simple loop, but testing is the only way to know.

Assuming that N is a multiple of four, that sizeof (short) is 16 bit and working with 64 bit registers works.

 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. */


So I just tested it on SUN M5000 (SPARC64 VII 2.5 GHz) with GCC 3.4.1 in 64-bit mode on a 4,000,000 element array. The naive implementation is a bit faster. I tried with SUNStudio 12 and with GCC 4.3, but I haven't been able to even compile the program because of the array size.


I managed to compile it now on GCC 4.3. The optimized version is a bit faster than the naive one.

              GCC 3.4          GCC 4.3
naive         11.1 ms          11.8 ms
optimized     12.4 ms          10.0 ms


We can conclude from that, as far as C is concerned, don't bother with an optimized version of the copy loop, the gain is so low that the risk of error outweighs the benefit.

share|improve this answer
add comment

What about

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

    dst[i] = src[i];

For a C++ version Konrad's or Nawaz's answers are surely better suited.

share|improve this answer
This ought to be the most efficient way in both C and C++, if we forget about compiler optimizations. –  Lundin Sep 6 '11 at 15:32
add comment
  1. Initialize an int[] with the same length as the short[].
  2. Iterate over the short[], assigning the ith element of the short[] to the ith position of the int[].
share|improve this answer
add comment

Just copy the address of the short array to access each element of the short array, like pTp32[0...LEN-1].arr[0..1]:

unsigned short shrtArray[LEN]; //..
union type32
    short arr[2];
    int value;
type32 * pTp32 = (type32*)shrtArray;
share|improve this answer
add comment

On many architectures a decrementing do-while may be faster than the for and while loops proposed here. Something like:

unsigned short ushorts[M];
unsigned int uints[N];

int i = M-1;
    uints[i] = ushorts[i];
} while(i >= 0);

The compiler can take care of most optimizations such as loop unrolling, but generally the above is faster (on many architectures) because:

  • You get the first iteration for free in a do-while vs. a while or for
  • The loop ends when i = 0. Checking for 0 can save an instruction because the zero flag is set automatically. If the loop incremented and ended when i = M then it may need an extra compare instruction to test if i < M.

There may be faster ways as well, such as doing it entirely with pointer arithmetic. This could turn into a fun exercise of disassembling the code and analyzing to see which appears faster. It is all architecture dependent. Fortunately others have done this work for you with std::copy.

share|improve this answer
The loop indices are wrong. It should be int i = M-1 and do {...} while(i > -1); –  Nawaz Sep 6 '11 at 14:41
While the loop termination might be slightly faster, copying backwards is equally likely not to be very cache friendly. –  Bo Persson Sep 6 '11 at 15:59
Since you're likely to be memory bound here, the extra ALU instruction to check the loop bound is unlikely to be a major issue. –  bdonlan Sep 6 '11 at 18:00
add comment

Your Answer


