使用 Python 的 Base-2(二进制)表示

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/187273/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 19:37:46  来源:igfitidea点击:

Base-2 (Binary) Representation Using Python

python

提问by Gregg Lind

Building on How Do You Express Binary Literals in Python, I was thinking about sensible, intuitive ways to do that Programming 101 chestnut of displaying integers in base-2 form. This is the best I came up with, but I'd like to replace it with a better algorithm, or at least one that should have screaming-fast performance.

建立在How Do You Express Binary Literals in Python 的基础上,我正在考虑明智、直观的方法来实现以 2 进制形式显示整数的编程 101 栗子。这是我想出的最好的,但我想用更好的算法替换它,或者至少是一个应该具有超快性能的算法。

def num_bin(N, places=8):
    def bit_at_p(N, p):
        ''' find the bit at place p for number n '''
        two_p = 1 << p   # 2 ^ p, using bitshift, will have exactly one
                         # bit set, at place p
        x = N & two_p    # binary composition, will be one where *both* numbers
                         # have a 1 at that bit.  this can only happen 
                         # at position p.  will yield  two_p if  N has a 1 at 
                         # bit p
        return int(x > 0)

    bits =  ( bit_at_p(N,x) for x in xrange(places))
    return "".join( (str(x) for x in bits) )

    # or, more consisely 
    # return "".join([str(int((N & 1 << x)>0)) for x in xrange(places)])

回答by Brian

For best efficiency, you generally want to process more than a single bit at a time. You can use a simple method to get a fixed width binary representation. eg.

为了获得最佳效率,您通常希望一次处理多个位。您可以使用一种简单的方法来获得固定宽度的二进制表示。例如。

def _bin(x, width):
    return ''.join(str((x>>i)&1) for i in xrange(width-1,-1,-1))

_bin(x, 8) will now give a zero padded representation of x's lower 8 bits. This can be used to build a lookup table, allowing your converter to process 8 bits at a time (or more if you want to devote the memory to it).

_bin(x, 8) 现在将给出 x 的低 8 位的零填充表示。这可用于构建查找表,允许您的转换器一次处理 8 位(如果您想将内存用于它,则可以处理更多位)。

_conv_table = [_bin(x,8) for x in range(256)]

Then you can use this in your real function, stripping off leading zeroes when returning it. I've also added handling for signed numbers, as without it you will get an infinite loop (Negative integers conceptually have an infinite number of set sign bits.)

然后你可以在你的实际函数中使用它,在返回它时去掉前导零。我还添加了对有符号数的处理,因为没有它你会得到一个无限循环(负整数在概念上有无限数量的符号位。)

def bin(x):
    if x == 0: 
        return '0' #Special case: Don't strip leading zero if no other digits
    elif x < 0:
        sign='-'
        x*=-1
    else:
        sign = ''
    l=[]
    while x:
        l.append(_conv_table[x & 0xff])
        x >>= 8
    return sign + ''.join(reversed(l)).lstrip("0")

[Edit] Changed code to handle signed integers.
[Edit2] Here are some timing figures of the various solutions. bin is the function above, constantin_bin is from Constantin's answerand num_bin is the original version. Out of curiosity, I also tried a 16 bit lookup table variant of the above (bin16 below), and tried out Python3's builtin bin() function. All timings were for 100000 runs using an 01010101 bit pattern.

[编辑] 更改代码以处理有符号整数。
[Edit2] 以下是各种解决方案的一些时序图。bin 是上面的函数,constantin_bin 来自康斯坦丁的答案,num_bin 是原始版本。出于好奇,我还尝试了上面的 16 位查找表变体(下面的 bin16),并尝试了 Python3 的内置 bin() 函数。所有计时都是使用 01010101 位模式运行 100000 次。

Num Bits:              8       16       32       64      128      256
---------------------------------------------------------------------
bin                0.544    0.586    0.744    1.942    1.854    3.357 
bin16              0.542    0.494    0.592    0.773    1.150    1.886
constantin_bin     2.238    3.803    7.794   17.869   34.636   94.799
num_bin            3.712    5.693   12.086   32.566   67.523  128.565
Python3's bin      0.079    0.045    0.062    0.069    0.212    0.201 

As you can see, when processing long values using large chunks really pays off, but nothing beats the low-level C code of python3's builtin (which bizarrely seems consistently faster at 256 bits than 128!). Using a 16 bit lookup table improves things, but probably isn't worth it unless you really need it, as it uses up a large chunk of memory, and can introduce a small but noticalbe startup delay to precompute the table.

正如您所看到的,当使用大块处理长值时确实有回报,但没有什么比 python3 内置的低级 C 代码更好的了(奇怪的是,256 位似乎始终比 128 位更快!)。使用 16 位查找表可以改善情况,但除非您真的需要它,否则可能不值得,因为它会占用大量内存,并且可能会引入一个很小但值得注意的启动延迟来预计算表。

回答by Constantin

Not screaming-fast, but straightforward:

不是快速尖叫,而是直截了当:

>>> def bin(x):
...     sign = '-' if x < 0 else ''
...     x = abs(x)
...     bits = []
...     while x:
...             x, rmost = divmod(x, 2)
...             bits.append(rmost)
...     return sign + ''.join(str(b) for b in reversed(bits or [0]))

It is also faster than num_bin:

它也比num_bin

>>> import timeit
>>> t_bin = timeit.Timer('bin(0xf0)', 'from __main__ import bin')
>>> print t_bin.timeit(number=100000)
4.19453350997
>>> t_num_bin = timeit.Timer('num_bin(0xf0)', 'from __main__ import num_bin')
>>> print t_num_bin.timeit(number=100000)
4.70694716882

Even more, it actually works correctly (for my definition of "correctness" :)):

更重要的是,它实际上工作正常(对于我对“正确性”的定义:)):

>>> bin(1)
'1'
>>> num_bin(1)
'10000000'