Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does shifting a numpy uint8 create negative values?

Tags:

python

numpy

I'm using python 2.7, numpy 1.6.1, 32-bit on windows. I'm writing a function to pack some data into 32-bit integers and generating C source declarations from the constant values. In doing so, I found some strange behavior in numpy's uint8 type.

No one is surprised, I'm sure, to see this:

>>> n = 0x94 << 24
>>> n
2483027968L
>>> hex(n)
'0x94000000L'

But do the same with a numpy uint8, and you get something that surprised me:

>>> n = np.uint8(0x94) << 24
>>> n
-1811939328
>>> hex(n)
'-0x6c000000'

One would think an explicitly unsigned type would be even less likely to return a negative value.

Note that values with the sign-bit clear work as expected:

>>> n = np.uint8(0x74) << 24
>>> n; hex(n)
1946157056
'0x74000000'

I happen to notice that numpy seems to be promoting unsigned types to signed types:

>>> n = np.uint8(0x74) << 24
>>> type(n)
<type 'numpy.int32'>

That seems a clear bug. I can find no reference to such a known bug, but...is it?

like image 856
jspencer Avatar asked Sep 05 '25 03:09

jspencer


1 Answers

numpy appears to treat the right-hand argument (24) as a signed integer of the native width (int32 in your case, int64 in mine).

It looks like the uint8 gets promoted to the same type, and the result of the shift is also of the same type:

>>> np.uint8(0x94) << 56
-7782220156096217088
>>> type(np.uint8(0x94) << 56)
<type 'numpy.int64'>

Making the right-hand argument into an unsigned int gives the result you expect:

>>> np.uint8(0x94) << np.uint(56)
10664523917613334528
>>> type(np.uint8(0x94) << np.uint(56))
<type 'numpy.uint64'>
>>> hex(np.uint8(0x94) << np.uint(56))
'0x9400000000000000L'
like image 152
NPE Avatar answered Sep 07 '25 19:09

NPE