Skip to main content
 首页 » 编程设计

python之如何将 int 转换为包含二进制表示的列表在 python 中快速

2025年05月04日13三少

目前我有以下版本,但这是我的主要瓶颈,而且速度很慢。

def intToBinary(Input): 
    bStrInput = format(Input, "016b") 
    bStrInput = list(bStrInput) 
    bInput = list(map(int, bStrInput)) 
    return bInput 

关于如何加速此代码的任何想法?

我在 Tensorflow 项目中使用它,用于整数的热编码转换。该函数接受 2 字节整数(在 [0, 65536) 范围内)并输出值为 0 和 1 的整数列表:

>>> intToBinary(50411) 
[1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1] 

结果通过 tInput = torch.tensor(bInput, dtype=torch.uint8) 传递给张量。

请您参考如下方法:

你的版本,略有改进

您的版本可以通过不使用中间变量和列表转换来避免一些操作码:

def intToBinary(Input): 
    return list(map(int, format(Input, "016b"))) 

Pure Python still, bitshifting 选项

但是,您可以通过不先转换为字符串再转换为整数来使其更快。如果您只需要位,则使用位操作:

def int_to_binary(v): 
    return [(v >> i) & 1 for i in range(15, -1, -1)] 

这会将输入整数的位向右移动 15、14 等步,然后用 1 屏蔽掉移位后的整数,以获取每个最右边位的位值时间。

速度比较,使用 1000 个随机整数将方差降低到可接受的水平:

>>> import sys, platform, psutil 
>>> sys.version_info 
sys.version_info(major=3, minor=7, micro=0, releaselevel='final', serial=0) 
>>> platform.platform(), psutil.cpu_freq().current / 1000, psutil.cpu_count(), psutil.virtual_memory().total // (1024 ** 3) 
('Darwin-17.7.0-x86_64-i386-64bit', 2.9, 8, 16) 
>>> from timeit import Timer 
>>> from random import randrange 
>>> testvalues = [randrange(2**16) for _ in range(1000)] 
>>> count, total = Timer("for i in tv: t(i)", "from __main__ import intToBinary as t, testvalues as tv").autorange() 
>>> (total / count) * (10 ** 3)   # milliseconds 
3.2812212200224167 
>>> count, total = Timer("for i in tv: t(i)", "from __main__ import int_to_binary as t, testvalues as tv").autorange() 
>>> (total / count) * (10 ** 3)   # milliseconds 
2.2861225200176705 

因此 int_to_binary() 产生 1000 个结果的速度大约是原来的 1.5 倍,大约需要 2.3 毫秒,而优化的字符串操作版本只需 3.3 多毫秒。

基本循环和函数调用在我的机器上需要 7.4 微秒:

>>> count, total = Timer("for i in tv: pass", "from __main__ import testvalues as tv; t = lambda i: None").autorange() 
>>> (total / count) * (10 ** 3) 
0.007374252940062434 

因此每次调用的基本时间约为 3.27 微秒,而位操作版本为 2.28 微秒。

Numpy 能做什么

如果您使用的是 Tensorflow,您还可以使用 numpy 操作,它可以使用 numpy.unpackbits() function 将 uint8 转换为二进制; uint16 需要是 'viewed'首先是 uint8:

import numpy as np 
 
def int_to_bits_np(v): 
    return np.unpackbits(np.array([v], dtype=np.uint16).view(np.uint8)).tolist() 

这将转换为 numpy 数组,back to a list of Python integers同样,仅在一个值上效率不高:

>>> count, total = Timer("for i in tv: t(i)", "from __main__ import int_to_bits_np as t, testvalues as tv").autorange() 
>>> (total / count) * (10 ** 3) 
2.654717969999183 

比您的版本快,但比移位慢。

Numpy 向量化选项

您可能不想转换回列表,因为这里的 numpy 数组已经为您的张量提供了正确的 dtype。您还可以在大量值 上使用它;比如输入的整1000个整数:

def int_to_bits_array(varray): 
    """Convert an array of uint16 values to binary""" 
    return np.unpackbits(varray.reshape(varray.shape[0], 1).view(np.uint8), axis=1) 

这是方式,方式,方式更快:

>>> testvalues_array = np.array(testvalues, dtype=np.uint16) 
>>> int_to_bits_array(testvalues_array) 
array([[1, 1, 0, ..., 1, 1, 0], 
       [0, 1, 1, ..., 1, 0, 0], 
       [1, 1, 1, ..., 0, 0, 0], 
       ..., 
       [1, 1, 1, ..., 0, 1, 0], 
       [0, 0, 0, ..., 1, 1, 0], 
       [0, 0, 0, ..., 0, 0, 0]], dtype=uint8) 
>>> count, total = Timer("t(tva)", "from __main__ import int_to_bits_array as t, testvalues_array as tva").autorange() 
>>> (total / count) * (10 ** 3)  # milliseconds 
0.007919690339913358 
>>> (total / count) * (10 ** 6)  # microseconds 
7.919690339913359 

是的,这是一步将 1000 个值转换为二进制,在 8 微秒内处理所有值。这会线性增加到更大的数字; 100 万个随机值在 8 毫秒内转换:

>>> million_testvalues_array = np.random.randint(2 ** 16, size=10 ** 6, dtype=np.uint16) 
>>> count, total = Timer("t(tva)", "from __main__ import int_to_bits_array as t, million_testvalues_array as tva").autorange() 
>>> (total / count) * (10 ** 3)  # milliseconds 
7.9162722200271665