Python: битовый массив в целое число: случайное получение отрицательных целых чисел с массивами NumPy - PullRequest
1 голос
/ 19 апреля 2020
Python 3.7.4 (default, Aug 13 2019, 20:35:49) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
>>> np.version.version
'1.17.2'

Я поддерживаю целые числа как битовый массив для алгоритмической обработки на битовом уровне. Я использую довольно стандартный способ преобразования массива битов в целое число, а затем просмотр в десятичном формате.

def decimal(binaryValue):
    decimalValue = 0
    for bit in binaryValue:
        decimalValue = (decimalValue << 1) | bit
        print(decimalValue) #For testing
    return decimalValue

Я странным образом получаю отрицательные целые числа случайным образом для определенных 64-битных массивов или больше. После некоторого удаления волос и безумной отладки я понял, что это происходит, когда я использую массив NumPy. Нет проблем с обычными списками. Вот конкретный пример c:

>>> b = [1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1]
>>> decimal(b)
1
3
7
...
4418570559336253839
8837141118672507678
17674282237345015357
17674282237345015357
>>> import numpy as np
>>> b_np = np.array(b)
>>> b_np
array([1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0,
   1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
   0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1])
>>> decimal(b_np)
1
3
7
...
4418570559336253839
8837141118672507678
-772461836364536259
-772461836364536259
>>> np.binary_repr(decimal(b))
'1111010101000111101010100000110101110000111100100010011000111101'
>>> np.binary_repr(decimal(b_np))
'-101010111000010101011111001010001111000011011101100111000011'

Как вы можете видеть, с представлением массива numpy что-то происходит при оценке последнего бита. Если я преобразую массив numpy обратно в список, я получу отрицательное число! Очень очень странно Что-то происходит в пространстве numpy. Но c идентичен b.

>>> c = list(b_np)
>>> c
[1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1]
>>> decimal(c)
1
3
7
...
4418570559336253839
8837141118672507678
-772461836364536259
-772461836364536259
>>>np_binary_rep(decimal(c))
'-101010111000010101011111001010001111000011011101100111000011'

Простые проверки:

>>> len(b)
64
>>> len(b_np)
64
>>> len(c)
64
>>> b == c
True
>>> b == b_np
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True])

Что происходит? Очевидно, 64-битная проблема, но не вижу, где. Спасибо.

1 Ответ

2 голосов
/ 19 апреля 2020

Когда вы пытаетесь преобразовать переменную b, вы назначаете тип данных int переменной decimal, но когда вы делаете это с типом данных numpy.array, таким как b_np, вы назначаете numpy.int64 тип данных.

int type

Тип int может представлять целое число до sys.maxsize * 2 + 1:

import sys
print(sys.maxsize * 2 + 1)
# Prints 18446744073709551615 (length 20)

Это означает, что ваш первый результат 17674282237345015357 представляется беззнаковым целым, потому что 18446744073709551615 > 17674282237345015357 == True.

numpy.int64 type

Этот тип данных может представлять целые числа от -9223372036854775808 to 9223372036854775807, здесь вы можете проверить .
Поскольку 9223372036854775807 (длина 19) меньше ожидаемого результата 18446744073709551615, 64-й байт считается знаком, поэтому только ваш последний результат дает отрицательное значение. Если вы попробуете тот же пример с массивом с '62 length ( 2 ** 62` представляемыми значениями), вы увидите, что у вас не будет отрицательных значений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...