[记录点滴] 一个解决Lua 随机数生成问题的办法

0x00 摘要

本文是开发中的简略记录,具体涉及知识点有:Lua,随机数。

0x01 背景

Lua语言生成随机数需要用到两个函数:

  • math.randomseed(n) : 用法是 接收一个整数n作为随即序列的种子。
  • math.random([n [,m]]) : 用法有三种:
    • random(),产生[0, 1)之间的浮点随机数。
    • random(n),产生[1, n]之间的整数。
    • .random(m, n),产生[n, m]之间的整数。

0x02 问题

2.1 Lua随机数函数问题

Lua语言的随机数函数存在问题:

  1. 第一个随机数总是固定,而且常常是最小的那个值
  2. 如果 seed 很小或者seed 变化很小,产生的随机序列仍然很相似。
  3. 如果很短的时间内多次运行这个程序,那么你得到的随机序列会是几乎不变的。

原因是LUA的random只是封装了C的rand函数,使得random函数有一定的缺陷,

2.2 C语言随机数函数问题

其实计算机产生的随机数都是依照事先写好的算法执行出来的,行为是可以预测的,所以计算机产生的随机数都不是真正意义上的随机数,只是伪随机数,是以一个真值(也称为种子)为初始条件,然后用一定的算法不停迭代产生随机数。

C语言 rand的内部是用线性同余法做的,因为其周期特别长,所以在一定范围内可以看成是随机的。

线性同余方法(LCG)是一种产生伪随机数的方法。它是根据递归公式实现:

RandSeed = (A * RandSeed + B) % M

线性同余法最重要的是定义了三个整数,乘数 A、增量 B和模数 M,其中A, B, M是产生器设定的常数。 LCG的周期最大为 M,但大部分情况都会少于M。要令LCG达到最大周期,应符合以下条件:

  • B,M互质;
  • M的所有质因数都能整除A-1;
  • 若M是4的倍数,A-1也是;
  • A,B,N[0]都比M小;
  • A,B是正整数。

0x03 解决方案

问题的解决方案就是:让用户使用randomseed先设一个随机种子。比如在服务器启动的时候设置一个随机种子,让系统产生的随机序列不相同。

3.1 移位轮转 + 线性同余

一种常见的办法是以 time 函数返回的秒数为基准。但是因为如果需要短期内频繁使用随机数,这个方法不可行,因为容易产生类似数字,所以就把 time返回的数值字串倒过来(低位变高位), 再取高位几位。这样即使 time变化很小, 但是因为低位变了高位, 种子数值变化却很大,就可以使伪随机序列生成的更好一些。

这其实是一种 “移位轮转“ 的思想

math.randomseed(tostring(os.time()):reverse():sub(1, 6))

3.2 Linux随机种子

在linux下,我们可以使用 /dev/random以及/dev/urandom产生随机种子。

其原理是利用当前系统的熵池来计算出一定数量的随机比特,其中熵池是根据当前系统的“环境噪音”,它是由很多参数共同评估的,如内存的使用,文件使用量等等,环境噪音直接影响着所产生的随机种子的有效性。

/dev/random与/dev/urandom之间存在区别:

  • urandom即”unlocked random”,,每次打开并读取/dev/urandom时,会从熵池中随机返回所需要的字节数。/dev/urandom的读取操作不会阻塞,因为它会重复使用熵池中的数据以产生随机数;
  • /dev/random则是每次读之前去检查熵池是否为空,若为空,则需要阻塞并去更新熵池。

对于我们来说,需要阻塞总是不好的,因此 urandom 更加理想

3.3 移位轮转 + 线性同余 + Linux随机种子

我们可以采用的是在之前办法上,加入Linux随机种子,代码如下:

local _M = {}

function _M.random_seed()
local in_file = io.open("/dev/urandom", "r")
if in_file ~= nil then
local d= in_file:read(4)
math.randomseed(os.time() + d:byte(1) + (d:byte(2) * 256) + (d:byte(3) * 65536) + (d:byte(4) * 4294967296))
else
math.randomseed(tostring(os.time()):reverse():sub(1, 7))
end
end return _M

当然也可以再结合起来设置

math.randomseed(tostring(os.time()):reverse():sub(1, 6)+ d:byte(1) + (d:byte(2) * 256) + (d:byte(3) * 65536) + (d:byte(4) * 4294967296))

0xFF 参考

线性同余方法(LCG)产生随机数

Linux下随机数生成的函数与常见方法

