C基础 寻找随机函数的G点详解

引言

随机函数算法应该是计算机史上最重要的十大算法之一吧. 而C中使用的随机函数

#include <stdlib.h>

_Check_return_ _ACRTIMP int __cdecl rand(void);

本文主要围绕rand 函数找到G点. 就是伪随机函数的周期值.

关于rand 源码, 可以从Linux底层源码 glibc中找.  看了一下大约4个文件. 算法比较复杂. 感觉很稳定.

这里不探讨随机算法的实现. 只为了找到 随机函数周期.

前言

现在window上测试. 测试代码 main.c

#include <stdio.h>
#include <stdlib.h>

#define _INT_R    (128)
#define _INT_FZ    (10000000)

// 得到rand() 返回值, 并写入到文件中
int getrand(long long *pcut) {
  static int _cut = 0;
  long long t = *pcut + 1;

  int r = rand();

  // 每次到万再提醒一下
  if(t % _INT_FZ == 0)
    fprintf(stdout, "%d 个数据跑完了[%d, %lld]\n", _INT_FZ, _cut, t);

  if(t < 0) { // 数据超标了
    ++_cut;
    fprintf(stderr, "Now %d T > %lld\n", _cut, t - 1);
    *pcut = 0; // 重新开始一轮
  }

  *pcut = t;
  return r;
}

/*
 * 验证 rand 函数的周期
 */
int main(int argc, char* argv[]) {
  int rbase[_INT_R];
  int i = -1, r;
  long long cut = 0;

  // 先产生随机函数
  while(++i < _INT_R)
    rbase[i] = getrand(&cut);

  // 这里开始随机了
  for(;;) {
    r = getrand(&cut);
    if (r != rbase[0])
      continue;

    for(i=1; i<_INT_R; ++i) {
      r = getrand(&cut);
      if(r != rbase[i])
        break;
    }

    // 找见了数据
    if(i == _INT_R) {
      printf("Now T = %lld\n", cut);
      break;
    }
  }

  system("pause");
  return 0;
}

主要思路是 _INT_R 128个数重叠那我们就认为. 已经找到这个周期了.

测试结果截图是

主要采用 Release  X64 编译. 为了检验上面结果是可以接受的, 将 _INT_R 改成1024 重新编译一次.

运行结果如下:

综合上面我们找见了 window 上 rand 函数的 G点 是

2147483776 - 128 =  214748248

2147484672 - 1024 = 2147483648

因而得到 window 上 VS2015 编译器的 rand G点 是 2147483648.

G点在游戏中用的很多. 例如抽奖, 掉装备, 暴击等等.

正文

1. 在linux 上试试水

在linux上试试 测试代码基本一样 rand2.c 如下

#include <stdio.h>
#include <stdlib.h>

#define _INT_R    (1024)
#define _INT_FZ    (100000000)

// 得到rand() 返回值, 并写入到文件中
int getrand(long long *pcut) {
  static int _cut = 0;
  long long t = *pcut + 1;

  int r = rand();

  // 每次到万再提醒一下
  if(t % _INT_FZ == 0)
    fprintf(stdout, "%d个数据又跑完了[%d, %lld]\n", _INT_FZ, _cut, t);

  if(t < 0) { // 数据超标了
    ++_cut;
    fprintf(stderr, "Now %d T > %lld\n", _cut, t - 1);
    *pcut = 0; // 重新开始一轮
  }

  *pcut = t;
  return r;
}

/*
 * 验证 rand 函数的周期
 */
int main(int argc, char* argv[]) {
  int rbase[_INT_R];
  int i = -1, r;
  long long cut = 0;

  // 先产生随机函数
  while(++i < _INT_R)
    rbase[i] = getrand(&cut);

  // 这里开始随机了
  for(;;) {
    r = getrand(&cut);
    if (r != rbase[0])
      continue;

    for(i=1; i<_INT_R; ++i) {
      r = getrand(&cut);
      if(r != rbase[i])
        break;
    }

    // 找见了数据
    if(i == _INT_R) {
      printf("Now T = %lld\n", cut);
      break;
    }
  }

  return 0;
}

编译命令

gcc -03 -o randc2.out rand2.c

最后运行结果, 等了 好久还是没出来.

Linux 上的rand 函数写的很有水准, 分布的很随机. 总而言之这个随机值比较大. 但一定存在的.

有兴趣的可以按照上面思路优化跑一跑. 这边Ubuntu 是虚拟机跑的慢.

2. 继续扩展, 减小rand 返回 MAX值 试试水

修改上面 getrand  函数

// _INT_RMAX 表示随机数范围 [0, 100)
#define _INT_RMAX  (100)
#define _INT_R    (1024)
#define _INT_FZ    (10000000)

