【问题标题】:Uniform random bit from a mask来自掩码的统一随机位
【发布时间】:2018-11-29 13:20:38
【问题描述】:

假设我有一个 64 位无符号整数 (u64) mask,设置了一位或多位。

我想从m 中随机均匀地选择一个设置位,以提供一个新掩码x,这样x & mask 就设置了一个位。执行此操作的一些伪代码可能是:

def uniform_random_bit_from_mask(mask):
  assert mask > 0
  set_indices = get_set_indices(mask)
  random_index = uniform_random_choice(set_indices)
  new_mask = set_bit(random_index, 0)
  return new_mask

但是我需要尽可能快地执行此操作(与上面类似的低级语言代码正在减慢热循环)。有没有人有更有效的方案?

【问题讨论】:

  • 如果您只能获得number of set bits efficiently,那么您就不必创建索引列表。
  • 是的,获取设置位的数量更便宜 - 但我仍然需要在最终掩码中设置位,所以我需要索引?
  • 随机函数应该只是告诉你翻转第 i 位,所以你实际上不需要跟踪列表,但我相信你仍然需要遍历这些位。但是,rand() 函数不是这里的真正瓶颈吗?
  • 如果您认为可以优化,也许您可​​以说明实际问题。现在我会说这些优化会给你不到 1% 的速度提升(尽管分析会给你准确的值)。
  • @hellow 我假设 OP 想要一个 Rust 的答案,而 Pythonish 伪代码只是为了说明。

标签: random rust statistics bit-manipulation


【解决方案1】:

如何优化的细节取决于您未指定的几个因素——目标架构、掩码中的预期设置位数、您要使用的语言、对随机性的要求等等。在不知道更多细节的情况下,很难给出有用的答案,但我会给出一些可能有用的提示。

大多数现代架构都有一条指令来计算整数中设置的位数,通常称为“popcount”,并且该指令在大多数低级语言中都有公开。在 Rust 中,您可以使用 count_ones() method。这为您提供了可供选择的位总数k

然后您可以在0k - 1(含)之间生成一个随机数i。下一步是选择mask 中的ith 设置位。一个有效的方法是这个循环(Rust 代码):

for _ in 0..i {
    mask &= mask - 1;
}
let new_mask = 1 << mask.trailing_zeros();

循环在每次迭代中清除最低有效设置位。由于i &lt; k,我们知道mask 在循环之后不能为零。最后一行从仍然设置的mask 的最低有效位生成一个新掩码。

在常见架构上,瓶颈很可能是随机数生成器。如果您使用 Rust 的 rand crate,您可以使用 SmallRng 来提高性能,但代价是密码不安全,这可能与您的用例无关。

【讨论】:

  • 你是怎么想到mask &amp;= mask - 1的?你以前有没有见过类似的东西,或者它只是来找你的?我总是忘记你也可以用算术运算符做一些聪明的小把戏
  • @trentcl 我很久以前就看到过这个,但我不记得我在哪里捡到它了。它经常出人意料地有用。 :)
猜你喜欢
  • 2016-11-29
  • 1970-01-01
  • 2017-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多