【问题标题】:Setting a bit range in an ordinal在序数中设置位范围
【发布时间】:2012-03-25 22:29:13
【问题描述】:

Following my previous question,我需要创建一个由设置为 1 的固定位组成的值。我使用了以下函数:

void MaskAddRange(UINT& mask, UINT first, UINT count)
{
    mask |= ((1 << count) - 1) << first;
}

但是,正如我们所发现的,它对于count = 32 不能正常工作。在这种情况下,1 &lt;&lt; count 的结果理论上是未定义的行为(或结果),实际上在 x86 上它是 1,因为移位操作数被视为模 32。 p>

我也想修复这个表达式,使其在这种极端情况下也能正常工作。最简单/最好/最有效的方法是什么?

通过分支(if?)处理这种特定情况有点简单,虽然丑陋,但我敢打赌它也效率低下。

另一种方法是将移位操作数提升为更大的类型(64 位)。我的意思是:

void MaskAddRange(UINT& mask, UINT first, UINT count)
{
    mask |= (UINT(unsigned __int64(1) << count) - 1) << first;
}

有没有更好的办法?

【问题讨论】:

  • 嗯。你能添加一个简单、简短、简明的函数所需行为的描述吗?我宁愿不必对有问题的代码中的要求进行逆向工程。
  • void MaskAddRange(UINT&amp; mask, UINT first, UINT count){...} 是 C 中的语法错误。也许你的意思是 C++?
  • @wildplasser:是的,我的意思是 C++。我不想标记问题 C++,因为问题本身与 C++ 无关
  • 在 C 中,人们可能会编写类似 mask |= ((1ull &lt;&lt; count) - 1) &lt;&lt; first; 的内容并将其放入“函数样式”宏中,因为 C 不知道引用调用。

标签: c bit-manipulation


【解决方案1】:

除非你能证明它,否则永远不要假设任何事情都是低效的。 if-else 在您的架构+操作系统上可能比升级到 64 位更有效。我认为除了您已经发布的这两个方法之外,没有其他任何理智的方法。

我会选择 if-else,因为它记录了处理极端情况的意图。升级到 64 位并不表示这种意图。

【讨论】:

  • 非常感谢您撰写有关编写高效软件指南的理论文章。然而,在我的特殊情况下,我可以很容易地证明分支比单个 CPU 指令效率低(已经这样做了)。我还认为,一种理智的方法应该是基于“有根据的猜测”假设一些事实,然后进行强制性验证。
  • P.S.我同意使用明确的if-else 实际上是自我记录处理特定极端情况的意图,这有点有价值。 OTOH 更一般地说,我更喜欢写一些本质上涵盖所有极端情况的东西(如果可以的话)。那么就更容易看清程序流程了,不用在心里考虑所有的情况。这通常也会导致更好、更通用的表述。
  • 能否提供给我们您所指的“单CPU指令”?因为您(或霍华德)的功能永远不会是一条指令,我可以保证。但为了缩短讨论时间,让我这样说:在有效支持 64 位整数运算的 CPU 上,您的 64 位促销代码将是最有效的。看看你是如何使用 Windows 的,你可能运行在一个能有效支持 64 位整数运算的 CPU 上。
【解决方案2】:

你可以使用

mask |= (UINT(-1)<<first) & (UINT(-1)>>(32-first-count))

这更复杂,但在任何情况下都应该有效。此表达式相对于其他解决方案的效率可能取决于架构和编译器。

【讨论】:

  • 有趣。但是它很容易出现另一种极端情况,first=0count=0
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-20
相关资源
最近更新 更多