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

我有点计数方法,我想尽快做。 我想尝试下面的Bit Twiddling Hacks算法,但我不知道C.什么是’type T’什么是py等价于(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 

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

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

 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所说:个人资料!

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

(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位。 没有溢出exception。 许多有点麻烦的算法依赖于此。 但是(a)Python的intlong是签名的(b)旧的Python 2.X会引发exception,最近的Python 2.Xs会默默地将int提升为long和Python 3.x int == Python 2.x long

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

使用long而不是int对效率没有太大作用。 您会注意到,即使输入为0,32位算法也会返回一个long答案,因为32位all_ones很long