zoukankan      html  css  js  c++  java
  • 随机数真的是随机的么? ---让菠菜、*等裤衩赔穿的漏洞

      日常业务中,经常会生成随机数,这里以C++为例,常见的随机数生成方法如下:原理很简单,先生成一个随机数生成器,指定种子,然后生成随机数;

    #include <iostream>
    #include <windows.h>
    
    int main()
    {
        printf("time(0)=%d",time(0));
        srand(0);
        for(int i=0;i<=10;i++){
            printf("%d
    ",rand());
        }
        system("pause");
        
    }

      根据随机数的定义,每次生成的数不一样才能叫随机数。然而上面这段代码真是这样的么?我们看看效果了:生产的10个数确实不一样啊,这不就是我们想要的效果么? 感兴趣的读者可以自行尝试多生成一些数,看看每次生成的数是不是都不一样!

      

            然而这样就结束了么?图样图森破!同样的代码,我们多运行几次实例看看了,效果如下:不同的时间点我生成了4个不同的实例,然后每次生成实例产生的随机数都是一样的,这是不是很“毁三观”啊!

      

       我明明想生成随机数,为啥每次生成实例产生的数据都是一样的了?换句话说:srand生成随机数的原理是啥了?

       计算机的随机数都是由伪随机数,即是由小M多项式序列生成的,其中产生每个小序列都有一个初始值,即随机种子。(注意: 小M多项式序列的周期是65535,即每次利用一个随机种子生成的随机数的周期是65535,当你取得65535个随机数后它们又重复出现了。)我们知道 rand() 函数可以用来产生随机数,但是这不是真正意义上的随机数,是一个伪随机数,是根据一个数(我们可以称它为种子)为基准以某个递推公式推算出来的一系列数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数,所以我们运行不同实例时产生的“随机数”居然是一样的,都是相同种子惹的祸!所以我们把种子用当前时间来代替,重新更改后的代码如下:

    #include <iostream>
    #include <windows.h>
    
    int main()
    {
        int seed = time(0);
        printf("seed=%d", seed);
        srand(seed);
        for(int i=0;i<=10;i++){
            printf("%d
    ",rand());
        }
        system("pause");
    }

      多运行几个实例,每次产生的数确实不一样了:这样就万事大吉、高枕无忧了?

        

         前面说了:相同的种子,产生的伪随机数是一样的,是不是也可以反过来猜想: 根据伪随机数倒推种子了?比如我先在看到的数字是22843、6380、25403、7962,是不是能倒推出种子是16210637719041了?一旦倒推出种子,我是不是也能成功预测第5个数字是13894了?穷举找seed的代码如下:

    int num[] = { 22843,6380,25403,7962 };
        int seed = time(0);
        bool bfind = false;
        while (seed--) 
        {
            srand(seed);
            for (int i=0;i<4;i++) 
            {
                if (num[i]!=rand()) 
                {
                    bfind = false;
                    break;
                }
                bfind = true;
            }
            printf("%d is not the seed,continue!
    ", seed);
            if (bfind) 
            {
                printf("find the seed:%d 
    ", seed);
                break;
            }
               
        }

      一旦找到seed,就能用这个seed继续生成剩下的数字,准确预测了!

      注意:实战时,因为不知道菠菜站点启动服务器的时间,所以这个计算量较大,一般都是用服务器+多线程跑的,这里只是介绍最核心的原理,感兴趣的小伙伴可以自行尝试!

    1、https://www.runoob.com/w3cnote/cpp-rand-srand.html  C++ rand 与 srand 的用法

  • 相关阅读:
    【BZOJ 2124】【CodeVS 1283】等差子序列
    【BZOJ 1036】【ZJOI 2008】树的统计Count
    【BZOJ 1901】【ZJU 2112】Dynamic Rankings
    【BZOJ 3924】【ZJOI 2015】幻想乡战略游戏
    【BZOJ 4103】【THUSC 2015】异或运算
    【BZOJ 4513】【SDOI 2016】储能表
    【HDU 3622】Bomb Game
    【BZOJ 3166】【HEOI 2013】Alo
    【BZOJ 3530】【SDOI 2014】数数
    【BZOJ 4567】【SCOI 2016】背单词
  • 原文地址:https://www.cnblogs.com/theseventhson/p/14771241.html
Copyright © 2011-2022 走看看