试图在每次迭代中产生一个唯一的随机数序列
Trying to produce a unique sequence of random numbers per iteration
正如标题所述,每次运行这个小程序时,我都试图创建一个唯一的随机数序列。
然而,有时我得到这样的结果:
102
201
102
的代码#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
int main() {
for (int i = 0; i < 3; i++) {
srand (time(NULL)+i);
cout << rand() % 3;
cout << rand() % 3;
cout << rand() % 3 << 'n' << endl;
}
}
显然,srand没有我想要的那种神奇的功能。我希望能有个合理的破解方法?
Edit1:澄清一下,这只是一个简单的测试程序,它将在更大的范围内实现。所以我可能会运行1000次,或者更多的rand%50,而不是3次rand%3的迭代。如果我在它的操作中看到了102,我希望我再也不会看到102。
首先,如果您打算使用srand
/rand
,您希望在每次程序执行开始时为其播种一次(且仅一次):
int main() {
srand(time(NULL));
for (int i = 0; i < 3; i++) {
cout << rand() % 3;
cout << rand() % 3;
cout << rand() % 3 << 'n' << endl;
}
其次,time
通常只产生一个分辨率为1秒的结果,所以即使有了这个修正,如果您在同一秒内运行该程序两次,您可以期望它在两次运行中产生相同的结果。
第三,无论如何,您并不真的想使用srand
/rand
。<random>
中的随机数生成器通常要好得多(而且,也许更重要的是,它们被更好地定义为代表一个更广为人知的数量)。
#include <random>
#include <iostream>
int main() {
std::mt19937_64 gen { std::random_device()() };
std::uniform_int_distribution<int> d(0, 2);
for (int i = 0; i < 3; i++) {
for (int j=0; j<3; j++)
std::cout << d(gen);
std::cout << "n";
}
}
然而,根据编辑,这仍然不够。你真正想要的是一个没有重复的随机样本。要做到这一点,你需要做的不仅仅是生成数字。随机生成的数字不仅可以重复,而且如果你生成足够多的数字,不可避免地会重复(但即使不是不可避免的,重复的可能性也会变得相当高)。
只要生成的结果数量相对于可能的结果数量较少,就可以很容易地在生成结果时将结果存储在集合中,并且只将先前不存在于集合中的结果视为实际输出:
#include <random>
#include <iostream>
#include <set>
#include <iomanip>
int main() {
std::mt19937_64 gen { std::random_device()() };
std::uniform_int_distribution<int> d(0, 999);
std::set<int> results;
for (int i = 0; i < 50;) {
int result = d(gen);
if (results.insert(result).second) {
std::cout << std::setw(5) << result;
++i;
if (i % 10 == 0)
std::cout << "n";
}
}
}
如果结果的数量接近可能结果的数量,这将变得非常低效。例如,假设您生成的数字从1到1000(所以有1000个可能的结果)。考虑一下如果你决定产生1000个结果(即所有可能的结果)会发生什么。在这种情况下,当你产生最后一个结果时,实际上只剩下一种可能性——但不是只产生那一种可能性,而是产生一个又一个随机数,直到你偶然发现剩下的一种可能性。
对于这种情况,有更好的方法来做这项工作。例如,您可以从一个容器开始,其中包含所有可能的数字。要生成输出,需要在该容器中生成一个随机索引。您输出该数字,并从容器中删除该数字,然后重复(但这一次,容器小了1,因此您将随机索引的范围减小了1)。这样,您生成的每个随机数都会产生一个输出。
如果可以通过对数字数组进行洗牌来完成相同的操作。但这有两个缺点。首先,你需要正确地洗牌——费雪-耶茨洗牌法效果很好,但否则很容易产生偏差。其次,除非您确实使用了数组中的所有(或非常接近所有)数字,否则这是低效的。
在极端情况下,考虑需要几个64位数字(例如10个)。在这里,首先用264-1中的数字填充数组。然后进行264-2交换。所以,你做了大约265操作来产生10个数字。在这种极端情况下,问题应该是相当明显的。虽然如果您生成1000个32位的数字就不那么明显了,但您仍然会遇到相同的基本问题,只是程度要小一些。因此,尽管对于一些特定情况,这是一种有效的方法,但其适用性相当有限。
生成一个包含27个小于3的三位数字的数组。洗牌。根据需要迭代经过洗牌的数组,值将是唯一的,直到耗尽所有值。
正如其他人指出的那样,不要一直重新播种您的随机数生成器。此外,rand
是一个糟糕的生成器,您应该使用c++标准库中可用的更好的选择之一。
您正在有效地生成一个以3为基数的三位数。使用您选择的RNG生成0范围内的以10为基数的数字。26,换算成以3为底。那就有000…222 .
如果必须避免重复,那么按照pjs的建议对数组进行洗牌。这将导致后面的数字比前面的数字"不那么随机",因为它们取自较小的池。
- c++多进程编写一个唯一的文件
- 我需要编写一个程序来读取一个文件,该文件将输出所有唯一的整数,如果已经看到整数,它将被关闭
- 从另一个唯一 ptr 的原始 ptr 创建唯一的 ptr
- 如何在以 256 为基数的唯一 xLen-digit 表示中写一个整数 x?
- 需要在C 中生成一个从00001到99999的唯一5位数字
- 如何在给定任意数量的整数的情况下创建一个唯一键?并使用该键存储,然后从地图中查找
- 尝试创建一个读取.txt文件,显示它,计数唯一单词的程序,并在使用了多少次的情况下显示独特的单词.C
- 如何制作一个采用类型类的唯一指针?(通用)它不让我
- 为什么要在 c++ 中创建一个指向基元类型的唯一指针?
- 如何将唯一指针从一个向量移动到另一个唯一指针向量
- 将 n 个整数组合成一个唯一的表示形式
- 正确地返回一个唯一的ptr
- 为每个对象定义一个唯一的函数
- 需要在数组中找到一个唯一的数字
- 更快的方式,然后我填充一个唯一的整数除了两个值的向量?c++
- 如何将三个整数组合成一个唯一的标记,使标记在c++中保持整数
- 一个唯一的ptr类如何将它的实例指针传递给它的成员对象
- 试图在每次迭代中产生一个唯一的随机数序列
- 可变模板类:每个可变模板参数可以实现一个唯一的成员函数吗
- 如何将两个正整数映射为一个唯一的整数