[记录点滴] 一个解决Lua 随机数生成问题的办法的更多相关文章

  1. [记录点滴]授人以渔,从Tensorflow找不到dll扩展到如何排查问题

    [记录点滴]授人以渔,从Tensorflow找不到dll扩展到如何排查问题 目录 [记录点滴]授人以渔,从Tensorflow找不到dll扩展到如何排查问题 0x00 摘要 0x01 引言 0x02 ...

  2. 30多条mysql数据库优化方法,千万级数据库记录查询轻松解决(转载)

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...

  3. 分享一个解决MySQL写入中文乱码的方法

    分享一个解决MySQL写入中文乱码的方法 之前有发帖请教过如何解决MySQL写入中文乱码的问题.但没人会,或者是会的人不想回答.搜索网上的答案并尝试很多次无效,所以当时就因为这个乱码问题搁浅了一个软件 ...

  4. 转载:30多条mysql数据库优化方法,千万级数据库记录查询轻松解决

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...

  5. 反射记录点滴——Field

    反射记录点滴 1. 反射获取类的属性 Class.getDeclareFileld(String name) 返回一个Filed对象,该对象反映此Class对象所表示的类或接口的指定已声明字段. Cl ...

  6. Requirejs加载超时问题的一个解决方法:设置waitSeconds=0

    有时Requirejs会遇到加载js超时问题 除了排查js脚本问题,网络问题以外的一个解决方法是加大Require的等待时间waitSeconds,或者直接设置为0,这个参数的意义是:The numb ...

  7. 第一个Cocos2d-x Lua游戏

    我们的编写的第一个Cocos2d-x Lua程序,命名为HelloLua,从该工程开始学习其它的内容.创建工程我们创建Cocos2d-x Lua工程可以通过Cocos2d-x提供的命令工具cocos实 ...

  8. 批处理命令篇--配置免安装mysql 5.6.22, 以及1067错误的一个解决方法

    mysql 服务启动出现1067错误的一个解决方法: 当服务启动出现1067错误时,可查看“windows 事件查看器”,发现类似错误提示 Can't find messagefile 'F:\    ...

  9. Lua:Nginx Lua环境配置,第一个Nginx Lua代码

    一.编译安装LuaJIT Lua:编译安装LuaJIT,第一个Lua程序 http://blog.csdn.net/guowenyan001/article/details/48250427 二.下载 ...

  10. 采用boosting思想开发一个解决二分类样本不平衡的多估计器模型

    # -*- coding: utf-8 -*- """ Created on Wed Oct 31 20:59:39 2018 脚本描述:采用boosting思想开发一个 ...

随机推荐

  1. python之数据库管理工具sandman2

    文档:Welcome to sandman2's documentation! - sandman2 0.0.1 documentation [安装] pip install sandman2 安装成 ...

  2. API之接口服务

    聚合数据: https://www.juhe.cn/ 百度api市场: https://apis.baidu.com/

  3. yum之镜像加速

    有没有遇到使用yum安装软件慢如龟,默认的系统使用的是centos的镜像源,我们可以修改为国内镜像源加速软件安装 163)http://mirrors.163.com/.help/centos.htm ...

  4. CCPC Henan Provincial Contest 2020

    CCPC Henan Provincial Contest 2020 Problem B. 广告投放 n集节目按顺序播出,节目组决定在某些节目中投放广告,节目最初播出时有m名观众,若\(i\)集投放广 ...

  5. ip addr没有ip显示?

    重新启动网络 service NetworkManager stop systemctl restart network

  6. Spring AOP基础、快速入门

    介绍 AOP,面向切面编程,作为面向对象的一种补充,将公共逻辑(事务管理.日志.缓存.权限控制.限流等)封装成切面,跟业务代码进行分离,可以减少系统的重复代码和降低模块之间的耦合度.切面就是那些与业务 ...

  7. 【MyBatis】学习笔记04:配置文件模板

    [Mybatis]学习笔记01:连接数据库,实现增删改 [Mybatis]学习笔记02:实现简单的查 [MyBatis]学习笔记03:配置文件进一步解读(非常重要) 目录 IDEA配置模板的地方 核心 ...

  8. server.error.include-message

    使用的thymeleaf模板引擎,默认前端无法获取message和exception 想要在前端获取到message和exception,配置一下配置 server.error.include-exc ...

  9. 在Deepin系统上配置微软Windows远程桌面服务

    . 前言 本文主要讲解如何在deepin系统上安装和配置Xrdp远程桌面. Xrdp是微软的远程桌面协议(Remote Desktop Protocol, RDP)的开源版本.在Linux系统上安装X ...

  10. (八).NET6.0添加通用的Redis功能

    1.添加包:StackExchange.Redis 2.在配置文件里面,新建Redis的有关配置信息 Name是别名,可以任意起.Ip是Redis的服务端地址,例如安装本地,就是127.0.0.1,端 ...