Почему битовый сдвиг влево возвращает разные результаты в Python и Java?
Я пытаюсь перенести некоторые функции из приложения Java в Python.
В Java,
System.out.println(155 << 24);
возвращает: -1694498816
В Python:
print(155 << 24)
возвращает 2600468480
многие другие побитовые операции работали одинаково на обоих языках. Почему эти две операции приводят к разным результатам?
EDIT: я пытаюсь создать функцию в python для репликации того, как работает оператор Left shift в Java. Что-то вроде:
def lshift(val, n):
return (int(val) << n) - 0x100000000
однако это не кажется правильным, поскольку (я думаю) это превращает все числа в негативы?
EDIT2: несколько часов спустя я решил, что, вероятно, не лучшая идея использовать Python для этой работы и будет принимать участие в приложении Java и использовать его в качестве микро-службы для существующего приложения Python.
3 ответов
вот 3 различных способа преобразования целого числа Python в его эквивалент Java signed int
. Обратите внимание, что эти функции будут не работает правильно, если аргумент шире 32 бит, поэтому вы можете использовать битную маскировку для аргумента перед их вызовом.
первый способ-использовать struct
module чтобы интерпретировать число как 32-битное целое число без знака, упаковать его в байты (используя локальное соглашение endian), а затем распаковать эти байты, интерпретируя они как 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
используйте long в java, чтобы получить тот же результат
System.out.println(155L << 24);
вместо
System.out.println(155 << 24);
Long - длина 4 байта, поэтому точность одинакова для этого контекста для целых чисел python.