我需要使用以下算法从流中读取数据:
-对流中所有连续的设置位("1"s)进行计数。
-然后,从流中再读取k个比特。K是可变的,在整个程序中都会发生变化。让我们调用读取数据"m">
解码后的数字就是
number = (consecutive_set_bits << k) + m;
这个算法执行的次数非常多。正因为如此,这段代码尽可能快是至关重要的。
主要问题是,1字节、2字节、4字节等集合中的编码数是可变的,因此一个微不足道的实现(我现在脑子里唯一的实现)需要一个从流中读取单个比特的循环。在最坏的情况下,对于一个编码系数,我在循环中有14次迭代。
我能以某种方式避免这个循环吗?
顺序提取单个位的想法还不错。如果做得好,它可能几乎和任何其他解决方案一样快。
粒度g的流中任意位置的比特序列,例如,对于(16比特)word
s的流,g=16,可以在大小为g的块上逐块处理。
为了从流中提取位置s
到e
(具有(e - s) <= g
)处的比特作为"右对齐"数字,示例实现可以是:
shift = s % g
lowerBits = data[ floor( s / g ) ] >> shift
upperBits = data[ floor( e / g ) ] << (g - shift)
bitSequence = (lowerBits | upperBits) & ( (1 << (e-s)) -1 )[*]
[*]最后一项只屏蔽了我们可能得到的任何不需要的高位,并使它们在最终结果中成为0
。
(小心数据的尾数:)
这是否真的会加速事情的发展还不能确定。(这取决于正在处理的数据、底层计算硬件、使用的编译器。注意,需要一些除法和一个模运算,这可能会显著减慢算法的速度。)
以相同的方式可以非常有效地逐个地提取比特。例如:
blockIndex = floor( bitPosition / g )
bitIndex = bitPosition % g
nextBit = (data[ blockIndex ] >> bitIndex) & 1
如果并且当bitPosition
总是仅递增1时,这当然可以被优化以避免blockIndex
和bitIndex
的重新计算。
另一种常见的方法是使用变量"掩码"来提取单个比特:
mask = 1
index = 0
while ( not all bits read ) {
block = data[index]
if ( mask & block != 0 ) {
// a 1 was encountered
} else {
// a 0 was encountered
}
mask = mask << 1
if ( mask == 0 ) {
mask = 1
index = index + 1
}
}
请注意mask
是如何用于屏蔽当前位并跟踪何时前进到下一个数据块的。为了实现这一点,mask
当然必须与数据块具有相同的宽度g
。
综上所述:
我认为,在一般情况下,该解决方案不会比每读取一位一次循环迭代更高效,任何优化都只会在某个方向上略微改变性能。