tags:

views:

469

answers:

3

I have a vector containing the values 0, 1, 2 and 3. What I want to do is take the lower two bits from each set of 16 elements drawn from this vector and append them all together to get one uint32. Anyone know an easy way to do this?

Follow-up: What if the number of elements in the vector isn't an integer multiple of 16?

A: 

I think you should have a look at bitget and bitshift. It should be possible to be something like this (pseudo-matlab code as I haven't worked with Matlab for a long time):

result = 0;
for i = 1:16 do
  result += bitshift(bitget(vector(i), 2:-1:1), 2);

Note that this will give you the last bits of the first vector in the highest bits, so you might want to descend i from 16 to 1 instead

schnaader
bitshift and bitget were commands I was using before, and am trying to avoid...
devin
+5  A: 

Here's a vectorized version:

v = floor(rand(64,1)*4);
nWord = size(v,1)/16;
sum(reshape([bitget(v,2) bitget(v,1)]',[32 nWord]).*repmat(2.^(31:(-1):0)',[1 nWord ]))
Jacob
The vectorization is very clever, I wouldn't have thought of that. You can (slightly) optimize this by usingsum(reshape(v, [16 nWord]) .* repmat(2.^(30:(-2):0)',[1 nWord]));which avoids the bitget.
mtrw
Yeah that's pretty cool!
Jacob
All right, one more optimization to use matrix multiplication:uint32(reshape(v, [16 nWord])' * (2.^(30:(-2):0)'))'(also I added the cast to uint32).And as schnaader said in his/her answer, if your vector is LSB to MSB, change the exponent vector to 0:2:30.
mtrw
+3  A: 

To refine what was suggested by Jacob in his answer and mtrw in his comment, here's the most succinct version I can come up with (given a 1-by-N variable vec containing the values 0 through 3):

value = uint32(vec(1:16)*4.^(0:15)');

This treats the first element in the array as the least-significant bit in the result. To treat the first element as the most-significant bit, use the following:

value = uint32(vec(16:-1:1)*4.^(0:15)');

EDIT: This addresses the new revision of the question...

If the number of elements in your vector isn't a multiple of 16, then the last series of numbers you extract from it will have less than 16 values. You will likely want to pad the higher bits of the series with zeroes to make it a 16-element vector. Depending on whether the first element in the series is the least-significant bit (LSB) or most-significant bit (MSB), you will end up padding the series differently:

v = [2 3 1 1 3 1 2 2];  % A sample 8-element vector
v = [v zeros(1,8)];  % If v(1) is the LSB, set the higher bits to zero
% or...
v = [zeros(1,8) v];  % If v(1) is the MSB, again set the higher bits to zero

If you want to process the entire vector all at once, here is how you would do it (with any necessary zero-padding included) for the case when vec(1) is the LSB:

nValues = numel(vec);
nRem = rem(nValues,16);
vec = [vec(:) zeros(1,nRem)];  % Pad with zeroes
vec = reshape(vec,16,[])';  % Reshape to an N-by-16 matrix
values = uint32(vec*4.^(0:15)');

and when vec(1) is the MSB:

nValues = numel(vec);
nRem = rem(nValues,16);
vec = [vec(1:(nValues-nRem)) zeros(1,nRem) ...
       vec((nValues-nRem+1):nValues)];  % Pad with zeroes
vec = reshape(vec,16,[])';  % Reshape to an N-by-16 matrix
values = uint32(fliplr(vec)*4.^(0:15)');
gnovice

related questions