1

Given 2 numpy.ndarray's I want to set the 2 LSB's of the array1 to array2. To clarify:

array1 = [1, 2, 3, 4, 5]
array2 = [4, 3, 4]

In binary this can be represented as:

array1 = [00000001, 00000010, 00000011, 00000100]
array2 = [00000100, 00000011, 00000100]

Now the new array after setting the 2LSB's of array2 to array1 is:

newArray = [00000000, 00000011, 00000000, 00000100]

I can use np.unpackbits to convert the array to binary representation. But how do I just change the last 2 bits of array1 without changing the upper 6 bits of array1?

Mike
  • 49
  • 3

3 Answers3

1

First you need to resize array2 to have the same shape as array1.

# mutates array2 in-place
array2.resize(array1.shape)

# or, if array2 is never longer than array1
array2 = numpy.pad(array2, (0, len(array1) - len(array2)), 'constant')

Then, use standard bit manipulation methods to copy the last two bits.

(array1 & ~3) | (array2 & 3)
Community
  • 1
  • 1
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
0

kennytm's answer is how it should be done because math. However, here is another approach going the array route you were starting down.

a = np.array( [[1], [2], [3], [4], [5]], dtype=np.uint8 )
b = np.array( [[4], [3], [4]], dtype=np.uint8 )
au = np.unpackbits( a, axis=1 )
bu = np.unpackbits( b, axis=1 )
nu = au

for i in range( 0, len(nu) ):
    if len(bu) > i:
        nu[i][-2] = bu[i][-2]
        nu[i][-1] = bu[i][-1]

print( nu )

Yields

[[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 1 1]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 1 0 0]
[0 0 0 0 0 1 0 1]]
domwrap
  • 443
  • 1
  • 4
  • 12
0

With plain bit operations, this is how you can do it.

array1 = [00000001, 00000010, 00000011, 00000100]
array2 = [00000100, 00000011, 00000100]

Get first index of array2.

array2[0] = 00000100

Apply following:

result = array2[0] << 6
result >>>= 6 (Unsigned, since we don't care about sign here)

Now, apply following:

result2 = array1[0] >>> 2
result2 <<= 2

And then:

result1 | result2

For explaining with respect to your given data, I will apply it on index 1 of both arrays.

array2[1] = 00000011

So, first

00000011 << 6 will give 11000000

Now, apply unsigned right shift on the result.

11000000 >>> 6 will give 00000011

Applying on array1[1]

array1[1] = 00000010

So,

00000010 >>> 2 will give 0000 0000

and

0000 0000 << 2 will give 0000 0000

Now, apply | on two results.

0000 0000 | 0000 0011 will give 0000 0011

Explanation

You might be wondering why performing operations twice? For example, on array2, I first performed a left shift of 6 bits and then an unsigned right shift of 6 bits?

Left shift of 6 bits will remove all other bits in array2 since, we don't require them for this operation (we don't care whatever those bits were)

Unsigned right shift of 6 bits again will bring our last 2 bits of array2 back to normal position since that is all what matters for our final result.

Now, first an unsigned right shift on array1 of 2 bits, will drop last 2 bits and applying left shift of 2 bits again, will set them as 0 and OR'ing (|) them will add last 2 bits in the final result.

SSC
  • 2,956
  • 3
  • 27
  • 43