我注意到通过做一个简单的基于控制台的测验应用程序练习。当我使用rand()
时,它连续几次给我相同的值。数字范围越小,问题就越大。
例如
for (i=0; i<10; i++) {
x = rand() % 20 + 1;
cout << x << ", ";
}
会给我1, 1, 1, 2, 1, 1, 1, 1, 14,
- 有太多定义,对吧?我通常从没有到4个奇数(休息是一样的,它也可以是11, 11, 11, 4, 11 ...
)
我做错了吗?或rand()
不是那么随意我认为是这样的?
(或者它只是来自C#/ Java的一些我不知道的习惯?它对我来说也发生了很多......)
答案 0 :(得分:4)
如果我运行该代码几次,我会得到不同的输出。当然,不像我想的那样变化,但看似不确定(虽然当然是,因为rand()
只给出伪随机数......)。
然而,你对待你的数字的方式不会给你一个超过[1,20]的统一分布,我想这就是你所期望的。要实现这一目标要复杂得多,但绝不可能。举个例子,看一下documentation for <random>
at cplusplus.com - 在底部有一个展示程序,可以在[0,1]上生成均匀分布。为了得到[1,20],您只需将输入参数更改为生成器 - 它可以在您喜欢的任何范围内为您提供均匀分布。
我做了一个快速测试,并拨打rand()
一百万次。正如您在下面的输出中所看到的,即使样本量非常大,分布中也存在一些不均匀性。随着样本数量变为无穷大,该行将(可能)变平,使用类似rand() % 20 + 1
的内容为您提供非常长时间的分发。如果您采取其他措施(如上面的示例),即使是非常小的样本量,您也可以更好地实现均匀分布。
修改强>
我看到其他几个人在发布使用它之前使用srand()
播种随机数生成器。这是一个很好的建议,但在这种情况下它不会解决您的问题。我再说一遍:在这种情况下,播种不是问题。
种子主要用于控制程序输出的可重复性。如果使用常量值(例如0)对随机数进行种子处理,程序将每次都给出相同的输出,这对于测试一切是否正常工作非常有用。通过播种非常量的东西(当前时间是一种流行的选择),您可以确保结果在不同的程序运行之间有所不同。
根本不调用srand()
与使用C ++标准调用srand(1)
相同。因此,每次运行程序时都会得到相同的结果,但每次运行中都会有一系列完全有效的伪随机数。
答案 1 :(得分:3)
听起来你正在击中模拟偏见。
使用%
将随机数缩放到某个范围并不是一个好主意。如果你将它降低到2的幂,但仍然相当差,这几乎是可以接受的。它主要受较小的比特的影响,这些比特在许多算法中经常不那么随机(特别是rand()
),并且它以非均匀的方式收缩到较小的范围,因为你的减少的范围不会平均分配随机数生成器的范围。要缩小范围,您应该使用除法和循环,如下所示:
// generate a number from 0 to range-1
int divisor = MAX_RAND/(range+1);
int result;
do
{
result = rand()/divisor;
} while (result >= range);
这并不像它看起来那么低效,因为循环几乎总是只传递一次。此外,如果你打算将你的生成器用于接近MAX_RAND
的数字,你需要一个更复杂的divisor
方程式,这是我无法记得的。
另外,rand()
是一个非常差的随机数生成器,如果你关心结果的质量,可以考虑使用类似Mersenne Twister的东西。
答案 2 :(得分:2)
您需要先调用srand()
并为其提供更好的伪随机值参数。
示例:
#include <iostream>
#include <string>
#include <vector>
#include "stdlib.h"
#include "time.h"
using namespace std;
int main()
{
srand(time(0));
int x,i;
for (i=0; i<10; i++) {
x = rand() % 20 + 1;
cout << x << ", ";
}
system("pause");
return 0;
}
如果您不希望重复生成的任何数字并且不需要考虑内存,则可以使用vector
整数,随机随机播放,然后获取前N个整数的值。 / p>
示例:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
//Get 5 random numbers between 1 and 20
vector<int> v;
for(int i=1; i<=20; i++)
v.push_back(i);
random_shuffle(v.begin(),v.end());
for(int i=0; i<5; i++)
cout << v[i] << endl;
system("pause");
return 0;
}
答案 3 :(得分:0)
可能的问题是您每次使用相同的“随机”数字,并且任何int
mod 1都为零。换句话说,(myInt % 1 == 0
)总是如此。而不是%1
,请使用% theBiggestNumberDesired
。
另外,使用srand
为随机数播种。使用常量种子来验证您是否获得了良好的结果。然后更改种子以确保您仍然获得良好的结果。然后使用更随机的种子,如时钟进一步奶嘴。随机种子释放。
答案 4 :(得分:0)
注意:如果在不调用srand()的情况下在不同的线程中运行它,rand()会给你相同的结果。试着这样看看自己:
vector<thread> workers;
for (int i = 0; i < 10; i++)
workers.push_back(std::thread([]{ cout << rand() << endl; }));
for (auto& th : workers)
{
if (th.joinable())
th.join();
}