如何使随机数独一无二
How to make Random Numbers unique
我正在制作一个随机数生成器。它询问用户希望在数字中包含多少位数字。例如,如果他们输入2,它将生成10到99之间的随机数。我制作了生成器,但我的问题是数字不是唯一的。
这是我的密码。我不知道为什么它不生成唯一的数字。我以为srand(时间(空))能做到。
void TargetGen::randomNumberGen()
{
srand (time(NULL));
if (intLength == 1)
{
for (int i = 0; i< intQuantity; i++)
{
int min = 1;
int max = 9;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "t";
}
}
else if (intLength == 2)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 10;
int max = 90;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "t";
}
}
if (intLength == 3)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 100;
int max = 900;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "t";
}
}
else if (intLength == 4)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 1000;
int max = 9000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "t";
}
}
if (intLength == 5)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 10000;
int max = 90000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "t";
}
}
else if (intLength == 6)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 100000;
int max = 900000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "t";
}
}
if (intLength == 7)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 1000000;
int max = 9000000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "t";
}
}
else if (intLength == 8)
{
for (int i = 0; i <intQuantity; i++)
{
int min = 10000000;
int max = 89999999;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "t";
}
}
if (intLength == 9)
{
for (int i = 0; i < intQuantity; i++)
{
int min = 100000000;
int max = 900000000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "t";
}
}
}
好吧,我想我找到了一种不用数组的方法,但在我切换到fisher-yates方法之前,它不起作用。有人能告诉我为什么这不起作用吗?它本质上应该是将随机数放入变量numGen中。然后在变量b=到numgen中。只是为了保持numGen过去的值,所以当循环通过并生成另一个随机数时,它会将其与旧数字进行比较,如果不等于旧数字,它就会输出它。如果它等于旧数字而不是输出它,它会解增量i,这样它就可以在循环中运行,而不会完全跳过这个数字。然而,当我这样做的时候,是无限循环。我不知道为什么。
if(intLength==1){
for (int i = 0; i< intQuantity; ++i)
{
int min = 1;
int max = 9;
int number1 = rand();
int numGen = number1 % max + min;
if (intQuantity > max)
{
intQuantity = max;
}
for (int k = 0; k < 1; k++)
{
cout << numGen << "t";
int b = numGen;
}
int b = numGen;
if (b != numGen )
{
cout << numGen << "t";
}
else
{
i--;
}
}
}
每个人都对随机数有着有趣的期望——显然,你希望随机数是唯一的!如果您使用任何好的随机数生成器,您的随机数将永远不会被保证是唯一的。
最明显的是,如果你想生成[1,2]范围内的随机数,并且你要生成两个数,你会(通常期望)以相同的概率得到以下四种可能性之一:
1,2
2,1
1,1
2,2
要求一个好的随机数生成器生成前两个,而不是后两个是没有意义的。
现在,花一点时间思考一下,如果你要求在同一范围内生成三个数字,会发生什么。。。1,2,然后呢??
因此,唯一性不是,也不会是随机数生成器的属性。
不过,你的具体问题可能需要独特性。在这种情况下,您需要做一些额外的工作来确保唯一性。
一种方法是保留一个已经选择了数字的选项卡。你可以把它们放在一套里,如果你得到了之前得到的,可以重新挑选。然而,只有当你选择了一小组与你的范围相比较的数字时,这才是有效的;如果你选择了大部分的范围,那么这个过程的结束是无效的。
如果你要挑选的数字计数与范围的大部分相对应,那么使用范围的数组,并使用良好的洗牌算法来洗牌是更好的解决方案。(费雪-耶茨洗牌应该能起作用。)
提示0:使用数论中的二次残差;一个整数q称为模p的二次残差,如果它与模p,使得:
x2lect q(mod p)
提示1:定理:假设p是素数,只要2x<p.例如:
02选择0(mod 13)
12Select1(mod 13)
22Select4(mod 13)
32Select9(mod 13)
42Select3(mod 13)
52lect 12(mod 13)
62Select10(mod 13)
提示2:定理:假设p是素数,使得p≠3(mod 4),不仅x2%p(即二次残差)对于2x<p,但是p-x2%p对于2x>p也是唯一的。例如:
02%11=0
12%11=1
22%11=4
32%11=9
42%11=5
52%11=3
11-62%11=8
11-72%11=6
11-82%11=2
11-92%11=7
11-102%11=10
因此,这个方法为我们提供了一个在小于p的整数上的完美的1对1置换,其中p可以是任何素数,使得p≠3(mod 4)。
提示3:
unsigned int UniqueRandomMapping(unsigned int x)
{
const unsigned int p = 11; //any prime number satisfying p ≡ 3 (mod 4)
unsigned int r = ((unsigned long long) x * x) % p;
if (x <= p / 2) return r;
else return p - r;
}
我不担心输入数字不正确(例如超出范围)。
备注
- 对于32位整数,您可以选择最大素数,使得p elec 3(mod 4)小于232,即4294967291
- 尽管这种方法为生成随机数提供了一个1对1的映射,但它也存在集群问题
- 为了提高上述方法的随机性,请将其与其他独特的随机映射方法,如XOR算子
我假设您可以想出一种方法来计算要使用的数字数量。这很简单,因为用户输入2等于10-99,3等于100-999,等等
如果你想自己实现唯一的、随机生成的数字,请查看这些链接。
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
下面是一个非常相似的实现:https://stackoverflow.com/a/196065/2142219
本质上,您正在创建一个X整数的数组,所有这些整数都设置为其索引的值。您可以随机选择一个介于0和MAX之间的索引,取该索引处的值并将其与最大值进行交换。MAX随后递减1,您可以通过随机选择0和MAX-1之间的索引来重复此操作。
这会给您一个0-999整数的随机数组,没有重复项。
以下是在一个范围内生成唯一随机数的两种可能方法。
- 跟踪已经使用
std::set
生成的数字,只要它们已经在集合中,就丢弃并重新生成数字。如果您想生成大量随机数,则不建议使用这种方法,因为存在生日悖论 - 生成给定范围内的所有数字,对它们进行随机排列,然后输出用户想要的任意数量
标准随机生成器永远不会生成唯一的数字,在这种情况下,它们将不独立。
要生成唯一的数字,您必须:
- 保存所有生成的数字,并将新数字与旧数字进行比较,如果有巧合,则重新生成
或
- 使用random_shuffle函数:http://en.cppreference.com/w/cpp/algorithm/random_shuffle提前获取所有序列
首先,srand()
/rand()
通常具有2^32的周期,这意味着在调用srand()
之后,rand()
将在对rand()
的前2^32次调用期间内部迭代不同的整数。尽管如此,rand()
很可能返回一个小于32位的结果:例如0
和RAND_MAX
之间的int
,其中RAND_MAX
是2^31-1或2^15-1,因此作为rand()
的调用者,您可能会看到重复的结果。不过,你可能读到了关于这一时期的文章,或者有人在意识到这一点的情况下发表的评论,不知何故,它被误认为是独一无二的。。。。
其次,对rand()
的任何调用都会生成一个比您想要的大得多的数字,而您正在这样做。。。
number1 % max
"number1 % max
"的结果在0 <= N <= max
的范围内,但随机数本身可能是大于max
的任意倍数。换句话说,两个不同的随机数相差max
的倍数,在您的程序中仍然会为number1 % max
产生相同的结果。
要获得一个范围内不同的随机数,可以用所有的数字预填充std::vector
,然后再填充std::shuffle
。
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 整数不会重复超过随机数
- if数组上的随机数
- 在将数字随机生成为数组期间从内存输出随机数的数组
- 半随机数生成C++
- 程序在尝试猜测它选择的随机数时进入无限循环?
- 有没有办法在 c++ 中同时生成随机数?如果没有,是否有解决方法?
- 具有随机数的二维数组不会更改
- 随机数未达到限制
- 我想生成许多矩阵并用随机数填充它
- <random>在实践中应该实际使用哪个随机数引擎? std::mt19937?
- 制作具有平均值的随机数生成器
- 为什么 rand 不在我的代码中生成随机数?
- C++ 随机数生成器:尝试将结果作为向量获取,但通过制作 void 函数来执行此操作而出现错误
- 从给定种子生成相同的随机数序列C++
- 随机数生成函数说明
- C++ 尝试生成随机数时弹出警告帮助?
- 尝试在 c++ 中创建随机数生成器并收到错误
- 从给定的随机数组值生成随机数 Arduino程序C++
- 如何使随机数独一无二