【发布时间】:2018-07-26 22:09:44
【问题描述】:
我需要对等大小的小整数数组做大量简单的代数。这些操作仅包含三种类型:(i)添加数组和(ii)按元素减去数组,以及(iii)比较一个数组中的所有元素是否不小于/大于另一个数组中的对应元素。
为了提高缓存局部性和计算速度,我将每个数组的小整数逐位填充到一定数量的 64 位整数中。使用的 64 位整数的数量由分配给数组元素的位数决定。让a[j] 表示一个数组元素。我为a[j] 设计的位包括(i)可以保持最大绝对值a[j] 在计算过程中可能达到的位,(ii)符号位,以及(iii)位符号位的左边。最左边的位保存来自右边的可能进位,并在加法或减法后归零。
下面是两个 64 位整数相加、相减和比较的玩具示例,每个整数包含五个小整数:前 10 位、接下来的 5 位、接下来的 10 位、接下来的 13 位和接下来的 20 位。其余位无用,设置为0。
// leftmostBitMask =
// 0b0111111111011110111111111011111111111101111111111111111111000000
// ^ ^ ^ ^ ^
// leftmost
std::size_t add(std::size_t x, std::size_t y, std::size_t leftmostBitMask)
{
return (x + y) & leftmostBitMask;
}
std::size_t minus(std::size_t x, std::size_t y, std::size_t leftmostBitMask)
{
return (x - y + ((~leftmostBitMask) << 1)) & leftmostBitMask;
}
bool notAllGreaterEqual(std::size_t x, std::size_t y, std::size_t leftmostBitMask)
{
// return (minus(x, y, leftmostBitMask) & (leftmostBitMask >> 1)) == 0;
return (x - y) & ((~leftmostBitMask) >> 1);
}
我的算法看起来很复杂,尤其是比较函数。有更快的解决方案吗?
谢谢!
顺便说一句,SIMD 不是我所描述的。我的问题是比 SIMD 低一级的优化。
更多背景:这个想法服务于多维空间中相当复杂的搜索算法。我们观察到不同维度的值大小之间存在很大差异。例如,在计算一个重要的 6 维测试用例时,一个维度的绝对值可能达到 50000,而其他所有维度都远低于 1000。如果没有整数压缩,每个对象需要一个大小为 6 的 32 位数组,而整数压缩会减少维数为 1(64 位整数)。这种减少促使我考虑填充整数..
【问题讨论】:
-
工作代码的性能问题在Code Review的范围内。
-
您应该使用位旋转与不使用位旋转来分析您的压缩。通常,位操作会带走压缩带来的任何速度优势。让处理器用它的字长来发挥它的魔力。
-
与其压缩,不如尝试优化。将编译器的优化设置为最大速度。接下来,组织您的数据以进行数据缓存优化。另外,尝试从数组中加载许多临时变量,然后处理它们。这将利用处理器的缓存能力。如果将临时变量声明为
const,编译器可以将它们放入寄存器中,从而提高性能。 -
这里的想法是编写代码,以便编译器可以执行最佳优化。例如,考虑循环展开。如果您为循环展开编码,编译器可能能够发出并行处理指令。
-
顺便说一句,这被称为 SWAR,所以现在您可以搜索一些内容。已有大量工作。
标签: c++ arrays bit-manipulation