我需要使用以下算法从流中读取数据:
从流中计算所有连续设置位(“1”)。
- 然后,从流中读取更多位。 K是可变的,并在整个计划中发生变化。让我们调用读取数据“m”
然后解码的数字是
number = (consecutive_set_bits << k) + m;
该算法执行的次数非常多。因此,这段代码尽可能快地至关重要。
主要问题是1字节,2字节,4字节等设置中的编码数量是可变的,因此一个简单的实现(我现在唯一的一个)需要一个循环从流中读取单个位。在最坏的情况下,我通过循环只进行了14次迭代,只有一个编码系数。
我可以以某种方式避免这种循环吗?
答案 0 :(得分:0)
顺序提取单个位的想法并不算太糟糕。如果做得好,它可能几乎与任何其他解决方案一样快。
粒度流 g 中任意位置的位序列,例如,对于(16位)word
的流,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
。
(小心数据的结束:))
一般来说,这是否会真正加快速度。 (取决于正在处理的数据,底层计算硬件,使用的编译器和c。请注意,需要一些分区和一个模运算,这可能会显着降低算法速度。)
逐个提取位可以以相同的方式非常有效地完成。例如:
blockIndex = floor( bitPosition / g )
bitIndex = bitPosition % g
nextBit = (data[ blockIndex ] >> bitIndex) & 1
这当然可以进行优化,以避免在blockIndex
始终仅增加1的情况下重新计算bitIndex
和bitPosition
。
另一种常见的方法是使用变量'mask'来提取单个位:
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
。
总结一下:
我认为,在一般情况下,解决方案可能比每位读取的循环迭代更有效,并且任何优化只会稍微改变一个方向或另一个方向的性能。