Two's complement of Hex number in Python

Question:

Below a and b (hex), representing two’s complement signed binary numbers.
For example:

a = 0x17c7cc6e
b = 0xc158a854

Now I want to know the signed representation of a & b in base 10. Sorry I’m a low level programmer and new to python; feel very stupid for asking this. I don’t care about additional library’s but the answer should be simple and straight forward. Background: a & b are extracted data from a UDP packet. I have no control over the format. So please don’t give me an answer that would assume I can change the format of those varibles before hand.

I have converted a & b into the following with this:

aBinary = bin(int(a, 16))[2:].zfill(32) => 00010111110001111100110001101110 => 398969966
bBinary = bin(int(b, 16))[2:].zfill(32) => 11000001010110001010100001010100 => -1051154348

I was trying to do something like this (doesn’t work):

if aBinary[1:2] == 1:
aBinary = ~aBinary + int(1, 2)

What is the proper way to do this in python?

Asked By: Nimjox

||

Answers:

>>> import numpy
>>> numpy.int32(0xc158a854)
-1051154348

You’ll have to know at least the width of your data. For instance, 0xc158a854 has 8 hexadecimal digits so it must be at least 32 bits wide; it appears to be an unsigned 32 bit value. We can process it using some bitwise operations:

In [232]: b = 0xc158a854

In [233]: if b >= 1<<31: b -= 1<<32

In [234]: b
Out[234]: -1051154348L

The L here marks that Python 2 has switched to processing the value as a long; it’s usually not important, but in this case indicates that I’ve been working with values outside the common int range for this installation. The tool to extract data from binary structures such as UDP packets is struct.unpack; if you just tell it that your value is signed in the first place, it will produce the correct value:

In [240]: s = 'xc1x58xa8x54'

In [241]: import struct

In [242]: struct.unpack('>i', s)
Out[242]: (-1051154348,)

That assumes two’s complement representation; one’s complement (such as the checksum used in UDP), sign and magnitude, or IEEE 754 floating point are some less common encodings for numbers.

Answered By: Yann Vernier

A nice way to do this in Python is using bitwise operations. For example, for 32-bit values:

def s32(value):
    return -(value & 0x80000000) | (value & 0x7fffffff)

Applying this to your values:

>>> s32(a)
398969966
>>> s32(b)
-1051154348

What this function does is sign-extend the value so it’s correctly interpreted with the right sign and value.

Python is a bit tricky in that it uses arbitrary precision integers, so negative numbers are treated as if there were an infinite series of leading 1 bits. For example:

>>> bin(-42 & 0xff)
'0b11010110'
>>> bin(-42 & 0xffff)
'0b1111111111010110'
>>> bin(-42 & 0xffffffff)
'0b11111111111111111111111111010110'
Answered By: dcoles

2^31 = 0x80000000 (sign bit, which in two’s compliment represents -2^31)
2^31-1 = 0x7fffffff (all the positive bits)

and hence (n & 0x7fffffff) – (n & 0x80000000) will apply the sign correctly

you could even do, n – ((n & 0x80000000)<<1) to subtract the msb value twice

or finally there’s, (n & 0x7fffffff) | -(n & 0x80000000) to just merge the negative bit, not subtract

def signedHex(n): return (n & 0x7fffffff) | -(n & 0x80000000)

signedHex = lambda n: (n & 0x7fffffff) | -(n & 0x80000000)
Answered By: Puddle

why not using ctypes ?

>>> import ctypes
>>> a = 0x17c7cc6e
>>> ctypes.c_int32(a).value
398969966
>>> b = 0xc158a854
>>> ctypes.c_int32(b).value
-1051154348
Answered By: Roman
value=input("enter hexa decimal value for getting compliment values:=")
highest_value="F"*len(value)
resulting_decimal=int(highest_value,16)-int(value,16)
ones_compliment=hex(resulting_decimal)
twos_compliment=hex(r+1)
print(f'ones compliment={ones_compliment}n twos complimet={twos_compliment}')
Answered By: renrael_yzal

Another modern solution:

>>> h = 0xc158a854
>>> int.from_bytes(bytes.fromhex(hex(h)[2:]), byteorder='big', signed=True)
-1051154348
Answered By: Ben Smyth
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.