首页 > 解决方案 > 将整数转换为半字节,`to_bytes()`?

问题描述

我有一个整数列表:

var = [1, 5, 4, 17, 231, 89]

如果我想将其转换为字节列表,我可以这样做:

[(i).to_bytes(1, byteorder='big') for i in var]

由于 in 中的每个值var都小于 256,因此每个整数可以容纳一个字节。但是,如果我有另一个清单,请说:

var = [1, 2, 15, 12]

这可以将一个整数放入半个字节,或者更准确地说是我正在寻找的,每个字节适合两个整数。

如果可能,我如何指定将两个整数组合成一个字节,既往又往?

如下所示:

var1 = [1, 5, 4, 17, 231, 89]
var2 = [1, 2, 15, 12]

def foo(var):
  if max(var) < 2**4:
    num_bytes = 0.5
  elif max(var) < 2**8:
    num_bytes = 1
  elif max(var) < 2**16:
    num_bytes = 2

  if num_bytes >= 1:
    return [(i).to_bytes(num_bytes, byteorder='big') for i in var], num_bytes
  elif num_bytes = 0.5:
    # convert var to list of nybbles
    # combine two nybbles to a byte
    # create list of bytes (length is half length of var)
    # return it and num_bytes

def unfoo(var, num_bytes):
  if num_bytes >= 1:
    print([int.from_bytes(i, 'big') for i in var])
  elif num_bytes = 0.5:
    # print original list of integers again

我想将整数列表转换为字节列表,但是如果可以将两个 nybbles 拟合为一个字节,然后再进行转换。

期望的结果是:

a, b = foo(var1)
unfoo(a, b) # prints [1, 5, 4, 17, 231, 89]

a, b = foo(var2)
unfoo(a, b) # prints [1, 2, 15, 12]

我不想要一个最小位数的列表来代表一个数字。请注意max(list):如果列表中的所有值都可以是 8 位,则将其调整为 8 位;如果所有值都可以是 16 位,则适合 16 位;如果所有值都可以是 nybble,则将两个 nybble 对组成一个字节列表。

基本上,如果我有两个整数可以分别放入一个 nybble 中,我如何将它们连接成一个字节?如果我知道需要将字节拆分为两个,我该如何拆分?我总是可以假设原始列表可以被 2 整除。

标签: pythontype-conversionbytebit

解决方案


您需要弄清楚一个字节可以容纳多少个数字。然后,您需要将每个数字移动正确的数量并创建一个包含组合数字的新列表。假设你可以在一个字节中放入两个数字,你会得到new_number = (old_num1 << 4) + old_num2

def foo(var):
    num_bytes = math.ceil(1 + max(math.log2(x) for x in var)) / 8
    if num_bytes >= 1:
        num_bytes = int(num_bytes)
        return [(i).to_bytes(num_bytes, byteorder='big') for i in var], num_bytes
    elif num_bytes == 0.5:
        shift_bits = 4 # or generally, int(num_bytes * 8) 
        new_list = [(a << shift_bits) + b for a, b in zip(var[::2], var[1::2])]
        return [(i).to_bytes(1, byteorder='big') for i in new_list], num_bytes

unfoo,您需要执行此操作的逆操作:当 时,我们可以找到您在函数num_bytes < 1中移动的位数。foo()按照与前面的解释相同的名称,并给出new_number,我们可以得到old_num2作为最低有效四位(由 找到new_number & mask)并且old_num1是最高有效四位(由 找到new_number >> shift_bits

def unfoo(var, num_bytes):
    if num_bytes >= 1:
        return [int.from_bytes(i, 'big') for i in var]
    elif num_bytes == 0.5:
        new_list = [int.from_bytes(i, 'big') for i in var]
        ret = []
        shift_bits = 4 # in general: int(num_bytes * 8)
        mask = int(2**shift_bits - 1)
        for i in new_list:
            b = i & mask
            a = (i >> shift_bits) & mask
            ret.append(a)
            ret.append(b)
        return ret

检查这是否有效:

var1 = [1, 5, 4, 17, 231, 89]
var2 = [1, 2, 15, 12]
        
a, b = foo(var1)
c = unfoo(a, b) # prints [1, 5, 4, 17, 231, 89]

print(var1)
print(c)


a2, b2 = foo(var2)
c2 = unfoo(a2, b2) # prints [1, 2, 15, 12]
print(var2)
print(c2)

给出预期的输出:

[1, 5, 4, 17, 231, 89]
[1, 5, 4, 17, 231, 89]
[1, 2, 15, 12]
[1, 2, 15, 12]

推荐阅读