关于随机过程的一些记录

语言本身提供的简单的伪随机 一般是 均匀分布的 随机结果,在这样的基础上,我们通过一点简单的封装可以实现几个常见的随机要求:(以lua实现)

一,随机固定个数的不重复结果

在这之中,我们需要一个随机池来辅助随机过程,调用一次随机过程之后将其从随机池中删除,继续进行下次随机过程,最后得到想要的最终集合。理论上,这是选项们的一种排列组合结果。

i. 准备随机池:是一个数组,将你要随机的选项作为元素值,而数组下标是连续的,所以自然能够调用math.random(1,num)这样的函数:[5,8,6,1,7,4,9,5,8,4,6,3,1] 共13个选项。

math.random(1,13)这样就在 1,13之间随机一个数字,然后将其在随机池中对应的选项摘取出来加入不重复结果组。

local rand_poll = {5,8,6,1,7,4,9,5,8,4,6,3,1}   -- 随机池
local ret_array = {}   -- 作为结果组
local index = 0  -- 一次随机将返回随机池中的下标
for i=1, count , 1 do
  -- 调用真正随机规则,得到一个元素 的下标。
  index = get_random_one( rand_poll )
  -- 将元素加入到返回数组中
  table.insert( ret_array , rand_poll[index] )
  -- 将元素从随机池中删除
  table.remove( rand_poll , index )
end
-- ret_array 是最后的结果组

ii. 随机过程函数:将在随机池的下标中随机一个,以此返回随机池中的元素。

function get_random_one( array )
  if  #array <=0 then
  return  false
  end
  local rand_value = math.random( 1, #array )
  return  rand_value
end

二,具有概率判断的结果

想要实现的功能是,传入一个概率参数,根据概率判断本次随机是否成功。比如,本次随机一个结果,正确的概率是80%,非正确的概率是20%。

function get_one_by_probability( probability )
  -- probability is 浮点数
  local  boundary  =  probability * 100 
  --百分比,随机点数在[1,100]>均匀分布
  local  rand_value = math.random( 1 , 100 )
  if   rand_value  <  boundary then
     return  true    -- 随机到的点数在 范围内,结果算正确
  else
     return  false    -- 随机到的点数 超出范围,本次结果非正确
  end
end

三,具有随机库权重的实现过程

在随机过程一开始,需要通过随机池中的全部元素的权重累积得到权重的分配额,最终,权重总和作为随机上限。随机出结果之后,比对权重分配额,得到随机池中的对应id。

i. 准备条件:

-- array = {5,8,6,1,7,4,9,5,8,4,6,3,1}
-- obj_weight = {
  {id=1, weight=2} , 
  {id=2, weight=2} , 
  {id=3, weight=1} , 
  {id=4, weight=2} , 
  {id=5, weight=10} , 
  {id=6, weight=9} , 
  {id=7, weight=23}
}

ii. 随机过程主函数

function get_random_one( array )
  --整理得到权重的数组,及权重总和,weights不是数组。
  local weights = {}
  local total_weight = 0
  for i=1, #array , 1 do
     -- 取表中权重,并加和总权重
     -- the same can be : ( before_open , after_close ]
     weights[ array[i] ] = {}
     weights[ array[i] ].before_open = total_weight
     total_weight += get_obj_weight( array[i] )  -- 得到本元素的出现权重
     weights[ array[i] ].after_close = total_weight
     weights[ array[i] ].index = i
  end

  -- 得到随机值
  -- local rand_value = math.random( 1, total_weight )

  -- 换算随机值代表的object_id, 每个区间是不重合无交集的。
  for key , value in pairs( weights ) do
     if value.before_open < rand_value and rand_value <= value.after_close then
        return  value.index 
     end
  end
end

iii. 取权重子函数

function  get_obj_weight( id )
  return  obj_weight[id].weight
end 

四,另一方面 随机种子:

(这个不算是 随机函数的再封装,应该是随机过程的另一种需求)

就是,系统中随机的结果能够形成一个固定的序列,即,输入一个种子,能够,得到一个肯定的结果。这在调试和时候能够使得随机结果固定,方便调试。当然还有另一种用途:当每次的随机结果作为某种数据的依据,而这些数据是需要记录下来的,那么为了节省空间,我们只需记录随机时的种子,每次需要随机时,我们取得相应的随机种子即可得到当时的随机结果,即可得到一些想要的数据。
比如,要求每次从所有玩家中,随机10个不同玩家id。得到结果之后,去数据库中返回这个玩家的所有属性。需要记录下这10个玩家,等待下一个命令。
这样,我们需要记录一个开始的种子,即随机出第一个玩家的种子。这样顺着再随机10次,得到的结果序列是一样的。

i. 那么这个利用种子得到随机数的实现过程如下:

local next_rand = randint(cur_rand)
local rand_value = ( next_rand )%( ceiling ) + 1 
-- 上面一句相当于math.random( 1, ceiling )
-- 上面的过程相当于 在区间 [1, ceiling] 中得到一个数字

ii. 而其中的randint( rand_seed )函数是由C语言写成的库函数。

-- 这是函数的具体内容,函数返回的是下一个种子。
int next_rand = abs(cur_rand * 16807) % 2147483647;
-- 函数内部 的 2个数组:16807 ;2147483674是为什么。
--(我也不太清楚,大概的估计是有什么统计学的意义吧。如果有高手知道,烦请指点一二。)
posted @ 2014-10-18 16:13  Appleegig  阅读(240)  评论(0编辑  收藏  举报