我有以下问题。我有一个二进制表示的数字。我需要一种方法来随机选择两个不同的位(即找到1和0)。除此之外,我对该数字运行其他操作(反转序列,置换序列,......)这些是我已经使用过的方法:
有没有人有更好的想法呢?我需要这些操作非常快(我正在使用popcount,clz和其他二进制操作)
答案 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,但不能完全记住。