как преобразовать отрицательное целочисленное значение в шестнадцатеричное в python

Я использую питон 2.6

>>> hex(-199703103)
'-0xbe73a3f'

>>> hex(199703103)
'0xbe73a3f'

Положительное и отрицательное значение совпадают?

Когда я использую calc, значение равно FFFFFFFFF418C5C1.


person nic nic    schedule 19.10.2011    source источник


Ответы (3)


Целые числа Python могут расти сколь угодно большими. Чтобы вычислить необработанное двойное дополнение так, как вы хотите, вам нужно будет указать желаемую разрядность. В вашем примере показано -199703103 в 64-битном дополнении до двух, но оно также могло быть 32-битным или 128-битным, что привело к другому количеству 0xf в начале.

hex() этого не делает. В качестве альтернативы предлагаю следующее:

def tohex(val, nbits):
  return hex((val + (1 << nbits)) % (1 << nbits))

print tohex(-199703103, 64)
print tohex(199703103, 64)

Это распечатывает:

0xfffffffff418c5c1L
0xbe73a3fL
person NPE    schedule 19.10.2011
comment
Не могли бы вы объяснить, что происходит, когда вы добавляете (1<<64)? Почему это нужно делать? - person jathanism; 19.10.2011
comment
@jathanism, значение (1<<64) на единицу больше, чем может поместиться в 64-битное целое число. Добавление его к отрицательному числу сделает его положительным, если отрицательное число умещается в 64 бита. Если исходное число было положительным, % отменит эффект сложения. - person Mark Ransom; 19.10.2011
comment
Я считаю, что в этой реализации есть ошибка: tohex(-129,8) возвращает 0x7f, что невозможно, поскольку 8-битное целое число со знаком может хранить числа только от (-1)* (2 ^7)= -128 до 2 ^7 - 1 = 127. Поэтому функция должна проверять, находится ли val в этом диапазоне перед возвратом, если нет, вызывать исключение (или что-то в этом роде). Это может сделать код более надежным, я думаю :) - person Dang Manh Truong; 31.08.2016

Поскольку целые числа Python произвольно велики, вам необходимо маскировать значения, чтобы ограничить преобразование числом битов, которые вы хотите использовать для представления дополнения до 2 с.

>>> hex(-199703103 & (2**32-1)) # 32-bit
'0xf418c5c1L'
>>> hex(-199703103 & (2**64-1)) # 64-bit
'0xfffffffff418c5c1L'

Python отображает простой случай hex(-199703103) как отрицательное шестнадцатеричное значение (-0xbe73a3f), потому что представление с дополнением 2s будет иметь бесконечное количество F перед ним для произвольного числа точности. Значение маски (2**32-1 == 0xFFFFFFFF) ограничивает это:

FFF...FFFFFFFFFFFFFFFFFFFFFFFFF418c5c1
&                             FFFFFFFF
--------------------------------------
                              F418c5c1
person Mark Tolonen    schedule 19.10.2011
comment
Несмотря на краткость, не является ли возведение в степень дорогостоящим по сравнению с битовыми манипуляциями? - person swdev; 08.01.2015
comment
@swdev, py -m timeit "2**32-1" -> 0,0235 мкс на цикл, py -m timeit "2<<32-1" -> 0,0235 мкс на цикл. Не предполагай. Всегда измеряйте, если вам не все равно :) Скорее всего, байтовый компилятор Python генерирует ту же константу нагрузки. - person Mark Tolonen; 08.01.2015
comment
ой, сделай это (1<<32)-1...но ты понял...Также легче ошибиться. И я проверил с модулем dis, и Python просто генерирует константу. - person Mark Tolonen; 08.01.2015
comment
Также вы могли бы вместо 2**32-1 просто использовать константу 0xFFFFFFFF для 32-битной и 0xFFFFFFFFFFFFFFFF для 64-битной, если вас беспокоит синхронизация. Или mask_32bit=(2**32-1), чтобы не каждый раз считать, а только один раз. - person Tom Myddeltyn; 17.06.2016
comment
@busfault на комментарий выше скорость ничем не отличается. Python вычисляет константу один раз при генерации байтового кода. Не нужно оптимизировать. - person Mark Tolonen; 18.06.2016
comment
@MarkTolonen Спасибо, я этого не осознавал (очевидно) :-) - person Tom Myddeltyn; 20.06.2016

Добавляя к Отметки ответа, если вам нужен другой формат вывода, используйте

'{:X}'.format(-199703103 & (2**32-1))
person tm1    schedule 11.05.2018