Як перетворити підписане ціле число без підпису в python


78

Скажімо, у мене є цей номер i = -6884376. Як я можу посилатися на неї як на непідписану змінну? Щось як (unsigned long)iу C.


9
Python не має вбудованих типів без підпису.
BrenBarn

2
Ви можете використовувати функцію abs ().
Алі САЙД ОМАР

2
Крім того, яку проблему ви намагаєтесь вирішити цим?
BrenBarn

1
Цілочисельний тип Python має необмежену точність і не залежить від основних типів фіксованого розміру. Як такий, він не може розрізняти типи без знака та підпису. Вам доведеться зробити перетворення самостійно.
тикати

4
@AliSAIDOMAR ні, absфункція не дає того, що (unsigned)дає акторський склад , що є (uint32_t)a = (1LL << 32) - aдодатком 2
phuclv

Відповіді:


98

Припускаючи :

  1. Ви маєте на увазі уявлення про доповнення 2; і,
  2. До (unsigned long)вам означає беззнаковое 32-розрядний ціле число,

тоді вам просто потрібно додати 2**32 (or 1 << 32)до від’ємного значення.

Наприклад, застосуйте це до -1:

>>> -1
-1
>>> _ + 2**32
4294967295L
>>> bin(_)
'0b11111111111111111111111111111111'

Припущення # 1 означає, що ви хочете, щоб -1 розглядався як суцільний рядок з 1 біта, а припущення # 2 означає, що ви хочете, щоб їх було 32.

Однак ніхто, крім вас, не може сказати, якими є ваші приховані припущення. Якщо, наприклад, ви маєте на увазі подання 1-доповнення, то вам потрібно ~замість цього застосувати оператор префікса. Цілі числа Python наполегливо працюють, щоб створити ілюзію використання нескінченно широкого представлення доповнення 2 (як звичайне доповнення 2, але з нескінченною кількістю «знакових бітів»).

А щоб повторити те, що робить компілятор платформи C, ви можете використовувати ctypesмодуль:

>>> import ctypes
>>> ctypes.c_ulong(-1)  # stuff Python's -1 into a C unsigned long
c_ulong(4294967295L)
>>> _.value
4294967295L

C unsigned longбуває 4 байтами в полі, в якому пройшов цей зразок.


48
Я не знав, що ви можете використати _посилання на результат попереднього рядка!
Yay295,

@ Yay295 Правильно! Чи можливо це лише в інтерактивному режимі, чи можна використовувати його і в неінтерактивному режимі?
HelloGoodbye

1
@HelloGoodbye, використання "_"для отримання попереднього результату - це не особливість самої мови, а зручність, реалізована деякими (більшість? Усіх?) Інтерактивними оболонками Python. Вони повинні захопити найсвіжіший результат незалежно від того, щоб відобразити його. Сама мова такого не робить.
Тім Пітерс

На всякий випадок, якщо хтось ще натрапить на цю відповідь, я рекомендую перевірити відповідь @ Duncan, яка замінить будь-яке ціле число Python на unsigned longеквівалент. Просто додавання 2 ** 32 або 1 << 32 працює лише з від’ємними цілими числами в певному діапазоні.
Білл

68

Щоб отримати значення, еквівалентне творому C, просто побітово та з відповідною маскою. наприклад, якщо unsigned long32-бітний:

>>> i = -6884376
>>> i & 0xffffffff
4288082920

або якщо це 64 біт:

>>> i & 0xffffffffffffffff
18446744073702667240

Майте на увазі, хоча, хоча це дає вам значення, яке ви мали б у C, воно все ще є підписаним значенням, тому будь-які подальші обчислення можуть дати негативний результат, і вам доведеться продовжувати застосовувати маску для імітації 32 або 64 розрахунок бітів.

Це працює, тому що хоча Python виглядає так, ніби він зберігає всі числа як знак і величину, побітові операції визначаються як робота над значеннями доповнення двох. C зберігає цілі числа у двійки, доповнюючи їх, але з фіксованою кількістю бітів. Побітові оператори Python діють на двоє значень доповнення, але ніби вони мають нескінченну кількість бітів: для позитивних чисел вони розширюються вліво до нескінченності з нулями, але від'ємні числа продовжуються ліворуч з одиницями. &Оператор змінить цю левонаправленную рядок одиниць в нулі і залишити вас з тільки битами , які будуть мати підгонку в значення C.

Відображення значень у шістнадцятковій формі може зробити це зрозумілішим (і я переписав на рядок f як вираз, щоб показати, що нас цікавлять або 32, або 64 біти):

