很明显,渐近地,速度是O(N),其中N 是位数。我们的目标是改进其中涉及的常量。
免责声明:所提出的算法的描述是一个粗略的草图。有很多东西需要添加,特别是需要注意很多细节才能使其正常工作。不过,估计的执行时间不会与此处声称的不同。
基线算法
最明显的是textbook approach,它接受N操作,每个操作都涉及调用random_generator,它需要R毫秒,并访问两个不同位的位值,并设置新值给他们总共4 * A 毫秒(A 是读/写一位的时间)。假设数组查找操作需要C 毫秒。所以这个算法的总时间是N * (R + 4 * A + 2 * C)毫秒(大约)。假设随机数生成需要更多时间也是合理的,即R >> A == C。
提出的算法
假设位存储在字节存储中,即我们将使用字节块。
unsigned char bit_field[field_size = N / 8];
首先,让我们计算一下我们的位集中1 位的数量。为此,我们可以使用查找表并以字节数组的形式遍历位集:
# Generate lookup-table, you may modify it with `constexpr`
# to make it run in compile time.
int bitcount_lookup[256];
for (int = 0; i < 256; ++i) {
bitcount_lookup[i] = 0;
for (int b = 0; b < 8; ++b)
bitcount_lookup[i] += (i >> b) & 1;
}
我们可以将此视为预处理开销(因为它也可以在编译时计算)并说它需要0 毫秒。现在,计算1 位数很容易(以下将花费(N / 8) * C 毫秒):
int bitcount = 0;
for (auto *it = bit_field; it != bit_field + field_size; ++it)
bitcount += bitcount_lookup[*it];
现在,我们随机生成N / 8 数字(我们称结果数组为gencnt[N / 8]),每个都在[0..8] 范围内,因此它们总和为bitcount。这有点棘手,而且很难均匀地完成(与基线算法相比,生成均匀分布的“正确”算法相当慢)。一个非常统一但快速的解决方案大致是:
- 用值
v = bitcount / (N / 8) 填充gencnt[N / 8] 数组。
- 随机选择
N / 16“黑色”单元格。其余的是“白色”。该算法类似于random permutation,但只占数组的一半。
- 在
[0..v] 范围内生成N / 16 随机数。我们就叫他们tmp[N / 16]吧。
- 将“黑色”单元格增加
tmp[i] 值,将“白色”单元格减少tmp[i]。这将确保总和为bitcount。
之后,我们将有一个统一的随机数组gencnt[N / 8],其值是特定“单元格”中1 的字节数。全部生成于:
(N / 8) * C + (N / 16) * (4 * C) + (N / 16) * (R + 2 * C)
^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
filling step random coloring filling
毫秒(这个估计是在我的脑海中通过具体实现完成的)。最后,我们可以将指定位数设置为1 的字节查找表(可以编译开销,甚至在编译时为constexpr,因此假设这需要0 毫秒):
std::vector<std::vector<unsigned char>> random_lookup(8);
for (int c = 0; c < 8; c++)
random_lookup[c] = { /* numbers with `c` bits set to `1` */ };
然后,我们可以如下填写我们的bit_field(大约需要(N / 8) * (R + 3 * C) 毫秒):
for (int i = 0; i < field_size; i++) {
bit_field[i] = random_lookup[gencnt[i]][rand() % gencnt[i].size()];
总结一切,我们有总执行时间:
T = (N / 8) * C +
(N / 8) * C + (N / 16) * (4 * C) + (N / 16) * (R + 2 * C) +
(N / 8) * (R + 3 * C)
= N * (C + (3/16) * R) < N * (R + 4 * A + 2 * C)
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
proposed algorithm naive baseline algo
虽然它不是真正均匀随机的,但它确实将位分布相当均匀和随机,而且速度非常快,希望能在您的用例中完成工作。