2

I am new to hexadecimals and couldn't find any similar previous posts. I have a hexadecimal string 50f116bcf, b3b4d25d0, for example, that is known to be a 36-bit integer. Not sure if it's signed or unsigned. I was wondering how I can go about converting the hexadecimal to 38-bit integer to two 18-bit integers in python.

I saw in this post about converting hex to 16-bit signed integer using

def twos_complement(hexstr,bits):
     value = int(hexstr,16)
     if value & (1 << (bits-1)):
         value -= 1 << bits
     return value

twos_complement('FFFE',16)
-2

Would this generalize to a 38-bit integer as well twos_complement('b3b4d25d0',38)?

For splitting an integer, I saw this post splitting a 16-bit int (x variable) to two 8-bit using

c = (x >> 8) & 0xff
f = x & 0xff

(1030333333 >> 8) & 0xff
163
(1030333333 >> 8) 
4024739

Can this also be generalized to splitting a known 38-bit integer to two 16-bit integer using the method below?

c = (x >> 16) & 0xff
f = x & 0xff
pairwiseseq
  • 313
  • 2
  • 13

2 Answers2

2

Assuming that a hex-string represents a positive integer you can just modify your last two lines into

>>> value = 0x50f116bcf
>>> msb = (value >> 18) & (2**18 - 1)
>>> lsb = value & (2**18 - 1)

# and convert (msb, lsb) back into value by using the binary OR 
>>> (msb << 18) | lsb == value
True

or generalize this idea and use the following function

def bin_grouper(value, bits):
    """bin_grouper(0b1011010, 3) --> 001 011 010"""
    import math
    num = math.ceil(value.bit_length() / bits)  # number of blocks
    mask = 2**bits - 1
    blocks = [(value >> idx*bits) & mask for idx in range(num)]
    fmtstr = f'{{:0{bits}b}}'
    return [fmtstr.format(v) for v in reversed(blocks)]

in order split a 36-bit number into two 18-bit numbers:

>>> bin_grouper(0x50f116bcf, 18)
['010100001111000100', '010110101111001111']

# or

>>> bin_grouper(int('50f116bcf', 16), 18)
['010100001111000100', '010110101111001111']

In order to compare the result you can convert the 0x50f116bcf into a 36-bit binary string and test the upper 18-bits (msb) and the lower 18-bits (lsb):

>>> bstr = f'{0x50f116bcf:036b}'
>>> bstr
'010100001111000100010110101111001111'

>>> blocks = bin_grouper(0x50f116bcf, 18)
>>> blocks[0] == bstr[:18] == f'{msb:018b}'
True
>>> blocks[1] == bstr[18:] == f'{lsb:018b}'
True
fhgd
  • 402
  • 2
  • 10
  • 1
    Can you show him how to get those two 18 bit numbers back to 36 bit pls? :-) Nice post btw. I think that would help him as he can confirm the results – oppressionslayer Nov 28 '19 at 01:24
  • FYI: The ceil operation can be [replaced](https://stackoverflow.com/a/54585138/5599281) with `num = -(value.bit_length() // -bits)` – fhgd Nov 28 '19 at 01:39
  • Thanks fhgd, many answers related to this question on stackoverflow aren't very helpful, i think your answer will help many who search on the topic. – oppressionslayer Nov 28 '19 at 02:13
0

Here's a base converter:

def getbasetasifintisbaset(orig,basefrom=10, baseto=16):
   num=orig
   result = 0
   i=0
   while num != 0:
       result += (num % basefrom) * (baseto ** i) 
       num //=basefrom
       i += 1
   return result 

getbasetasifintisbaset(100,10,16)                                                                                                                                   
#256

getbasetasifintisbaset(256,16,10)                                                                                                                                   
#100
oppressionslayer
  • 6,942
  • 2
  • 7
  • 24