也许很多人会奇怪为什么使用LUA的时候,第一个随机数总是固定,而且常常是最小的那个值,下面我就简要的说明一下吧,说得不好,还请谅解。我现在使用的4.0版本的LUA,看的代码是5.0的,呵呵

LUA4.0版本中的自带函数库中有两个关于随机数的函数,一个是random,一个是randomseed。random有两个参数,用来设置随机数的范围,比如random(1,100)设置随机数的范围为1至100之间。由于C中所产生的随机序列是固定的,并且第一个随机数比较小,只有41。LUA重新设计了random函数,使得它可以产生范围固定的随机数,但由于LUA的random只是封装了C的rand函数,使得random函数也有一定的缺陷,那就是如果random的两个输入参数的值相差很小的时候,那么随机序列的第一个随机数就会和第一个输入参数很接近,比如第一次调用random(1,100)的时候,返回值肯定是1,只有相差大于799时,如random(1,800)第一次调用才会返回2,也是很接近1。
       
由于这个原因,为了实现真正的随机,那么第一次就不能让玩家调用random函数,不然玩家就可以获得一些低概率的东西了。比如if
random(1,100) == 1 then ......
do,看起来是1%的的概率,但是第一次执行的时候是100%成立的,存在一定的隐患。解决这个问题的方法有两个,一就是第一次random函数不能让玩家执行,二就是使用randomseed先设一个随机种子。对于第一种方法,可能还是有一定的风险,毕竟随机序列还是固定的,玩家第一次调用random的时候还是得到有规律的返回值。第二种方法比较安全,在服务器启动的时候设置一个随机种子,让系统产生的随机序列不相同,但使用randomseed的时候也还要注意一个问题,那就是做种子的数要足够的大,大于10000就行了。不然randomseed所产生的随机序列的第一个值还是很小。原因是randomseed是直接封装了C的srand,如果种子的值太小,那么srand所产生的序列和默认序列(srand(1)所产生的序列)是相差不大的,序列的第一个值还是很小。
        因此,只要在服务器启动的时候调用一下randomseed(GetTime())就可以解决这个问题了。
        还要补充一下,LUA中产生随机数的算法还是有一些问题,比如执行random(1,3276700),它返回的值最后两位必为0。这是由LUA本身的随机函数算法决定的。
        还是简要介绍一下LUA中random函数的实现方法吧,主要由源码中的下面两行实现:
        lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
        lua_pushnumber(L, (int)floor(r*(u-m+1))+m);

其中m为random函数的第一个参数,u为第二个参数。由上面的代码可以看出,如果u-l太小,那么当r也很小的时候,r*(u-m+1)就会很小(小于1),那么再经过floor运算,最经结果就是m。这就可以解释为什么random产生的第一个随机数常常会很接近m。再来看看当m为0,u为327670的时候会怎样。在上面的代码里,RAND_MAX是一个宏,它的值是32767,也就是C语言中rand函数可以返回的最大值(不同的操作系统可能会有不一样的最大值)。当m为0,u为327670的时候,那么返回值就是floor(r*(327671)+0),我们再假设LUA与平台无关并且rand不会返回32767(上面用%避免了这个问题),那么r就可以简化为rand()/RAND_MAX,代入上式为floor(rand()*327671/32767)+0,就算rand()的返回值是32766,最终的结果也只有327660.99996......,经过floor运算后,最后那位数必为0。呵呵,我叫这样的随机数就伪随机数中的伪随机数。实际上面的公式是不允许化简的,即不能简单地把r代入r*(u-m+1),至于为什么,呵呵,因为r的值并不是rand()/RAND_MAX的值,r是double类型的,所以它只是一个和rand()/RAND_MAX很接近的数。

引用请注明出处。作者:yanjun_1982   日期:2006年10月11日

