用于搜索位阵列以查找连续设置/清除位的快速代码
Fast code for searching bit-array for contiguous set/clear bits?
是否有一些速度相当快的代码可以帮助我快速搜索大位图(几兆字节)中连续零位或一位的运行?
我所说的"相当快"是指可以利用机器单词大小,一次比较整个单词,而不是进行速度慢得可怕的逐位分析(比如vector<bool>
)。
它非常有用,例如搜索卷的位图以获得可用空间(用于碎片整理等)。
Windows有一个RTL_BITMAP
数据结构,可以与其API一起使用。
但我前段时间需要代码,所以我在这里写了它(警告,它有点难看):
https://gist.github.com/3206128
我只对进行了部分测试,所以它可能仍然有错误(尤其是在reverse
上)。但最近的版本(与本版本略有不同)似乎对我有用,所以值得一试。
整个过程的基本操作是能够快速找到一段比特的长度:
long long GetRunLength(
const void *const pBitmap, unsigned long long nBitmapBits,
long long startInclusive, long long endExclusive,
const bool reverse, /*out*/ bool *pBit);
考虑到它的多功能性,其他一切都应该很容易建立在这个基础上。
我尝试包含一些SSE代码,但它并没有显著提高性能。然而,一般来说,代码比逐点分析快很多倍,所以我认为它可能很有用。
测试你是否能以某种方式获得vector<bool>
的缓冲区应该很容易——如果你使用的是Visual C++,那么我提供了一个函数可以帮你做到这一点。如果你发现虫子,请随时告诉我。
我不知道如何直接处理内存字,所以我想出了一个处理字节的快速解决方案;为了方便起见,让我们画出一个计算连续数的算法:
构造两个大小为256的表,在其中为0和255之间的每个数字写入,即字节开头和结尾的尾随1的数量。例如,对于数字167(二进制为10100111),将1放在第一个表中,将3放在第二个表中。让我们称第一张表为BBeg,第二张表为BEnd。然后,对于每个字节b,有两种情况:如果它是255,那么在当前连续的一组一的当前和上加8,就处于一个一的区域中。否则,您将用BBeg[b]位结束一个区域,并用BEnd[b]位开始一个新区域。根据你想要的信息,你可以调整这个算法(这就是为什么我不在这里放任何代码的原因,我不知道你想要什么输出)。
一个缺陷是它不计算一个字节内的(小的)连续一组1。。。
除了这个算法,一个朋友告诉我,如果是磁盘压缩,只需查找0(空磁盘区域)和255(满磁盘区域)之间的字节。这是一种快速的启发式方法,可以构建一个需要压缩哪些块的映射。也许这超出了这个话题的范围。。。
听起来这可能很有用:
http://www.aggregate.org/MAGIC/#Population%20Count%20%28Ones%20Count%29和http://www.aggregate.org/MAGIC/#Leading%20Zero%20Count
你没有说你是否想做某种RLE,或者只是在字节中计数零和一位(比如0b1001应该返回1x1 2x0 1x1)。
查找表加上快速检查的SWAR算法可能会很容易地为您提供这些信息。有点像这样:
byte lut[0x10000] = { /* see below */ };
for (uint * word = words; word < words + bitmapSize; word++) {
if (word == 0 || word == (uint)-1) // Fast bailout
{
// Do what you want if all 0 or all 1
}
byte hiVal = lut[*word >> 16], loVal = lut[*word & 0xFFFF];
// Do what you want with hiVal and loVal
LUT必须根据您的预期算法进行构建。如果你想计算单词中连续的0和1的数量,你可以这样构建:
for (int i = 0; i < sizeof(lut); i++)
lut[i] = countContiguousZero(i); // Or countContiguousOne(i)
// The implementation of countContiguousZero can be slow, you don't care
// The result of the function should return the largest number of contiguous zero (0 to 15, using the 4 low bits of the byte, and might return the position of the run in the 4 high bits of the byte
// Since you've already dismissed word = 0, you don't need the 16 contiguous zero case.
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 有没有办法在c ++中清除空数组,请检查下面的代码以获取说明
- 以下代码运行后,如何在程序再次运行之前清除用户声明的变量 empName
- 用于搜索位阵列以查找连续设置/清除位的快速代码
- 如何清除通用 C++ 代码中的“double”
- 如何清除代码块中的缓冲区
- 在Class::方法中清除破坏代码
- 清除c++构造函数中重复的代码
- 使用一行代码m.s swap(std::stringstream());清除stringstream