Paul Oyster
Paul Oyster

Reputation:

How to get the signed integer value of a long in python?

If lv stores a long value, and the machine is 32 bits, the following code:

iv = int(lv & 0xffffffff)

results an iv of type long, instead of the machine's int.

How can I get the (signed) int value in this case?

Upvotes: 37

Views: 83466

Answers (9)

Simplest solution with any bit-length of number

Why is the syntax of a signed integer so difficult for the human mind to understand. Because this is the idea of machines. :-) Let's explain. If we have a bi-directional 7-bit counter with the initial state

000 0000

and we get a pulse for the back count input. Then the next number to count will be

111 1111

And the people said:

Hey, the counter we need to know that this is a negative reload. You should add a sign letting you know about this.

And the counter added:

1111 1111

And people asked,

How are we going to calculate that this is -1.

The counter replied: Find a number one greater than the reading and subtract it and you get the result.

   1111 1111
 -10000 0000
____________
(dec)     -1




def sigIntFromHex(a):  # a = 0x0xffe1
    if a & (1 << (a.bit_length()-1)):  # check if highest bit is 1 thru & with 0x1000
        return a - (1 << (a.bit_length()))  # 0xffe1 - 0x10000 
    else:
        return a

###and more elegant:###

def sigIntFromHex(a):
    return a - (1 << (a.bit_length())) if a & (1 << (a.bit_length()-1)) else a
        
b = 0xFFE1
print(sigIntFromHex(b))

I hope I helped

Upvotes: -2

Galaxie_128
Galaxie_128

Reputation: 1

In case the hexadecimal representation of the number is of 4 bytes, this would solve the problem.

def B2T_32(x):
  num=int(x,16)
  if(num & 0x80000000): # If it has the negative sign bit. (MSB=1)
    num -= 0x80000000*2
  return num
print(B2T_32(input("enter a input as a hex value\n")))

Upvotes: -1

tim
tim

Reputation: 482

If you know how many bits are in the original value, e.g. byte or multibyte values from an I2C sensor, then you can do the standard Two's Complement conversion:

def TwosComp8(n):
    return n - 0x100 if n & 0x80 else n

def TwosComp16(n):
    return n - 0x10000 if n & 0x8000 else n

def TwosComp32(n):
    return n - 0x100000000 if n & 0x80000000 else n

Upvotes: 0

Rob Milne
Rob Milne

Reputation: 69

A quick and dirty solution (x is never greater than 32-bit in my case).

if x > 0x7fffffff:
    x = x - 4294967296

Upvotes: 6

gengkev
gengkev

Reputation: 1959

Essentially, the problem is to sign extend from 32 bits to... an infinite number of bits, because Python has arbitrarily large integers. Normally, sign extension is done automatically by CPU instructions when casting, so it's interesting that this is harder in Python than it would be in, say, C.

By playing around, I found something similar to BreizhGatch's function, but that doesn't require a conditional statement. n & 0x80000000 extracts the 32-bit sign bit; then, the - keeps the same 32-bit representation but sign-extends it; finally, the extended sign bits are set on n.

def toSigned32(n):
    n = n & 0xffffffff
    return n | (-(n & 0x80000000))

Bit Twiddling Hacks suggests another solution that perhaps works more generally. n ^ 0x80000000 flips the 32-bit sign bit; then - 0x80000000 will sign-extend the opposite bit. Another way to think about it is that initially, negative numbers are above positive numbers (separated by 0x80000000); the ^ swaps their positions; then the - shifts negative numbers to below 0.

def toSigned32(n):
    n = n & 0xffffffff
    return (n ^ 0x80000000) - 0x80000000

Upvotes: 29

BreizhGatch
BreizhGatch

Reputation: 101

Can I suggest this:

def getSignedNumber(number, bitLength):
    mask = (2 ** bitLength) - 1
    if number & (1 << (bitLength - 1)):
        return number | ~mask
    else:
        return number & mask

print iv, '->', getSignedNumber(iv, 32)

Upvotes: 10

Raony Barrios
Raony Barrios

Reputation: 385

import ctypes

number = lv & 0xFFFFFFFF

signed_number = ctypes.c_long(number).value

Upvotes: 36

Glenn Maynard
Glenn Maynard

Reputation: 57474

You're working in a high-level scripting language; by nature, the native data types of the system you're running on aren't visible. You can't cast to a native signed int with code like this.

If you know that you want the value converted to a 32-bit signed integer--regardless of the platform--you can just do the conversion with the simple math:

iv = 0xDEADBEEF
if(iv & 0x80000000):
    iv = -0x100000000 + iv

Upvotes: 22

Tupteq
Tupteq

Reputation: 3095

You may use struct library to convert values like that. It's ugly, but works:

from struct import pack, unpack
signed = unpack('l', pack('L', lv & 0xffffffff))[0]

Upvotes: 9

Related Questions