伪随机与实验

版权声明:本文为博主原创文章,可以转载但必须注明出处。 https://blog.csdn.net/nirendao/article/details/84405398

众所周知,计算机产生的是伪随机数。所谓伪随机,就是:当知道种子和随机产生算法之后,就可以完全确定出随机数序列了。并且这个随机数序列是循环重复的。不同的随机产生算法的循环周期不同;好的随机产生算法的循环周期会很长。

有的文章提到,可以通过引入系统以外的变量来达到真随机的目的,比如“Unix 维护了一个熵池,不断收集非确定性的设备事件,即机器运行环境中产生的硬件噪音,来作为种子”。个人觉得,这本质上仍然是伪随机,只是利用硬件噪声生成种子而已,这和使用时间戳作为种子没有本质区别。只是别人可能没法知道种子是啥,因此也无法推测出随机序列。而该文中提到的 /dev/random (其实还有一个 /dev/urandom)是一个字符文件,如果读取它,会取得随机字符,而不是随机数字。当然我们可以想办法把随机字符转换成随机数字。关于如何使用 /dev/random 和 /dev/urandom, 可以参见这篇文章,本文不再赘述。

有的文章中提到,C++中的随机数序列的循环周期是65536或2^32. 本文接下来的部分将验证一下计算机产生的是否是伪随机,以及循环周期是多少。

先看代码:

#include <iostream> 
#include <cstdlib> 
#include <ctime>
using namespace std;

void gen_rand_int(unsigned int seed)
{
    // srand((unsigned)time(NULL));  
    srand(seed);  
    for(int i = 0; i < 10;i++ )  
        cout << rand() << ' ';  
    cout << endl;
}

void gen_2_rand_int(unsigned int seed)
{
    srand(seed);  
    long max_unsigned_int = 4294967295;
    int i_1, i_65536, i_65537, i_max_ui, i_max_ui_1; 
    long yi = 100000000;
    long tmp;
    for (long i=0; i<=max_unsigned_int; ++i) {
        tmp = rand();
        if (i == 0) 
            i_1 = tmp; 
        else if (i == 65535) 
            i_65536 = tmp;
        else if (i == 65536) 
            i_65537 == tmp;
        else if (i == max_unsigned_int) 
            i_max_ui = tmp; 
        
        if (i % yi == 0) 
            cout << i/yi << " Yi have been generated" << endl;
    }
    cout << "the first number is: " << i_1 << endl;
    cout << "the 65536" << " number is " << i_65536 << endl;
    cout << "the 65537" << " number is " << i_65537 << endl;
    cout << "the " << max_unsigned_int+1 << " number is " << i_max_ui << endl;
    cout << "the " << max_unsigned_int+2 << " number is " << rand() << endl;
}

int main() 
{  
    gen_rand_int(10);
    gen_rand_int(10);  // print the same as above
    gen_2_rand_int(10);
    
    return 0; 
}

然后,给出观察结论:

1. 在某一台机器上,由main函数中连续2次调用 gen_rand_int(10) 的打印结果完全一致。
   仍然在这一台机器上,多次运行该二进制可执行文件,gen_rand_int(10)的打印结果完全一致。
   由此可以看出,伪随机的含义就是,一旦知道了种子和算法,随机数序列就是确定的了。这一点在下面还可以继续看出。

2. 笔者将以上程序拿到5台机器上跑,在相同的种子下,结果很有趣:
 

  前10个数 第65536个数 第65537个数 第2^32个数 第2^32+1个数
A - Ubuntu 18.04 ABCD相同 1174608988 每次都变 1843318998 1902554484
B - Ubuntu 16.04 ABCD相同 1174608988 每次都变 1843318998 1902554484
C - CentOS 7.3 ABCD相同 1174608988 0 1843318998 1902554484
D - RHEL 7.5 ABCD相同 1174608988 0 1843318998 1902554484
E - Cygwin on Windows 与ABCD不同 与ABCD不同 0 与ABCD不同 与ABCD不同

由上可以看出,

a. 一般来说,在给定种子时,在各Linux系统上C++程序取得的随机数序列基本都是一致的; 

b. 第65537个随机数似乎比较特别,Ubuntu每次跑都会是一个不同的值,似乎有点“随机”,而Red Hat系列的Linux此处总为0

c. Cygwin系统的随机数取得与真实Linux系统的随机数差别较大,可能是取随机数的库使用的是Windows上的库。

d. 没有看出来循环周期是多少,但基本可以确定不是65536或2^32;根据网上有些文章,可能采用的是一种较好的随机生成算法,其循环周期远大于2^32. 

(完)

猜你喜欢

转载自blog.csdn.net/nirendao/article/details/84405398
今日推荐