[记录点滴] 一个解决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. 《花100块做个摸鱼小网站! 》第十篇—响应式布局适配PC端和移动端

    ️基础链接导航️ 服务器 → ️ 阿里云活动地址 看样例 → 摸鱼小网站地址 学代码 → 源码库地址 一.前言 大家好呀,我是summo,小网站一直有个问题,就是PC端的样式和移动端的样式是两套,并且 ...

  2. (Redis基础教程之十三) 如何从命令行更改Redis的配置

    介绍 Redis是一个开源的内存中键值数据存储.Redis有几个命令,可让您即时更改Redis服务器的配置设置.本教程将介绍其中一些命令,并说明如何使这些配置更改永久生效. 如何使用本指南 本指南以备 ...

  3. Xdebug+Phpstorm本地调试

    很久不用php进行开发, debug插件的安装与配置都忘完了, 看了下自己之前记录的一篇文章, 有点太乱了, 这里简约介绍下,方便后面快捷使用 XDebug下载地址: https://xdebug.o ...

  4. 记ios的input框获取焦点之后界面放大问题

    在移动端开发项目中,发现页面在使用 iPhone 访问的时候,点击 input 和 textarea 等文本输入框聚焦 focus() 时,页面会整体放大,而且失去焦点之后页面不能返回原来的样子.检查 ...

  5. Teable 团队 Sealos 最佳实践,创业公司的完美选择

    大家好,我是开源多维表格项目 Teable 的创始人陈加贝. 作为飞书多维表格的最早期负责人,我参与并见证了这个产品从 0 到 1 的全过程.这段经历也让我深入理解了企业在数据协作方面的真实需求. 以 ...

  6. 腾讯云TKE-PV使用COS存储案例:容器目录权限问题

    背景 在TKE的集群中创建工作负载并把某一个对应的cos桶的根目录挂载到/data目录,在镜像构建的时候有把/data目录设置权限为755,但是运行容器后成功挂载cos桶的根目录到/data/目录,发 ...

  7. OpenTelemetry.NET API

    OpenTelemetry.NET API Status and Releases Tracing Metrics Logging 1.0 Alpha Beta 安装 dotnet add packa ...

  8. 金Gien乐道 | 8月热点回顾

    中电金信2023年中工作会议:加快推进以"源启"为基石的业务模式转型 ​​8月12日,中电金信2023年中工作会议在上海召开.会议贯彻落实中国电子2023年中工作会议精神,总结上半 ...

  9. cocos2d 的故事

    https://en.wikipedia.org/wiki/Cocos2d The history of Cocos2d in a glimpse – RETRO.MOE http://los-coc ...

  10. 【Python自动化】selenium简单应用

    准备工作 查询浏览器版本 chrome://version/ 下载驱动 https://chromedriver.storage.googleapis.com/index.html 下载的驱动版本要和 ...