- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
考虑以下来自 C++ 标准库的算法:std::shuffle
具有以下签名:
template <class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG&& g);
它对给定范围 [first, last)
中的元素重新排序,使得这些元素的每个可能排列具有相等的出现概率。
我正在尝试实现相同的算法,但它在位级别工作,随机打乱输入序列中单词的位。考虑到一系列 64 位单词,我正在尝试实现:
template <class URBG>
void bit_shuffle(std::uint64_t* first, std::uint64_t* last, URBG&& g)
问题:如何尽可能高效地做到这一点(必要时使用编译器内部函数)?我不一定要寻找完整的实现,但更多的是寻找建议/研究方向,因为我真的不清楚有效实现它是否可行。
最佳答案
很明显,渐近速度是O(N)
,其中N
是位数。我们的目标是改进其中涉及的常量。
Disclaimer: the description proposed algorithm is a rough sketch. There are a lot of stuffs needs to be added and, especially, a lot of details that needs to be cared of in order to make it work correctly. The approximated execution time will not be different from what is claimed here though.
最明显的是 textbook approach ,它需要 N
操作,每个操作都涉及调用 random_generator
需要 R
毫秒,并访问两个不同位的位值,以及总共为它们设置新值 4 * A
毫秒(A
是读/写一位的时间)。假设数组查找操作需要 C
毫秒。所以这个算法的总时间是 N * (R + 4 * A + 2 * C)
毫秒(大约)。假设随机数生成需要更多时间也是合理的,即 R >> A == C
。
假设位存储在字节存储中,即我们将使用字节 block 。
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()];
Summing everything up, we have the total execution time:
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 algoAlthough it's not truly uniformly random, but it does spread the bits out quite evenly and randomly, and it's quite fast and hopefully gets the job done in your use-case.
关于c++ - 有效地随机改组单词序列的位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57316214/
我让随机数低于之前的随机数。 if Airplane==1: while icounter0: print "You have enoph fuel to get to New
是否可以生成 BigFloat 的随机数?类型均匀分布在区间 [0,1)? 我的意思是,因为 rand(BigFloat)不可用,看来我们必须使用 BigFloat(rand())为了那个结局。然而,
我正在尝试学习 Kotlin,所以我正在学习互联网上的教程,其中讲师编写了一个与他们配合良好的代码,但它给我带来了错误。 这是错误 Error:(26, 17) Kotlin: Cannot crea
是否有任何方法可以模拟 Collections.shuffle 的行为,而不使比较器容易受到排序算法实现的影响,从而保证结果的安全? 我的意思是不违反类似的契约(Contract)等.. 最佳答案 在
我正在创建一个游戏,目前必须处理一些math.random问题。 我的Lua能力不是那么强,你觉得怎么样 您能制定一个使用 math.random 和给定百分比的算法吗? 我的意思是这样的函数: fu
我想以某种方式让按钮在按下按钮时随机改变位置。我有一个想法如何解决这个问题,其中一个我在下面突出显示,但我已经认为这不是我需要的。 import javafx.application.Applicat
对于我的 Java 类(class),我应该制作一个随机猜数字游戏。我一直陷入过去几天创建的循环中。程序的输出总是无限循环,我不明白为什么。非常感谢任何帮助。 /* This program wi
我已经查看了涉及该主题的一些其他问题,但我没有在任何地方看到这个特定问题。我有一个点击 Web 元素的测试。我尝试通过 ID 和 XPath 引用它,并使用 wait.until() 等待它变得可见。
我在具有自定义类的字典和列表中遇到了该异常。示例: List dsa = (List)Session["Display"]; 当我使用 Session 时,转换工作了 10-20 次..然后它开始抛
需要帮助以了解如何执行以下操作: 每隔 2 秒,这两个数字将生成包含从 1 到 3 的整数值的随机数。 按下“匹配”按钮后,如果两个数字相同,则绿色标签上的数字增加 1。 按下“匹配”按钮后,如果两个
void getS(char *fileName){ FILE *src; if((src = fopen(fileName, "r")) == NULL){ prin
如果我有 2 个具有以下字段的 MySQL 数据库... RequestDB: - Username - Category DisplayDB: - Username - Category
我有以下语句 select random() * 999 + 111 from generate_series(1,10) 结果是: 690,046183290426 983,732229881454
我有一个使用 3x4 CSS 网格构建的简单网站。但出于某种原因,当我在 chrome“检查”中检查页面时,有一个奇怪的空白 显然不在我的代码中的标签。 它会导致网站上出现额外的一行,从而导致出现
我有两个动画,一个是“过渡”,它在悬停时缩小图像,另一个是 animation2,其中图像的不透明度以周期性间隔重复变化。 我有 animation2 在图像上进行,当我将鼠标悬停在它上面时,anim
如图所示post在 C++ 中有几种生成随机 float 的方法。但是我不完全理解答案的第三个选项: float r3 = LO + static_cast (rand()) /( static_c
我正在尝试将类添加到具有相同类的三个 div,但我不希望任何被添加的类重复。 我有一个脚本可以将一个类添加到同时显示的 1、2 或 3 个 div。期望的效果是将图像显示为背景图像,并且在我的样式表中
我有一个基本上可以工作的程序,它创建由用户设置的大小的嵌套列表,并根据用户输入重复。 但是,我希望各个集合仅包含唯一值,目前这是我的输出。 > python3 testv.py Size of you
我正在尝试基于 C# 中的种子生成一个数字。唯一的问题是种子太大而不能成为 int32。有什么方法可以像种子一样使用 long 吗? 是的,种子必须很长。 最佳答案 这是我移植的 Java.Util.
我写这个函数是为了得到一个介于 0 .. 1 之间的伪随机 float : float randomFloat() { float r = (float)rand()/(float)RAN
我是一名优秀的程序员,十分优秀!