我想从已知的位掩码中选择一些随机位。理想情况下,我也希望以随机顺序选择这些位,但是可以将任务拆分为稍后选择和随机播放。
数据的一些其他特征:
以下是我期望的掩码和事物的例子(选择随机4位):
mask 0111111011111011111110111111111111111101111111100111101111111111
random4 ....1...........1........1...............1......................
shuffled bit positions: 41, 16, 4, 25
在这个例子中,我不应该回到位0,因为它已经被禁用了。
这是该算法的一个已知热点,所以我想尽可能多地挤出它(对随机选择的测试只需要比我当前的随机选择实现长约2倍)。我目前的想法是填充n
中的第一个char positions[64]
数字,并在位掩码中设置位的位置。因此,对于上面的示例,我最终得到:[1, 2, 3, 4, 5, 6, 8, 9, ...]
。然后开始选择0
和n
之间的随机数来选择随机位位置。每次选择后,将位置设置为-1,如果再次按-1,则重复随机选择。
这非常适合选择4个数字,但在选择32个数字时经常会重复选择。
另一个想法是创建一个如上所述的位置数组,然后使用Fisher-Yates对其进行随机排列并选择第一个n
位置。这需要在数组中进行更多写操作,并且总是需要生成与设置位一样多的随机数,这对于仅选择4位可能是一种过度杀伤。
有没有更快的方法来生成这些数据?我的目标是模拟的准确性,所以我真的可以在一秒钟内检查多少随机迭代。
语言并不重要,但我猜C会占据主导地位。
答案 0 :(得分:1)
你不需要做一个完整的Fisher-Yates洗牌。只需在获得第一个n
值后停止。您甚至可以为下一个样本重用部分洗牌的数组。这是C99中的一个例子:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
// Assumes that the array a contains numbers 0..63 in any order
static void print_random_bits(uint64_t bitmask, int num_bits, int a[64]) {
for (int i = 0, j = 63; i < num_bits; ++i, --j) {
int r = rand() % (j + 1);
int t = a[r];
if (r != j) {
a[r] = a[j];
a[j] = t;
}
printf("random bit %2d: %d\n", t, bitmask & (1ULL << t) ? 1 : 0);
}
}
int main(void) {
int a[64];
for (int i = 0; i < 64; ++i) {
a[i] = i;
}
uint64_t bitmask = 0x5555555555555555ULL;
for (int i = 0; i < 10; ++i) {
print_random_bits(bitmask, 8, a);
printf("\n");
}
return 0;
}