【问题标题】:Efficient Division by Least Significant Bit set in C/C++C/C++ 中设置的最低有效位的高效除法
【发布时间】:2014-03-26 17:52:52
【问题描述】:

我想尽快执行以下操作

x / LSB(x)  

其中x 是编译时未知的整数值,LSB(x) = x & -x。 (或者,该操作相当于 even 除以 2 合理 可移植的解决方案(没有编译器内在函数/内置函数像 GCC 的 __builtin_clz 或类似的)。

我担心的是下面的简单实现

x / (x & -x)

仍然会导致昂贵的除法,因为编译器可能无法意识到除法实际上相当于右移除数中尾随零的数量。

如果我的担忧是合理的,那么实施它的更有效方法是什么?

我希望有一个解决方案可以轻松扩展到 32 位、64 位、128 位等大小的整数类型...

【问题讨论】:

  • 据我所知,您还不能真正做到这一点,除非使用一堆预处理器来选择正确的内在函数。 N3864 会有所帮助..
  • 您是用 C 还是 C++ 编写代码?此外,编译器通常很擅长发现这些东西。
  • C++。我主要关心 GCC、clang 和 MSVC++。
  • 偶数除法是什么意思?我看不出除以 2
  • 偶数除法 = 除法无余数。

标签: c++ c performance integer bit-manipulation


【解决方案1】:

怎么样

x >>= ffs(x)-1;

ffs 函数符合 4.3BSD,POSIX.1-2001。

x 为 0 时无效。

【讨论】:

  • int _ffs = ffs(x); x >>= _ffs - !!_ffs; 之类的东西也应该为零..
  • 我很确定 BSD 和 POSIX 都不是 C 或 C++。
  • FFS...他们不能给它一个更好的名字吗?啊哈
【解决方案2】:

如果您不想依赖 CLZ(计算前导零)硬件指令,您可以按照this answer 中的说明计算前导零。查找和乘以幻数非常快。我将在这里重新发布代码:

unsigned x;  // input to clz
unsigned c;  // output of clz
static const unsigned MultiplyDeBruijnBitPosition[32] = 
{
  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
  31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
c = MultiplyDeBruijnBitPosition[((unsigned)((x & -x) * 0x077CB531U)) >> 27];

计算完前导零后,您就不再需要使用除法指令了。相反,您可以将值右移c。也就是(去掉一个不需要的临时值),代码变成这样:

static const unsigned MultiplyDeBruijnBitPosition[32] = 
{
  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
  31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};

x >>= MultiplyDeBruijnBitPosition[((unsigned)((x & -x) * 0x077CB531U)) >> 27]; // x /= LSB(x)  

【讨论】:

    猜你喜欢
    • 2013-11-13
    • 2020-09-07
    • 2015-09-22
    • 2017-11-18
    • 2010-10-19
    • 2011-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多