简体   繁体   English

按位运算,移动进位

[英]Bitwise operation, moving a carry bit

The goal is to be able to do: 目标是能够做到:

struct.pack('!H', x)

But if x is greater than 65535 then this will fail for obvious reasons. 但是如果x大于65535那么由于显而易见的原因,这将失败。
I'm not a wizard with bit manipulation but I've understood that << operations will loose any shifted bits. 我不是一个有位操作的向导,但我知道<<操作会松开任何移位的位。 But I have no idea how to extract one or more carrying bits from the binary/bytes string and add the carry value to the set of two bytes trailing the carrying bytes. 但我不知道如何从二进制/字节字符串中提取一个或多个携带位,并将进位值添加到尾随携带字节的两个字节的集合中。

And I need to traverse the bytes string by 2 bytes each time and sum them up against the previous two bytes. 我需要每次遍历字节字符串2个字节,并将它们与前两个字节相加。 Occasionally this will generate a value greater than 65535 - this is where I need to extract the carry bit from the result - and perform a + operation on the result with the carry bit itself (see picture below). 有时这会生成一个大于65535的值 - 这是我需要从结果中提取进位的地方 - 并对进位执行+运算(见下图)。

This is what I'm trying to accomplish: (In this case the carrying bit were only one, and the 2 trailing bytes would get +1 as a result.) 这就是我想要完成的事情:(在这种情况下,携带位只有一个,因此2个尾随字节将获得+1 。) 在此输入图像描述

And this is what I've got 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 literally have no idea how to do this quite simple task, without converting the result of a add operation into actual binary representation in string format ( 11001... ). 我真的不知道如何完成这个非常简单的任务,而不将add操作的结果转换为字符串格式的实际二进制表示( 11001... )。 And then do string manipulation s = s[-16:]+s[:-16] (oversimplified), finally converting it back to a set of 2 bytes. 然后进行字符串操作s = s[-16:]+s[:-16] (过度简化),最后将其转换回一组2个字节。 It doesn't seam practical, fast or very "correct". 它不实用,快速或非常“正确”。

I'm hoping one of you know your way around bit manipulation in Python that could tell me what the proper way of doing this is. 我希望你们中的一个人知道你在Python中进行位操作的方法,可以告诉我这样做的正确方法是什么。 There has to be some. 必须有一些。

A slightly more confusing picture of what I'm trying to accomplish (of keeping result at 2 bytes, cutting away any carrying bits and adding them to result as a "separate" value.): 我想要完成的一个稍微混乱的图片(将结果保持在2个字节,切掉任何携带位并将它们作为“单独”值添加到结果中。): 在此输入图像描述

The process is just (x & 0xFFFF) + (x >> 16) . 该过程只是(x & 0xFFFF) + (x >> 16) The << operation does not need to be involved. <<操作不需要涉及。 Here's an implementation of the worked example you cite: 以下是您引用的工作示例的实现:

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

Ok so this is not the most elegant solution, and not sure it's actually accurate but it doesn't break struct.pack() at least. 好的,所以这不是最优雅的解决方案,并且不确定它实际上是否准确,但它至少不会破坏struct.pack()

Based on a simple question by @Tryph, this is what I came up with as a work-around: 基于@Tryph的一个简单问题,这就是我提出的解决方法:

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))

Simply treats the bigger number as a Int instead of Short , this enables me to get the two prepending bytes as carry, and add those ontop of the trailing two bytes. 简单地将较大的数字视为Int而不是Short ,这使我能够将两个前置字节作为进位,并添加尾随两个字节的ontop。 It's not elegant, but probably works? 它不优雅,但可能有效吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM