Почему (2 ^ 31) >> 32 не 0? - PullRequest
       14

Почему (2 ^ 31) >> 32 не 0?

14 голосов
/ 11 марта 2019

Моя проблема в том, что

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

не возвращает 0, но возвращает array([2147483648], dtype=uint32). То же самое верно для

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

(поэтому я считаю, что это просто, как реализовано >>).

Интересно, что все эти альтернативы, похоже, работают, как и ожидалось, возвращая что-то вроде 0:

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

В частности, чем отличаются массивы Numpy, представляющие 2147483648 и [2147483648]?

Я видел эту проблему в JavaScript ( Почему << 32 не приводит к 0 в javascript? </a>) и C ++ ( Странное поведение оператора сдвига вправо (1 >> 32) , Почему `int >> 32` не всегда равно нулю? ), но еще не в Python / Numpy. Фактически, ни документы Python, ни документы Numpy, похоже, не документируют это поведение:

1 Ответ

8 голосов
/ 11 марта 2019

Хотя это и не задокументировано, numpy в основном реализован в C, а оператор сдвига в C (и C ++) не определен для сдвигов, больших или равных количеству битов. Таким образом, результат может быть произвольным.

Если вы посмотрите на типы примеров, которые работают, вы поймете, почему они работают:

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)),
)

int64

Первый использует собственный тип Python int, а все остальные преобразуются в numpy.int64, где поведение для 32-битного сдвига является правильным. В основном это связано с тем, что скалярные (нульмерные) массивы ведут себя по-разному. И в случае list этот целочисленный тип по умолчанию для numpy равен , а не numpy.uint32.

С другой стороны

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

uint32

Итак, вы столкнулись с неопределенным поведением здесь.

...