// 得到rand() 返回值, 并写入到文件中
int getrand(long long *pcut) {
  static int _cut = 0;
  long long t = *pcut + 1;

  int r = rand() % _INT_RMAX;

  // 每次到万再提醒一下
  if (t % _INT_FZ == 0)
    fprintf(stdout, "%d 个数据跑完了[%d, %lld]\n", _INT_FZ, _cut, t);

  if (t < 0) { // 数据超标了
    ++_cut;
    fprintf(stderr, "Now %d T > %lld\n", _cut, t - 1);
    *pcut = 0; // 重新开始一轮
  }

  *pcut = t;
  return r;
}

添加 了 取余看是否, 影响G点 测试结果

  

发现G点没有变化.

可以有推论: rand() 周期不随着 二次 mod取余而改变.

因而可以放心 mod使用 伪随机函数. G点还是那么大.

3. 最后, 赠送一个常用的 [min, max] 之间的随机函数

/*
 * 返回 [min, max] 区间的随机函数
 * min  : 起始位置
 * max  : 结束位置
 *    : 返回[min, max]区间之内的位置
 */
extern int random(int min, int max);

/*
 * 返回 [min, max] 区间的随机函数
 * min  : 起始位置
 * max  : 结束位置
 *    : 返回[min, max]区间之内的位置
 */
int
random(int min, int max) {
  assert(min < max);
  // 正常情况
  return rand() % (max - min + 1) + min;
}

测试demo 代码 结构如下

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>

/*
 * 返回 [min, max] 区间的随机函数
 * min  : 起始位置
 * max  : 结束位置
 *    : 返回[min, max]区间之内的位置
 */
extern int random(int min, int max);

/*
 * C 基础, 使用随机函数
 */
int main(int argc, char* argv[]) {

  int min = -5, max = 5;
  int i = 0;

  // 开始统一 初始化种子
  srand((unsigned)time(NULL));

  while(i < 100) {
    printf("%3d ", random(min, max));
    if (++i % 10 == 0)
      putchar('\n');
  }

  system("pause");
  return 0;
}

/*
 * 返回 [min, max] 区间的随机函数
 * min  : 起始位置
 * max  : 结束位置
 *    : 返回[min, max]区间之内的位置
 */
int
random(int min, int max) {
  assert(min < max);
  // 正常情况
  return rand() % (max - min + 1) + min;
}

测试结果是

基本比较稳定. 一切都在预料之中.

总结 本文 得出两个 推论

  a. rand()伪随机函数, 存在G点. 并且可以找到

  b. G点 不随着 二次 mod 取余改变.

后记

错误是难免的, 预祝明天愉快~~

