user3284986
user3284986

Reputation: 29

How to keep leading zeros in binary integer (python)?

I need to calculate a checksum for a hex serial word string using XOR. To my (limited) knowledge this has to be performed using the bitwise operator ^. Also, the data has to be converted to binary integer form. Below is my rudimentary code - but the checksum it calculates is 1000831. It should be 01001110 or 47hex. I think the error may be due to missing the leading zeros. All the formatting I've tried to add the leading zeros turns the binary integers back into strings. I appreciate any suggestions.

    word = ('010900004f')

    #divide word into 5 separate bytes
    wd1 = word[0:2] 
    wd2 = word[2:4]
    wd3 = word[4:6]
    wd4 = word[6:8]
    wd5 = word[8:10]

    #this converts a hex string to a binary string
    wd1bs = bin(int(wd1, 16))[2:] 
    wd2bs = bin(int(wd2, 16))[2:]
    wd3bs = bin(int(wd3, 16))[2:]
    wd4bs = bin(int(wd4, 16))[2:]

    #this converts binary string to binary integer
    wd1i = int(wd1bs)
    wd2i = int(wd2bs)
    wd3i = int(wd3bs)
    wd4i = int(wd4bs)
    wd5i = int(wd5bs)

    #now that I have binary integers, I can use the XOR bitwise operator to cal cksum
    checksum = (wd1i ^ wd2i ^ wd3i ^ wd4i ^ wd5i)

    #I should get 47 hex as the checksum
    print (checksum, type(checksum))

Upvotes: 2

Views: 3415

Answers (3)

Kei Minagawa
Kei Minagawa

Reputation: 4501

Just modify like this.

before:

wd1i = int(wd1bs)
wd2i = int(wd2bs)
wd3i = int(wd3bs)
wd4i = int(wd4bs)
wd5i = int(wd5bs)

after:

wd1i = int(wd1bs, 2)
wd2i = int(wd2bs, 2)
wd3i = int(wd3bs, 2)
wd4i = int(wd4bs, 2)
wd5i = int(wd5bs, 2)

Why your code doesn't work?

Because you are misunderstanding int(wd1bs) behavior. See doc here. So Python int function expect wd1bs is 10 base by default. But you expect int function to treat its argument as 2 base. So you need to write as int(wd1bs, 2)


Or you can also rewrite your entire code like this. So you don't need to use bin function in this case. And this code is basically same as @Hyperboreus answer. :)

w = int('010900004f', 16)
w1 = (0xff00000000 & w) >> 4*8
w2 = (0x00ff000000 & w) >> 3*8
w3 = (0x0000ff0000 & w) >> 2*8
w4 = (0x000000ff00 & w) >> 1*8
w5 = (0x00000000ff & w)

checksum = w1 ^ w2 ^ w3 ^ w4 ^ w5

print hex(checksum)
#'0x47'

And this is more shorter one.

import binascii
word = '010900004f'
print hex(reduce(lambda a, b: a ^ b, (ord(i) for i in binascii.unhexlify(word))))
#0x47

Upvotes: 1

Marat
Marat

Reputation: 15738

s = '010900004f'
b = int(s, 16)
print reduce(lambda x, y: x ^ y, ((b>> 8*i)&0xff for i in range(0, len(s)/2)), 0)

Upvotes: 1

Hyperboreus
Hyperboreus

Reputation: 32429

Why use all this conversions and the costly string functions?

(I will answer the X part of your XY-Problem, not the Y part.)

def checksum (s):
    v = int (s, 16)
    checksum = 0
    while v:
        checksum ^= v & 0xff
        v >>= 8
    return checksum

cs = checksum ('010900004f')
print (cs, bin (cs), hex (cs) )

Result is 0x47 as expected. Btw 0x47 is 0b1000111 and not as stated 0b1001110.

Upvotes: 5

Related Questions