关于LUA中的随机数问题的更多相关文章

  1. lua中的随机数

    Lua 生成随机数需要用到两个函数:math.randomseed(xx), math.random([n [, m]]) 1. math.randomseed(n) 接收一个整数 n 作为随机序列种 ...

  2. Lua中的一些库(1)

    [数学库] 数学库(math)由一组标准的数学函数构成.这里主要介绍几个常用的函数,其它的大家可以自行百度解决. 三角函数(sin,cos,tan……)所有的三角函数都使用弧度单位,可以用函数deg( ...

  3. lua中基类和“继承机制”

    基类:基类定义了所有对于派生类来说普通的属性和方法,派生类从基类继承所需的属性和方法,且在派生类中增加新的属性和方法. 继承:继承是C++语言的一种重要机制,它允许在已定义的类的基础上产生新类. lu ...

  4. lua中实现异步资源读写

    同样还是更新方面的需求,当我们检测到版本是新安装的以后,要进行upd目录清除.如果使用os.execute执行 rm -rf ooxx 是非常快的但由于os.execute一旦报错,那整个lua进程就 ...

  5. lua中清空目录和递归创建目录

    lua中的 lfs.mkdir lfs.rmdir只能针对单个目录,且lfs.rmdir不能清空文件夹 于是我想到了使用os.execute 递归创建目录如下os.execute("mkdi ...

  6. lua中的string类型

    在lua中用union TString来表示字符串类型 lobject.h: 其中结构体tsv中 reserved字段表示字符串是不是保留关键字,hash是其哈希值,len是其长度.我们在TStrin ...

  7. 为什么说Java中的随机数都是伪随机数?

    什么是伪随机数?  1.伪随机数是看似随机实质是固定的周期性序列,也就是有规则的随机. 2.只要这个随机数是由确定算法生成的,那就是伪随机,只能通过不断算法优化,使你的随机数更接近随机.   (随机这 ...

  8. 在 lua 中实现函数的重载

    在 lua 中实现函数的重载.注:好吧,lua中原来可以实现重载...local function create() local arg_table = {} local function dispa ...

  9. lua中的table、stack和registery

    ok,前面准备给一个dll写wrapper,写了篇日志,看似写的比较明白了,但是其实有很多米有弄明白的.比如PIL中使用的element,key,tname,field这些,还是比较容易混淆的.今天正 ...

随机推荐

  1. Windows内存放血篇,突破物理内存的CopyOnWrite

      本篇以x86(开启PAE) 以及x64 Win7系统 不借助微软API突破内存的写拷贝机制进行讲述 https://bbs.pediy.com/thread-222949.htm   0x01 B ...

  2. python中级---->pymongo存储json数据

    这里面我们介绍一下python中操作mangodb的第三方库pymongo的使用,以及简单的使用requests库作爬虫.人情冷暖正如花开花谢,不如将这种现象,想成一种必然的季节. pymongo的安 ...

  3. slice 定义和用法

    定义和用法 slice() 方法可从已有的数组中返回选定的元素. 语法 arrayObject.slice(start,end) 参数 描述 start 必需.规定从何处开始选取.如果是负数,那么它规 ...

  4. sencha touch list 批量选择扩展(2013-7-29)

    扩展js代码 /* *list多选扩展 */ Ext.define('ux.SimpleList', { alternateClassName: 'simpleList', extend: 'Ext. ...

  5. X-Requested-With导致CSRF失败

    在漫漫渗透之路中,眼前一亮的发现一个站.Referer字段没有检查,POST参数中的动态token也没有检查,这不是带一波CSRF的节奏嘛.但是遇到一个之前我没遇到的问题导致我CSRF失败,这个问题或 ...

  6. FAX modem和传真协议简介

    FAX就是传真,传真通信是使用传真机,借助公用通信网或其他通信线路传送图片,文字等信息,并在接收方获得发送原件系统的副本的一种通信方式.传真通信是现代图像通信的重要组成部分,它是目前采用公用电话网传送 ...

  7. node path的几个路径问题

    __dirname: 总是返回被执行的 js 所在文件夹的绝对路径 __filename: 总是返回被执行的 js 的绝对路径 process.cwd(): 总是返回运行 node 命令时所在的文件夹 ...

  8. 让HTML标签、DIV、SPAN拥有focus事件和blur事件,聚焦和失焦

    DIV和其他普通标签是不具有onfocus和onblur事件的.INPUT和A标签为什么拥有?而DIV和SPAN等普通标签却没有?有时候我们习惯性用键盘的TAB来移动光标,仔细看你会发现,光标只在IN ...

  9. mysql if判断

    select if(SUBSTR('06622200556',1,2)='06',0,1) from t_member_product_adb limit 2 输出结果为:0,0

  10. 3种方法教你PS快速去掉水印

    方法一:使用选框工具 勾选水印部分: 按住Shift+f5选择内容识别: 然后 ctrl+d 取消选择,水印就去掉了 PS:其实这个方法有个快捷办法,直接使用选框工具选中之后,按Delete就可以弹出 ...