以上这篇C基础 寻找随机函数的G点详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • C/C++产生随机数函数简单介绍

    计算机的随机数都是由伪随机数,即是由小M多项式序列生成的,其中产生每个小序列都有一个初始值,即随机种子.(注意: 小M多项式序列的周期是65535,即每次利用一个随机种子生成的随机数的周期是65535,当你取得65535个随机数后它们又重复出现了.) 我们知道rand()函数可以用来产生随机数,但是这不是真正意义上的随机数,是一个伪随机数,是根据一个数(我们可以称它为种子)为基准以某个递推公式推算出来的一系列数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数,

  • c语言随机数函数示例

    void srand( unsigned int seed );head file is <stdlib.h>RemarksThe srand function sets the starting point for generating a series of pseudorandom integers. To reinitialize the generator, use 1 as the seed argument. Any other value for seed sets the g

  • C语言中用于产生随机数的函数使用方法总结

    在UNIX操作系统和window的操作系统上,我们知道有一个函数rand,它就是用来产生随机数的函数API接口,那么它的原理如何实现? 如果约定a1=f(seed),an+1=f(an),那么可以得到一个序列a1,a2,a3..an,那么要制作一个伪随机函数rand,只需要让它每调用一次就返回序列的下一个元素就行.其实就是相当于第1次调用rand返回a1,第2次返回a2,-,第n次返回an,这样每次返回的数值都不一样,也就是相当于随机数了.但是其实不是真正的随机数,真正的随机数是使用物理现象产生

  • c语言中 基于随机函数的使用详解

    在C语言中,rand()函数可以用来产生随机数,但是这不是真真意义上的随机数,是一个伪随机数,是根据一个数,我们可以称它为种子,为基准以某个递推公式推算出来的一系数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数,当计算机正常开机后,这个种子的值是定了的,除非你破坏了系统,为了改变这个种子的值,C提供了srand()函数,它的原形是void srand( int a). 可能大家都知道C语言中的随机函数random,可是random函数并不是ANSI C标准,

  • C基础 寻找随机函数的G点详解

    引言 随机函数算法应该是计算机史上最重要的十大算法之一吧. 而C中使用的随机函数 #include <stdlib.h> _Check_return_ _ACRTIMP int __cdecl rand(void); 本文主要围绕rand 函数找到G点. 就是伪随机函数的周期值. 关于rand 源码, 可以从Linux底层源码 glibc中找.  看了一下大约4个文件. 算法比较复杂. 感觉很稳定. 这里不探讨随机算法的实现. 只为了找到 随机函数周期. 前言 现在window上测试. 测试代

  • Mysql的基础使用之MariaDB安装方法详解

    我首次用mysql是在ubuntu上,现在用的是linux 中的Red Hat 分支的centOS 7 ,安装时发现通常用的都是MariaDB 来代替mysql,通过资料查询发现Mariadb是mysql的其中的一种分支,由mysql的创始人带领的团队所开发的mysql分支的一种版本,因为mysql受到被Oracle收购后的日渐封闭与缓慢的更新,众多Linux发行版逐渐抛弃了这个人气开源数据库,使MySQL在各大Linux发行版中的失势由于不满MySQL被Oracle收购后的日渐封闭与缓慢的更新

  • python机器学习基础线性回归与岭回归算法详解

    目录 一.什么是线性回归 1.线性回归简述 2.数组和矩阵 数组 矩阵 3.线性回归的算法 二.权重的求解 1.正规方程 2.梯度下降 三.线性回归案例 1.案例概述 2.数据获取 3.数据分割 4.数据标准化 5.模型训练 6.回归性能评估 7.梯度下降与正规方程区别 四.岭回归Ridge 1.过拟合与欠拟合 2.正则化 一.什么是线性回归 1.线性回归简述 线性回归,是一种趋势,通过这个趋势,我们能预测所需要得到的大致目标值.线性关系在二维中是直线关系,三维中是平面关系. 我们可以使用如下模

  • Go语言基础函数基本用法及示例详解

    目录 概述 语法 函数定义 一.函数参数 无参数无返回 有参数有返回 函数值传递 函数引用传递 可变参数列表 无默认参数 函数作为参数 二.返回值 多个返回值 跳过返回值 匿名函数 匿名函数可以赋值给一个变量 为函数类型添加方法 总结 示例 概述 函数是基本的代码块,用于执行一个任务 语法 函数定义 func 函数名称( 参数列表] ) (返回值列表]){ 执行语句 } 一.函数参数 无参数无返回 func add() 有参数有返回 func add(a, b int) int 函数值传递 fu

  • Java中随机函数变换的示例详解

    目录 说明 解决的问题 问题1 问题2 问题3 问题4 说明 本示例中基于 Java ,其他语言也有类似的 API 解决的问题 问题1 Java 中 Math.random()函数是等概率返回区间[0,1)中的任意一个小数.即x < 1情况下,[0,x)中的数出现的的概率是x,如果我们要将x < 1情况下,[0,x)中的数出现的的概率调整成x^2,应该如何做? 问题1思路 由于[0,x)的概率是x,那么调用两次Math.random(),如果较大的那个值也要在[0,x)区间内,那么两次调用都必

  • JS中正则表达式全局匹配模式 /g用法详解

    本文章来详细介绍js中正则表达式的全局匹配模式 /g用法,代码如下: var str = "123#abc"; var re = /abc/ig; console.log(re.test(str)); //输出ture console.log(re.test(str)); //输出false console.log(re.test(str)); //输出ture console.log(re.test(str)); //输出false 在创建正则表达式对象时如果使用了"g&q

  • java基础(System.err和System.out)详解

    今天有位同事在使用System.err和System.out遇上了一些小问题. 看了些资料总结下: 1.JDK文档对两者的解释: out:"标准"输出流.此流已打开并准备接受输出数据.通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标. err:"标准"错误输出流.此流已打开并准备接受输出数据.通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标.按照惯例,此输出流用于显示错误消息,或者显示那些即使用户输出流(变量 out 的值)已经重

  • Java web基础学习之开发环境篇(详解)

    Tomcat + Eclipse添加Java EE插件 因为之前进行Java SE学习已经配置了JDK,安装了Eclipse for Java SE,所以选择了在Eclipse上添加插件的方式来配置Web开发环境 Tomcat是免安装版,直接解压即可: Eclipse中"帮助-安装新软件",work with处选择Mars - http://download.eclipse.org/releases/mars(注意对应自己版本): 选择Web.Java EE那个选项进行安装即可,如果报

  • C#学习笔记- 随机函数Random()的用法详解

    Random.Next() 返回非负随机数: Random.Next(Int) 返回一个小于所指定最大值的非负随机数 Random.Next(Int,Int) 返回一个指定范围内的随机数,例如(-100,0)返回负数 1.random(number)函数介绍 见帮助文档,简单再提一下,random(number)返回一个0~number-1之间的随机整数.参数number代表一个整数. 示例: trace(random(5)); 2.Math.random() 见帮助文档.返回一个有14位精度的

  • 关于Laravel-admin的基础用法总结和自定义model详解

    总结laravel-admin展示用到的基本方法 基础用法 自定义model 当列表数据获取有特定条件或自己写ORM方法时可以用到,支持排序 $grid->model()->select('id','name')->where('status',1)->groupBy('project_id'); $grid->model()->select('id','name')->where('status',1)->groupBy('project_id'); //

随机推荐