The Python Oracle

Why is (2^31) >> 32 not 0?

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
and get $2,000 discount on your first invoice
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Lost Jungle Looping

--

Chapters
00:00 Why Is (2^31) ≫≫ 32 Not 0?
01:14 Accepted Answer Score 8
02:11 Thank you

--

Full question
https://stackoverflow.com/questions/5509...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #arrays #numpy #bitshift

#avk47



ACCEPTED ANSWER

Score 8


While not documented, numpy is mostly implemented in C and the shift operator in C (and C++) is not defined for shifts greater than or equal to the number of bits. So the result can be arbitrary.

If you look at the types of the examples that work you'll see why they work:

print(
    type(2**31 >> 32),
    type(np.uint32(2**31) >> 32),
    type(np.array(2**31, dtype=np.uint32) >> 32),
    type(np.right_shift(2**31, 32)),
    np.right_shift([2**31], 32).dtype,
    type(np.right_shift(np.uint32(2**31), 32)),
    type(np.right_shift(np.array(2**31, dtype=np.uint32), 32)),
)

<class 'int'> <class 'numpy.int64'> <class 'numpy.int64'> <class 'numpy.int64'> int64 <class 'numpy.int64'> <class 'numpy.int64'>

The first uses Python's own int type, while the others are all converted to numpy.int64, where the behavior for a 32-bit shift is correct. This is mostly due to the fact that scalar (zero-dimensional) arrays behave differently. And in the list case that the default integer type for numpy is not numpy.uint32.

On the other hand

print((np.array([2**31], dtype=np.uint32) >> 32).dtype)

uint32

So you run into the undefined behavior here.