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

). enter image description here

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.): enter image description here

+3


source to share


2 answers


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

      

+1


source


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?

0


source







All Articles