C++,某些组合从未使用rand()出现
C++, certain combos never appear using rand()
我对0和2之间的两个int使用rand()。看起来第一个int从来都不是0,而第二个int是2。这是我的测试代码-
#include <iostream>
#include <time.h>
int main()
{
srand(time(NULL));
int number1, number2;
number1 = rand() % 3;
number2 = rand() % 3;
printf("%i, %i", number1, number2);
return 0;
}
Output-25尝试
2, 2
2, 2
2, 1
1, 2
0, 1
2, 2
1, 2
1, 0
2, 1
1, 0
0, 0
1, 2
2, 2
0, 0
2, 1
1, 0
2, 2
1, 0
2, 1
1, 0
0, 1
1, 2
1, 0
0, 0
2, 2
正如你所看到的,在25次尝试中,组合从来都不是0,2。这是我可能应该转移到<随机>?此外,永远不会有2,0。
不,这将发生在所有种子的9*(1-1/9)^25=0.4736,或大约50%的时间。也就是说,在你运行程序的前25个结果中,大约有一半的时间会丢失一些数字在{0,1,2}中的两位数序列。
再运行一次,看看会发生什么。
-
您绝对应该使用
<random>
。你越早忘记rand
的存在,你就会越快乐 -
CCD_ 3有时用线性同余生成器(LCG)来实现。LCG存在许多缺陷,最相关的是顺序生成的数字的低阶比特高度相关。因此,您永远不应该使用
rand() % k
来生成[0, k)
范围内的数字。还有其他原因。事实上,从有限的范围生成无偏随机整数涉及到一些微妙之处,<random>
会为您处理这些问题。 -
srand(time(NULL))
将随机数生成器的种子设定为从epoch开始的当前时间(以秒为单位),这意味着如果您按顺序运行程序几次,种子将相同或相似。如果种子相同,则随机数序列也将相同。如果种子相似,则随机数序列也可以相似。所以,除了在长时间运行的程序中,不要这样做。为伪随机数生成器找到一个好的种子可能很棘手。<random>
实现将具有更好的默认行为,因此您通常不需要担心这一点。
获取%3不仅仅取决于低阶位。
我使用VC++运行了下面的程序,模拟在调用之间的一秒钟内运行OP的程序1000万次。它没有显示出任何偏见。
start = 1413167398
(0, 0) 1110545
(0, 1) 1111285
(0, 2) 1111611
(1, 0) 1111317
(1, 1) 1111666
(1, 2) 1110451
(2, 0) 1111580
(2, 1) 1110491
(2, 2) 1111054
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <map>
#include <utility>
int main()
{
std::map<std::pair<int, int>, int> counter;
unsigned int start = static_cast<unsigned int>(std::time(nullptr));
std::cout << "start = " << start << std::endl;
unsigned int finish = start + 10000000;
for (unsigned int seed = start; seed != finish; ++seed)
{
std::srand(seed);
int x = rand() % 3;
int y = rand() % 3;
++counter[std::make_pair(x, y)];
}
for (auto iter = counter.cbegin(); iter != counter.cend(); ++iter)
{
std::cout << "(" << iter->first.first << ", " << iter->first.second << ") ";
std::cout << iter->second << std::endl;
}
return 0;
}
确实如此。这段代码在第一次运行时给了我0.2对:
for( int i = 0; i < 20; ++i) {
number1 = rand() % 3;
number2 = rand() % 3;
printf("%i, %in", number1, number2);
}
从均匀分布中生成真正的随机数并不能保证给定的(可能的)数会出现在有限数量的试验中。良好PRNG的四个BSI标准中的K2是
K2——与"true"不可区分的数字序列随机数。
因此,生成伪随机数当然倾向于以与从真实随机分布中采样相同的方式表现——尽管由于限制,任何(可能的)数都会在某个点出现(在小于或等于其周期的时间)。
http://ideone.com/c5oRQL
使用std::uniform_int_distribution
除此之外,rand()
并不是最好的发生器。每当模运算中的除数不能均匀地划分PRNG的范围时,它总是引入偏差。运算符%使得以这种方式产生的概率分布偏斜,因为作为rand()
的最大值的RAND_MAX可以不等于k*3+2。如果除数不能均匀地划分范围,那么分布将是偏斜的,并且偏差随着除数的增加而增加。你可以在这里阅读更多关于这方面的内容。总结一下:在C++中,您应该使用<random>
库:
#include <iostream>
#include <random>
int main()
{
std::random_device rd;
std::mt19937 gen( rd());
std::uniform_int_distribution<> dis( 0, 2);
for ( int n = 0; n < 25; ++n)
std::cout << dis(gen) << ' ';
std::cout << 'n';
}
- 为"adjacent"变量赋值时出现问题
- 在Ubuntu 16.04上安装Cilk时出现问题
- 代码在main()中运行,但在函数中出现错误
- 尝试导入pybind-opencv模块时出现libgtk错误
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 在某些循环内使用vector.push_back时出现分段错误
- C++中的赋值发生,尽管右侧出现异常
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 在WSL:configure_file上对config_file的每次调用都失败:配置文件时出现问题
- 我想做一个彼此不同但重复出现的数字
- 运行程序时出现问题
- 在c++中尝试对对象数组进行排序时,出现std:bad_alloc错误
- malloc() 可能出现内存泄漏
- 当我的阵列太大时出现分段错误
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- cpp二进制搜索问题,计算给定数组中输入元素的出现次数
- 使用 GCC 卸载的 OpenMP 卸载失败,并出现"Ptx assembly aborted due to errors"
- Qt5:使用QCommandLineParser类时出现奇怪的编译错误
- 生成一个rand()%25,其中每个数字只能出现一次
- C++,某些组合从未使用rand()出现