>>> hex(i)
'-0x690c18'
>>> hex (i & ((1 << 32) - 1))
'0xff96f3e8'
>>> hex (i & ((1 << 64) - 1)
'0xffffffffff96f3e8L'

Для 32-бітового значення в C додатні числа збільшуються до 2147483647 (0x7fffffff), а негативні числа мають верхній біт, що йде від -1 (0xffffffff) до -2147483648 (0x80000000). Для значень, які цілком вміщуються в масці, ми можемо змінити процес у Python, використовуючи меншу маску, щоб видалити знаковий біт, а потім віднявши знаковий біт:

>>> u = i & ((1 << 32) - 1)
>>> (u & ((1 << 31) - 1)) - (u & (1 << 31))
-6884376

Або для 64-розрядної версії:

>>> u = 18446744073702667240
>>> (u & ((1 << 63) - 1)) - (u & (1 << 63))
-6884376

Цей зворотний процес залишить значення незмінним, якщо знаковий біт дорівнює 0, але, очевидно, це не є справжнім оберненим, тому що якщо ви починали зі значення, яке не вписується в розмір маски, ці біти зникнуть.


+ Один: Простий, без імпорту
Петр Вепржек,

1
Чому це робиться? (а якою буде обернена операція)
МБ.

2
@MB Я розширив свою відповідь, сподіваюся, що це допоможе.
Дункан

Зворотне виявилося досить корисним. Деякі бібліотеки python, записані в C, повертають підписане 64-бітне значення, і це закінчується як long у python
user1978816

16

Python не має вбудованих типів без підпису. Ви можете використовувати математичні операції для обчислення нового int, що представляє значення, яке ви отримали б в C, але немає "беззнакового значення" Python int. Int Python - це абстракція цілочисельного значення, а не прямий доступ до цілого числа фіксованого байту.


4

Ви можете використовувати structвбудовану бібліотеку Python:

Кодувати:

import struct

i = -6884376
print('{0:b}'.format(i))

packed = struct.pack('>l', i)  # Packing a long number.
unpacked = struct.unpack('>L', packed)[0]  # Unpacking a packed long number to unsigned long
print(unpacked)
print('{0:b}'.format(unpacked))

Вийшов:

-11010010000110000011000
4288082920
11111111100101101111001111101000

Розшифрувати:

dec_pack = struct.pack('>L', unpacked)  # Packing an unsigned long number.
dec_unpack = struct.unpack('>l', dec_pack)[0]  # Unpacking a packed unsigned long number to long (revert action).
print(dec_unpack)

Вийшов:

-6884376

[ ПРИМІТКА ]:

  • > є операцією BigEndian.
  • l довгий.
  • L не підписано довго.
  • В amd64архітектурі intі longє 32-бітовими, отже, ви можете використовувати iі Iзамість lі, Lвідповідно.

1

python не має жодної вбудованої функції, щоб перетворити int на непідписаний int, а замість цього він має довгий діапазон.

>>> val = 9223372036854775807 (maximum value of int 64)
>>> type(val)
<type 'int'>
>>> val += 1
>>> type(val)
<type 'long'>

Збільшуючи значення val на 1, я перевищую межу підписаного 64-бітового цілого числа, і значення перетворюється на long. Якби Python використовував або перетворював на ціле число без знака, val все одно був би int. Або, недовго.

Підписані цілі числа представлені бітом, як правило, найбільш значущим бітом, для якого встановлено значення 0 для додатних чи 1 для негативних чисел. Те, що робить val & 0xff, насправді є val & 0x000000ff (на 32-бітній машині). Іншими словами, підписаний біт встановлюється на 0, а беззнакове значення емулюється.

Приклад:

>>> val = -1
>>> val & 0xff
255

0

просто використовуйте abs для перетворення непідписаного в підписаний python

 a=-12
b=abs(a)
print(b)

Вихід: 12


Я відчуваю, що це правда лише частково. Як стверджує MDN python > abs() Повертає абсолютне значення числа. Аргументом може бути звичайне або довге ціле число або число з плаваючою комою. Якщо аргумент є комплексним числом, повертається його величина. Це за визначенням не повертає unsignedзмінну весь час
Самуель Хулла

але він запитував лише ціле число.
Харі Прасат,

0

З версії 3.2:

def toSigned(n, byte_count): 
  return int.from_bytes(n.to_bytes(byte_count, 'little'), 'little', signed=True)

вихід:

In [8]: toSigned(5, 1)                                                                                                                                                                                                                                                                                                     
Out[8]: 5

In [9]: toSigned(0xff, 1)                                                                                                                                                                                                                                                                                                  
Out[9]: -1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.