随机对不同的位

时间:2014-08-26 19:05:55

标签: c++ algorithm random binary bit

我有以下问题。我有一个二进制表示的数字。我需要一种方法来随机选择两个不同的位(即找到1和0)。除此之外,我对该数字运行其他操作(反转序列,置换序列,......)这些是我已经使用过的方法:

  • 跟踪所有的零和零。当我创建二进制数的二进制表示时,我存储0和1的位置。这样我就可以为一个列表选择索引,从另一个列表中选择一个索引。然后我有两个不同的位。为了运行我的其他操作,我从基本交换操作创建了那些操作,这些操作在操作时更新1和0的索引。因此,我有第三个列表存储每个位的列表索引。如果一位是1我知道在列表中找到哪些索引的所有索引(零也是零)。
  • 当完成不需要位不同的操作时,上述方法产生一些开销。因此,另一种方法是在需要不同位时创建列表。

有没有人有更好的想法呢?我需要这些操作非常快(我正在使用popcount,clz和其他二进制操作)

2 个答案:

答案 0 :(得分:1)

我觉得我没有足够的信息来正确评估权衡,但也许你会发现这个想法很有用。要在单词中找到随机1(通过popcount和水库采样找到多个单词1;通过补充找到0),首先测试popcount。如果popcount为高,则随机均匀生成索引并测试它们直到找到一个。如果popcount为medium,则使用均匀随机掩码进行按位AND(但如果AND为零,则保留原始值)以减少popcount。当popcount为低时,使用clz有效地编译(小)候选列表,然后随机均匀采样。

答案 1 :(得分:0)

我认为以下可能是一个相当有效的算法来做你要求的。您只需迭代一次数字中的每一位,并且对于每个元素,您必须生成一个随机数(不确定它的成本有多高,但我相信有一些优化的CPU指令可用于获取随机数)。

想法是迭代所有位,并以正确的概率将索引更新为您正在访问的当前索引。

从流/数组中获取元素的通用伪代码:

p = 1
e = null
for s in stream:
  with probability 1/p:
    replace e with s
  p++
return e

Java版:

int[] getIdx(int n){
    int oneIdx  = 0;
    int zeroIdx = 0;

    int ones = 1;
    int zeros = 1;

    // this loop depends on whether you want to select all the prepended zeros
    // in a 32/64 bit representation. Alter to your liking...

    for(int i = n, j = 0; i > 0; i = i >>> 1, j++){
      if((i & 1) == 1){ // current element is 1
        if(Math.random() < 1/(float)ones){
          oneIdx = j;
        }
        ones++;
      } else{ // element is 0
        if(Math.random() < 1/(float)zeros){
          zeroIdx = j;
        }
        zeros++;
      }
    }
    return new int[]{zeroIdx,oneIdx};
  }

您可能会考虑的优化是使用整数而不是浮点数进行概率选择,可能会稍快一些。这是我前一段时间做过的关于这项工作的简短证据:here。我相信这个算法归功于Knuth,但不能完全记住。