Bitwise operation, move the carry bit
The goal is to be able to:
struct.pack('!H', x)
But if x
more than 65535
, then for obvious reasons it will not succeed.
I am not a master with little manipulation, but I figured out that operations <<
would lose any shifted bits. But I have no idea how to extract one or more bits from the binary / byte string and add the carry value to the set of two bytes ending with the carrier bytes.
And I need to move the byte string by 2 bytes each time and sum them over the previous 2 bytes. Sometimes this generates a value greater than 65535
- here I need to extract the carry bit from the result - and perform an operation +
on the result with the carry bit itself (see the picture below).
This is what I am trying to accomplish: (In this case, there was only one carry bit, and as a result, two bytes with bytes will get +1
).
And this is what I have so far:
from struct import unpack, pack
from binascii import *
even_bytes_string = b'\x45\x00\x00\x3c\x1c\x46\x40\x00\x40\x06\xac\x10\x0a\x63\xโโac\x10\x0a\x0c'
result = None
for i in range(0, len(even_bytes_string)-1,2):
if not result:
result = unpack('!H', even_bytes_string[i:i+2])[0]
continue
result += unpack('!H', even_bytes_string[i:i+2])[0]
if result > 65535:
# Got a carry bit.
pass
print(result)
print(pack('!H', result))
I have no idea how to do this quite simply, without converting the result of the append operation to an actual binary string representation ( 11001...
). And then do string manipulation s = s[-16:]+s[:-16]
(simplified), and finally convert it back to a set of 2 bytes. It is not a seam practical, quick or very "correct".
I hope some of you know your way around bit manipulation in Python that could tell me what's the right way to do this. There must be some.
A slightly more confusing picture of what I am trying to accomplish (store the result in 2 bytes, strip off any carrier bits and add them to the result as a "separate" value.):
source to share
The process is simple (x & 0xFFFF) + (x >> 16)
. The operation <<
does not require participation. Here's the runtime example you are citing:
def addwrap16( a, b ):
c = a + b
w = ( c & 0xFFFF ) + ( c >> 16 )
print(' {:04x} -> {:016b}'.format(a, a))
print(' {:04x} -> {:016b}'.format(b, b))
print('{:05x} -> {:017b}'.format(c, c))
print(' {:04x} -> {:016b}'.format(w, w))
print('')
return w
import struct, functools
even_bytes_string = b'\x45\x00\x00\x3c\x1c\x46\x40\x00\x40\x06\xac\x10\x0a\x63\xac\x10\x0a\x0c'
vals = struct.unpack( '!' + 'H' * ( len( even_bytes_string ) // 2 ), even_bytes_string )
result = functools.reduce(addwrap16, vals)
which spits out the following:
4500 -> 0100010100000000
003c -> 0000000000111100
0453c -> 00100010100111100
453c -> 0100010100111100
453c -> 0100010100111100
1c46 -> 0001110001000110
06182 -> 00110000110000010
6182 -> 0110000110000010
6182 -> 0110000110000010
4000 -> 0100000000000000
0a182 -> 01010000110000010
a182 -> 1010000110000010
a182 -> 1010000110000010
4006 -> 0100000000000110
0e188 -> 01110000110001000
e188 -> 1110000110001000
e188 -> 1110000110001000
ac10 -> 1010110000010000
18d98 -> 11000110110011000
8d99 -> 1000110110011001
8d99 -> 1000110110011001
0a63 -> 0000101001100011
097fc -> 01001011111111100
97fc -> 1001011111111100
97fc -> 1001011111111100
ac10 -> 1010110000010000
1440c -> 10100010000001100
440d -> 0100010000001101
440d -> 0100010000001101
0a0c -> 0000101000001100
04e19 -> 00100111000011001
4e19 -> 0100111000011001
source to share
So, this is not the most elegant solution, and not sure if it is really accurate, but it won't break struct.pack()
at least.
Based on @ Tryph's simple question, this is what I came across as a workaround:
from struct import unpack, pack
from binascii import *
even_bytes_string = b'\x45\x00\x00\x3c\x1c\x46\x40\x00\x40\x06\xac\x10\x0a\x63\xโโac\x10\x0a\x0c'
result = None
for i in range(0, len(even_bytes_string)-1,2):
if not result:
result = unpack('!H', even_bytes_string[i:i+2])[0]
continue
result += unpack('!H', even_bytes_string[i:i+2])[0]
if result > 65535:
tmp = pack('!I', result)
carry = unpack('!H', tmp[:2])[0]
result = unpack('!H', tmp[2:])[0]+carry
print(result)
print(pack('!H', result))
Just treats the larger number as Int
instead Short
, this allows me to get two bytes of the pre-byte as carry and append those bytes to the end of the two bytes. It's not elegant, but does it work?
source to share