Почему битовый сдвиг влево возвращает разные результаты в Python и Java?
Я пытаюсь перенести некоторые функции из приложения Java в Python.
В Java
System.out.println(155 << 24);
Возвращает: -1694498816
В Python:
print(155 << 24)
Возвращает 2600468480
Многие другие побитовые операции работали одинаково на обоих языках. Почему в этих двух операциях разные результаты?
РЕДАКТИРОВАТЬ: я пытаюсь создать функцию в Python, чтобы повторить, как работает левый оператор сдвига в Java. Что-то вроде:
def lshift(val, n):
return (int(val) << n) - 0x100000000
Однако это не кажется правильным, поскольку (я думаю) это превращает все числа в негативы?
РЕДАКТИРОВАТЬ 2: Несколько часов спустя я решил, что, вероятно, не самая лучшая идея использовать Python для этой работы, и примет участие в приложении Java и использует его в качестве микро-службы для существующего приложения Python.
3 ответа
Вот 3 различных способа преобразовать целое число Python в эквивалентную Java-подпись int
, Обратите внимание, что эти функции не будут работать правильно, если аргумент шире, чем 32 бита, поэтому вы можете использовать битовую маскировку аргумента перед вызовом их.
Первый способ заключается в использовании struct
модуль, чтобы интерпретировать число как 32-разрядное целое число без знака, упаковать его в байты (используя соглашение о локальном порядке байтов), а затем распаковать эти байты, интерпретируя их как 32-разрядное целое число со знаком. Другие два метода используют простую арифметику без вызовов функций, поэтому они быстрее, но я думаю, что их немного сложнее читать.
Этот код был написан на 32-битной машине с Python 2.6.6, но он должен корректно работать на любой архитектуре и версии Python (если только он не очень древний:)).
from __future__ import print_function
from struct import pack, unpack
def ulong_to_long_pack(u):
''' using pack & unpack '''
ubytes = pack('L', u)
return unpack('l', ubytes)[0]
def ulong_to_long_sub(u):
''' using subtraction '''
return u - (1<<32) if u >= (1<<31) else u
def ulong_to_long2_xor(u):
''' using exclusive OR '''
return u ^ ~((1<<32)-1) if u & (1<<31) else u
funcs = (ulong_to_long_pack, ulong_to_long_sub, ulong_to_long2_xor)
# test
for ulong_to_long in funcs:
print(ulong_to_long.__doc__)
u = 2600468480
print(u, ulong_to_long(u))
big = 1<<31
for u in range(big - 3, big + 3):
print(u, ulong_to_long(u))
print()
выход
using pack & unpack
2600468480 -1694498816
2147483645 2147483645
2147483646 2147483646
2147483647 2147483647
2147483648 -2147483648
2147483649 -2147483647
2147483650 -2147483646
using subtraction
2600468480 -1694498816
2147483645 2147483645
2147483646 2147483646
2147483647 2147483647
2147483648 -2147483648
2147483649 -2147483647
2147483650 -2147483646
using exclusive OR
2600468480 -1694498816
2147483645 2147483645
2147483646 2147483646
2147483647 2147483647
2147483648 -2147483648
2147483649 -2147483647
2147483650 -2147483646
Java имеет 32-битные целые числа фиксированной ширины, поэтому 155 << 24
сдвигает самый верхний установленный бит 155
(это бит 7, считая биты с нуля, потому что 155 больше, чем 27, но меньше, чем 28) в знаковый бит (бит 31), и в результате вы получите отрицательное число.
Python имеет целые числа произвольной точности, поэтому 155 << 24
численно равен положительному числу 155 × 224
Используйте долго в Java, чтобы получить тот же результат
System.out.println(155L << 24);
вместо
System.out.println(155 << 24);
Длина long составляет 4 байта, поэтому точность для этого контекста одинакова с целыми числами python.