C++可预测Rand()输出
C++ Predictable Rand() Output
注意到rand()函数每次产生相同的输出41后,我使用srand(time(0))为生成器播种。这解决了重复输出的问题,但现在它给了我不断增加的数字。(即245248250253255256)。我可以理解,由于系统时间的影响,它正在增加,但这正常吗?
这是我的程序:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
int number;
srand(time(0));
cout << rand() % 1000;
return 0;
}
我在重复运行,而不是循环运行。多项试验的结果:285295305311325334344354355
MS的C++rand()
使用最简单的随机生成器线性同余生成器
这是它的代码:
int __cdecl rand (
void
)
{
_ptiddata ptd = _getptd();
return( ((ptd->_holdrand = ptd->_holdrand * 214013L
+ 2531011L) >> 16) & 0x7fff );
}
因此,每当你为函数播种时,你只需设置第一个值(如果你快速运行程序,它显然会不时增加一些单位)
现在,如果你在rand()
的数学方程中插入一个值x+a
,其中x
是上次调用函数的值,a
是调用后时间的变化,你会注意到:((x+a)*214013+2531011)>>16=(x*214013+531011+a*214013)>>16
因为你的程序运行得很快。你的a
在0
和5
秒之间变化。那么你的a*214013
现在有一个最大值1070065
,当你把这个数字右移16位时,你得到的是十进制的16
,这是大约你的新输出与上一个输出的差异有多大(我说大约是因为你不能说(x*214013+2531011+a*214013>>16=(x*2140013+2531013>>16)+(a*214012>>16,因为进位)
这个错误大约每周出现一次:
如果每次在调用rand()之前都调用srand()
,那么您根本不会得到随机数,而是得到了一个时间的散列函数。在循环外调用srand()
一次,AND ONLY一次,最好是在程序刚开始时,然后根据需要多次调用rand()
以获取值。
不存在生成"一个随机数"这回事。如果在一系列程序调用中需要随机数,那么您别无选择,只能在程序之外生成这些随机数。一种方法是读取/dev/urandom
(在Linux上)或使用CryptGenRandom
(在Windows上)。另一种选择是使用硬件或类似random.org
的服务。
不管你有多好的生成器——如果你为每个调用设定种子,你不会得到随机数,你会得到种子值的哈希函数。如果你的种子值变化足够快,并且哈希函数非常好,那可能就足够了——但它仍然没有使用RNG算法。
我不知道为什么你会得到这些结果,但在C++11:中有更好的方法
#include <random>
#include <iostream>
int main()
{
auto rnd = std::default_random_engine(std::random_device{}());
std::uniform_int_distribution<> dis(1, 999);
std::cout << dis(rnd) << 'n';
}
rand
在运行库中被实现为线性同余生成器,其形式为:
result = (seed * result + offset) % big_number
如果我们认为big_number
是无穷大的,并且您在时间t
运行程序,则会得到
result = t * result + offset
如果你在很短的时间后再次运行程序alpha
,你会得到
result = (t + alpha)* result + offset
如果运行库用一个小值初始化结果,则显示的结果将随着alpha * result
的小值而增加。
用更高分辨率的计数器取代time()
将大大改善这一点。例如,在x86上,rdtcs
指令(通常作为编译器内部指令)几乎可以解决这个问题。
一个更好的解决方案是使用一个非线性同余生成器来种子rand()
,就像Jesse Good建议的那样,它也可以通过boost库在非c++11编译器上使用。
在可能的情况下,最好使用c++11随机生成器,而不是c rand。
rand
的工作方式需要遵循两条规则:
- 你必须先播种(
srand
) - 您不希望在每次呼叫
rand
之前为其播种。你只需要在你的整个序列之前播种一次
因此,要真正测试它,你的代码应该更像这样:
int main()
{
srand(time(0));
// Output a sequence of 100 random numbers, each less than 1000
for ( int i = 0; i < 100; i++ )
cout << rand() % 1000 << endl;
return 0;
}
如果程序必须每次运行仅输出一个随机数,并且程序运行频率为每秒一次或更多,则time(0)
可能不是合适的种子。也许使用clock_gettime(3)
,它会在几毫秒内给你更多的东西。
我最近遇到了同样的问题,发现Karoly Horvath对你最初问题的评论解决了这个问题,尽管它有点"黑客"。我看到返回值有一个可预测的增长,在srand()
之后立即粘贴另一个rand()
后,问题就消失了。我最终得到了这个:
srand(time(NULL));
rand();
int seed = rand();
我想弄清楚为什么会发生这种情况。。。但与此同时,这是有效的。
- 递归函数计算序列中的平方和(并输出过程)
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 请解释"函数1(p1,p2,p3);"的输出
- C++:将控制台输出存储在宏中更好吗
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 为什么我的代码在输出中增加了93天
- 如何从void函数输出字符串
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- AES加密到解密未正确输出
- 如何将c++程序的一些输出传递给shell,以便在shell中使用
- 使用C++程序合并排序没有得到正确的输出
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- C++格式化输出问题
- 输出在我的字符数组范围之外,同时使用 rand()
- Rand() 返回相同或非常相似的输出值
- C++可预测Rand()输出
- rand()有时会输出空行,其他时候它也可以正常工作
- CryptGenRandom输出与rand()调用不同
- 随机数(rand)不能输出未知字符