【问题标题】:Which algorithm is faster for checking if a bit is set?哪种算法更快地检查是否设置了位?
【发布时间】:2011-09-10 20:22:55
【问题描述】:

我正在制作一款游戏,其中我将大量数据存储在一个整数或长整数中,因为我将拥有大量数据。出于性能原因,我不想使用整个类,也不需要它们。我找到了两种从整数中检索一位的方法。我想知道是否有人知道我应该使用哪个或者哪个更快。

方法:

return (integer & (1 << bit)) != 0;

return (integer >> bit& 0x1) == 1;

【问题讨论】:

  • 过早的优化是魔鬼的玩物
  • 完美的微基准供您尝试。在 100 万次的循环中运行它们并计时。
  • 我几乎完全可以肯定第二个只是简单的错误,不管它是否更快......
  • @Oli,嗯,也许我记错了>>& 的优先级。不过,就我个人而言,我会在上面加上一些括号:)

标签: java algorithm optimization bit-manipulation


【解决方案1】:

您正在测试的位可能比您正在测试的 int“更稳定”。因此,您可以为该位设置常量,这意味着您只需进行一次移位。例如:

static final int LEFT_WALL = 1 << 1;
static final int RIGHT_WALL = 1 << 2;
static final int BOTTOM_WALL = 1 << 3;
static final int TOP_WALL = 1 << 4;

然后在你的循环中,你只是在检查

if ((integer & LEFT_WALL) != 0)
  // left wall collision
if ((integer & RIGHT_WALL) != 0)
  // right wall collision
...

因此,您只在循环中执行了两个操作(按位与和比较),而不是三个(移位、与和比较)。

更重要的是(如 cmets 中所指出的那样)比速度增益,它还使您更清楚您使用每个位的目的,因此代码更易于阅读。

【讨论】:

  • 甚至比保存操作更好,我可以轻松阅读并理解它。
  • 好主意。我的程序中也有几乎相同的最终变量 XD。顺便说一句,大多数人都说这不是一个非常重要的优化,但在某些时候我将不得不运行大约 2400 万次大声笑
  • @stas 是的,你这样节省了一个班次,这可能与 µop 融合和 co 成本可能是一个周期的一半。因此,在 3ghz CPU 上运行 24*10^6 次可以节省大约 1200 万个周期或大约 4ms。大大节省了。
  • @Voo:班次不会融合,班次也不会在任何位置融合,因为在它之后会有一个test(可以与分支融合)。这个int &amp; const != 0 可以编译成只是一个可以融合的测试/分支对。所以它要么是一个移位/融合对,要么只是一个融合测试/分支,显然第二个具有更短的依赖链,但在移位情况下,由于依赖关系,移位确实必须首先完成,所以它将是 1 个周期 -这实际上是一个巨大的差异,因为整个事情是 2 个周期。 50% 没什么好打喷嚏的。
【解决方案2】:

这取决于实现,取决于您的硬件和编译器。在没有实际进行任何计时赛的情况下,我认为没有人能说哪个会更好。

此外,我不会担心这样的事情,除非你有确凿的证据证明这段代码对时间非常关键,以至于你必须对其进行优化。除非您知道这是性能瓶颈,否则花时间对这样的代码进行微优化不太可能有成效,如果您无法通过优化代码的其他部分来获得更多的性能提升,我会感到非常惊讶。尝试分析代码以查看真正的瓶颈是什么,然后优化这些部分。

【讨论】:

    【解决方案3】:

    几乎可以肯定没有区别。

    但是,对于您的平台而言,唯一确定的方法是对它们进行分析。不过,您需要在一个循环中测量大量数字(如 100e6)的时间,以尽量减少测量误差。

    【讨论】:

      猜你喜欢
      • 2015-09-23
      • 1970-01-01
      • 2011-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      • 2014-07-26
      • 1970-01-01
      相关资源
      最近更新 更多