Python相当于来自Bit Twiddling Hacks的C代码?

时间:2010-02-14 16:01:09

标签: python c bit-manipulation

我有点计数方法,我想尽快做出来。我想从Bit Twiddling Hacks尝试下面的算法,但我不知道C.什么是'type T',什么是python等价的(T)〜(T)0/3?

  

最佳位的概括   计算整数的方法   位宽高达128(参数化为   类型T)是这样的:

v = v - ((v >> 1) & (T)~(T)0/3);      // temp 
v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      // temp
v = (v + (v >> 4)) & (T)~(T)0/255*15;                      // temp
c = (T)(v * ((T)~(T)0/255)) >> (sizeof(v) - 1) * CHAR_BIT; // count

2 个答案:

答案 0 :(得分:7)

T是整数类型,我假设它是无符号的。由于这是C,它将是固定宽度,可能(但不一定)是8,16,32,64或128中的一个。在该代码示例中重复出现的片段(T)~(T)0仅给出值2 * * N-1,其中N是类型T的宽度。我怀疑代码可能要求N是8的倍数 为了正确操作。

这是将给定代码直接转换为Python,以N为参数化,以位为单位的宽度。

def count_set_bits(v, N=128):
    mask = (1 << N) - 1

    v = v - ((v >> 1) & mask//3)
    v = (v & mask//15*3) + ((v >> 2) & mask//15*3)
    v = (v + (v >> 4)) & mask//255*15
    return (mask & v * (mask//255)) >> (N//8 - 1) * 8

注意事项:

(1)以上仅适用于最多2 ** 128的数字。不过,你可能可以将它推广到更大的数字。

(2)明显效率低下:例如,'mask // 15'计算两次。当然,这对于C来说并不重要,因为编译器几乎肯定会在编译时而不是运行时进行除法,但是Python的窥孔优化器可能不那么聪明。

(3)最快的C方法可能无法转换为最快的Python方法。对于Python速度,您可能应该寻找一种最小化Python按位运算次数的算法。正如Alexander Gessler所说:简介!

答案 1 :(得分:2)

您复制的内容是用于生成代码的模板。将该模板音译为另一种语言并期望它快速运行并不是一个好主意。我们来扩展模板。

(T)〜(T)0表示“与T型匹配的1位”。该算法需要4个掩码,我们将根据我们可能感兴趣的各种T大小计算这些掩码。

>>> for N in (8, 16, 32, 64, 128):
...     all_ones = (1 << N) - 1
...     constants = ' '.join([hex(x) for x in [
...         all_ones // 3,
...         all_ones // 15 * 3,
...         all_ones // 255 * 15,
...         all_ones // 255,
...         ]])
...     print N, constants
...
8 0x55 0x33 0xf 0x1
16 0x5555 0x3333 0xf0f 0x101
32 0x55555555L 0x33333333L 0xf0f0f0fL 0x1010101L
64 0x5555555555555555L 0x3333333333333333L 0xf0f0f0f0f0f0f0fL 0x101010101010101L
128 0x55555555555555555555555555555555L 0x33333333333333333333333333333333L 0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0fL 0x1010101010101010101010101010101L
>>>

您会注意到为32位大小写生成的掩码与硬编码的32位C代码中的掩码相匹配。实现细节:从32位掩码(Python 2.x)中丢失L后缀,并丢失Python 3.x的所有L后缀。

正如你所看到的那样,整个模板和(T)〜(T)0 caper仅仅是混淆的诡辩。简而言之,对于k字节类型,您需要4个掩码:

k bytes each 0x55
k bytes each 0x33
k bytes each 0x0f
k bytes each 0x01

并且最终的移位仅仅是N-8(即8 *(k-1))个比特。旁白:我怀疑模板代码是否真的可以在CHAR_BIT不是8的机器上运行,但是现在这些机器的数量并不多。

更新:将此类算法从C语音转换为Python时,还有另一点会影响正确性和速度。 C算法通常假设无符号整数。在C中,对无符号整数的操作以模2 * N静默工作。换句话说,仅保留最低有效N位。没有溢出异常。许多有点笨拙的算法依赖于此。但是(a)Python的intlong已签名(b)旧的Python 2.X将引发异常,最近的Python 2.X将默默地将int提升为long和Python 3.x int == Python 2.x long

在Python代码中,正确性问题通常至少需要register &= all_ones次。通常需要仔细分析以确定最小的正确掩蔽。

使用long代替int并不能提高效率。您会注意到,即使输入long,32位算法也会返回0个答案,因为32位all_ones是long