将 std::vector<unsigned int> 解释为位向量高效算法?
Interpreting a std::vector<unsigned int> as bitvector - efficient algorithm?
我要翻译
std::vector<unsigned int> numbers
作为位向量,即numbers[0]
的MSB是第1位,numbers[1]
的MSB是第33位,依此类推。我想在这个向量中找到 Ones 的所有序列,并将相应的位置存储在数据结构中。 (这里也定义了一个一个作为序列)
例如:我将值 15 和 112 存储在数字中。因此第 29 到 32 位和第 58 到 60 位等于 1。
挑战在于优化此功能的运行时间。
这是我对如何处理这个问题的想法:我考虑使用两个 for 循环。第一个循环遍历 "numbers" 的元素(我们称它为 element_loop),而第二个循环用于计算单个元素中所有 One 的位置(我们称它为 bit_loop).为此,我想到了检测序列的 "rising" 和 "falling edges"。
在每个 bit_loop 循环的开始,掩码被初始化为十六进制。值 0x80000000
。使用此掩码,我检查第 1 位是否等于 1。如果是,则存储当前位置 (0)。接下来,二进制表示的掩码“1000...”用于检测下一个循环中的"falling edge"。如果否,掩码将向右移动一位“0100...”以便在下一个循环中检测到 "rising edge"。 (我只关心那两个加粗的数字)
检测到边缘后,我会存储当前位置并以适当的方式将掩码移动一位。因此,在 pos 之后。 edge (01) 我切换到 neg。边缘检测(10),反之亦然。在遍历 32 位无符号数时,我将所有边缘位置存储在某种向量中。这个向量可以是 2-dim。数组,第一列是一个序列的开始,第二列是序列的结尾。此外,我需要对从一个元素到下一个元素的营业额进行一些特殊处理。
这是我的一般性问题:您如何看待这种方法?有没有办法更有效地处理这个问题?非常感谢您的提前帮助。
本
有多种按位技巧可以有效地进行位扫描,但如果您使用的是 C++,则可以利用 std::bitset
or boost::dynamic_bitset
中的任何一个来迭代位位置。不过,您描述的算法会针对每个块向后迭代,因此您可能希望使用 32 - (32 - i)
.
之类的东西来反转您的位置
根据体系结构,每个位大约需要一个周期。
有一些有效的(恒定时间)方法可以使用特殊的处理器指令或各种巧妙的技巧(例如,参见 Position of least significant bit that is set)来查找字中的第一个位集。
稍加小心,您可以向后工作并使用它们扫描第一个,然后进行一些屏蔽和位翻转并搜索下一个零,依此类推。
这个可能给你一个更快的算法,特别是如果序列平均很长,所以快速扫描的收益超过了位旋转的成本。
我要翻译
std::vector<unsigned int> numbers
作为位向量,即numbers[0]
的MSB是第1位,numbers[1]
的MSB是第33位,依此类推。我想在这个向量中找到 Ones 的所有序列,并将相应的位置存储在数据结构中。 (这里也定义了一个一个作为序列)
例如:我将值 15 和 112 存储在数字中。因此第 29 到 32 位和第 58 到 60 位等于 1。 挑战在于优化此功能的运行时间。
这是我对如何处理这个问题的想法:我考虑使用两个 for 循环。第一个循环遍历 "numbers" 的元素(我们称它为 element_loop),而第二个循环用于计算单个元素中所有 One 的位置(我们称它为 bit_loop).为此,我想到了检测序列的 "rising" 和 "falling edges"。
在每个 bit_loop 循环的开始,掩码被初始化为十六进制。值 0x80000000
。使用此掩码,我检查第 1 位是否等于 1。如果是,则存储当前位置 (0)。接下来,二进制表示的掩码“1000...”用于检测下一个循环中的"falling edge"。如果否,掩码将向右移动一位“0100...”以便在下一个循环中检测到 "rising edge"。 (我只关心那两个加粗的数字)
检测到边缘后,我会存储当前位置并以适当的方式将掩码移动一位。因此,在 pos 之后。 edge (01) 我切换到 neg。边缘检测(10),反之亦然。在遍历 32 位无符号数时,我将所有边缘位置存储在某种向量中。这个向量可以是 2-dim。数组,第一列是一个序列的开始,第二列是序列的结尾。此外,我需要对从一个元素到下一个元素的营业额进行一些特殊处理。
这是我的一般性问题:您如何看待这种方法?有没有办法更有效地处理这个问题?非常感谢您的提前帮助。
本
有多种按位技巧可以有效地进行位扫描,但如果您使用的是 C++,则可以利用 std::bitset
or boost::dynamic_bitset
中的任何一个来迭代位位置。不过,您描述的算法会针对每个块向后迭代,因此您可能希望使用 32 - (32 - i)
.
根据体系结构,每个位大约需要一个周期。
有一些有效的(恒定时间)方法可以使用特殊的处理器指令或各种巧妙的技巧(例如,参见 Position of least significant bit that is set)来查找字中的第一个位集。
稍加小心,您可以向后工作并使用它们扫描第一个,然后进行一些屏蔽和位翻转并搜索下一个零,依此类推。
这个可能给你一个更快的算法,特别是如果序列平均很长,所以快速扫描的收益超过了位旋转的成本。