返回   cpper编程论坛 > 算法
注册账号 论坛帮助 会员列表 日历事件 搜索 今日新帖 标记版面已读

回复
 
LinkBack 主题工具 显示模式
  #1 (permalink)  
旧 2008-03-31
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认 随机数问题

[题目描述]给定一个函数Random(5), 它将随机地返回 {1, 2, 3, 4, 5}中的一个数字. 问: 如何实现函数 random(n)?

希望数字分布比较均匀, 有什么比较好的实现方法吗?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #2 (permalink)  
旧 2008-04-01
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,563
文章: 6
cat 正向着好的方向发展
默认 回复: 随机数问题

google一下,或者直接看java源代码吧如果没有版权问题的话。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #3 (permalink)  
旧 2008-04-01
liuxinyu 的头像
高级会员
 
注册日期: 2006-02-09
帖子: 311
文章: 49
liuxinyu 正向着好的方向发展
默认 回复: 随机数问题

这个和分布方式相关。
正态分布,泊松分布和均匀分布的生成算法不一样。
如果要求正态分布的话,可以使用多项式生成,其他两个需要查一下。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #4 (permalink)  
旧 2008-04-01
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,563
文章: 6
cat 正向着好的方向发展
默认 回复: 随机数问题

他说要均匀分布……
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #5 (permalink)  
旧 2008-04-01
liuxinyu 的头像
高级会员
 
注册日期: 2006-02-09
帖子: 311
文章: 49
liuxinyu 正向着好的方向发展
默认 回复: 随机数问题

这里有一个线性同余法的:
[url=http://zhidao.baidu.com/question/540840.html?fr=qrl]
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #6 (permalink)  
旧 2008-04-02
初级会员
 
注册日期: 2008-04-02
帖子: 1
fter127 正向着好的方向发展
默认 回复: 随机数问题

直接使用rand()%5+1怎么样?rand()本身就是一个比较均匀的伪随机数。
-----------------------
#include <cstdlib>
#include <ctime>

int rand1_5()
{
return rand()%5+1;
}

int main()
{
srand(clock());//伪随机数使用系统时钟初始化;
int ret_val = rand1_5();
//...
}
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #7 (permalink)  
旧 2008-04-03
高级会员
 
注册日期: 2002-09-19
帖子: 840
文章: 7
tomato 正向着好的方向发展
默认 回复: 随机数问题

楼上貌似都理解错题意了
貌似是算法导论的习题,就是已经有一个均匀分布的int rand_5()
要实现一个int rand(n)

我改一下题目,假设rand_5返回0~4,需要构造一个0~n-1的随机数

我的方法是用k次rand_5()(5^k >= n)得到一个k位的5进制数,当这个数大于等于n时丢弃重新来一次,小于等于n时返回
例如n = 31,则k = 3,那么这个3位5进制数为rand_5() * 25 + rand_5() * 5 + rand_5()
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #8 (permalink)  
旧 2008-04-04
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认 回复: 随机数问题

引用:
作者: tomato 查看帖子
我的方法是用k次rand_5()(5^k >= n)得到一个k位的5进制数,当这个数大于等于n时丢弃重新来一次,小于等于n时返回
补充一下: k = floor(log(5, n)) + 1, 且5^k > n >= 5^(k-1). 调用k次rand_5(), 得到的数应该是[0, 5^k). 只保留小于n的数, 所得到的[0, n)上的每个数是均匀分布的.

这种做法效率不是很高, 但可以保证均匀分布. 如果不要求均匀分布, 将得到的数直接mod n, 就可以了.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #9 (permalink)  
旧 2008-04-04
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 847
文章: 7
bankrock 正向着好的方向发展
默认 回复: 随机数问题

这种方法在概率上有可能运行时间趋向无穷吧,看起来好不可靠
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #10 (permalink)  
旧 2008-04-05
初级会员
 
注册日期: 2008-04-05
帖子: 1
haohaolee 正向着好的方向发展
默认 回复: 随机数问题

引用:
作者: tomato 查看帖子
楼上貌似都理解错题意了
貌似是算法导论的习题,就是已经有一个均匀分布的int rand_5()
要实现一个int rand(n)

我改一下题目,假设rand_5返回0~4,需要构造一个0~n-1的随机数

我的方法是用k次rand_5()(5^k >= n)得到一个k位的5进制数,当这个数大于等于n时丢弃重新来一次,小于等于n时返回
例如n = 31,则k = 3,那么这个3位5进制数为rand_5() * 25 + rand_5() * 5 + rand_5()
正如版主所说,这个效率不高,这里给出一个效率更好的算法。
设已知Random(0, N) 要求Random(0, M) M > N
假入N=4, M=5, 那么必须至少要生成0~24个随机数才够用,也就是5*Random(0, 4) + Random(0, 4),但是大于M的直接抛弃又太浪费,于是想到可以mod M+1,但是这样又不均匀。在这种情况下,mod M+1可以如下所示:
0 ~ 5 6 ~ 11 12 ~ 17 18 ~ 23 24
事实上,如果只有位于0 ~ 23之间随机数就正好分为4组,很均匀。这里唯余一个24,mod M+1 = 0,概率空间会多一个0。
所以这里还是可以采用抛弃的思路,但是却是抛弃24的这种情况。一般来说,我们需要抛弃不能整除M+1的那一部分。算法如下:
PHP 代码:
algorithm random(MN)
  
dividend 0
  remainder 
0
  space 
1
  
while divisor space do
    
dividend remainder * (N+1) + random(0N)
    
remainder dividend % (M+1)
    
space space * (N+1) - dividend remainder
  
return remainder 
但是等等,这个算法其实没有直接抛弃不能整除的那部分,假设不能整除的那部分概率空间是{0, 1, ... , K} K < M。
也就是说,如果直接抛弃重来,那么我们又要从0开始获取随机数,而这里可以看出,我们已经有了位于 0 ~ K 之间的均匀随机数,那么如果直接继续迭代一次,
0 -> 0* (N+1) + Random(0, N) -> 0 ~ N
1 -> ... -> N+1 ~ 2N+1
2-> ... -> 2N+2 ~ 3N+2
...
K-> ... -> KN+K ~ KN+N+K
就得到了 0 ~ KN+N+K 之间的均匀随机数,无疑加快了速度。

这个算法的本质就是利用Random(0, N)迭代产生 0 ~ N^X-1 之间的随机数,如果space够用了就mod得到所需的随机数,排除不均匀的那部分,再利用那部分继续产生随机数。如此往复。本质上和直接抛弃是一样的,不过速度要快一些。

PS:算法不是我的,网上抄的,只有分析是自己的,有点罗嗦.....
完整的算法是:
PHP 代码:
algorithm random(abtolerant_error)
  
RAND_MAX 1
  divisor 
b-a+1
  dividend 
0
  remainder 
0
  space 
1
  error_bound 
1
  
while divisor space and error_bound tolerant_error do
    
dividend remainder * (RAND_MAX+1) + random(0RAND_MAX)
    
remainder dividend divisor
    space 
space * (RAND_MAX+1) - dividend remainder
    error_bound 
/= (RAND_MAX+1)
  return 
remainder 
这里注意的是,中间有个误差控制量,如果运气不好老是需要重来,那么一定次数后就直接返回退出,实践中也可以得到相当均匀的随机量。

此帖于 2008-04-05 02:13 AM 被 haohaolee 编辑.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #11 (permalink)  
旧 2008-04-06
liuxinyu 的头像
高级会员
 
注册日期: 2006-02-09
帖子: 311
文章: 49
liuxinyu 正向着好的方向发展
默认 回复: 随机数问题

给一个思路,用一个骰子可以随机获得1到6任何数字,现在用2个骰子,根据乘法原理,可以获得,6x6等于36种不同排列,并且均匀分布,采用6进制数,骰子1的点数-1,乘以6后加上骰子2的点数-1,就可以机会均等表示0-35。因此用k个骰子,就可以均匀表示0到6^k-1的范围。

值得注意的是,并不能用反复掷一个骰子然后将点数相加来获取1到6n之间的随机数,因为这样概率分布不均匀。

但是,如果n不是正好的6^k-1,则严格说,概率并不均匀。例如我希望通过2个dice,获取0到6这7个数字,必然从8到35代表的数字,超出范围,如果仅仅将结果模n,则就会面对鸽笼原理问题(或叫抽屉原则问题),必然某些数字的概率高,令一些概率低。

一个办法是丢弃,我考虑另一个调整办法,从rand ( m ) 生成rand ( n )。不失一般性,假设(m,n)=1。也就是互素。
首先,寻找k使得m^k<=n<m^(k+1)
令n和m^(k+1)-1的最小公倍数为lcm,并且令
n*p=lcm
(m^(k+1)-1)*p=lcm
我们把生成的随机数乘以q再处以p就将0到m^(k+1)-1均匀分布到0到n-1,附带的scheme代码如下,在MIT scheme上测试通过。
代码:
(define (find-power m n) (define (find-power-from k m n) (if (and (< (expt m k) n) (< n (expt m (+ k 1)))) k (find-power-from (+ k 1) m n))) (find-power-from 0 m n)) (define (generate k m) (if (= k 0) (random m) (+ (* (generate (- k 1) m) m) (random m)))) (define (rand-from n m) (let ((k (find-power m n))) (let ((upper-bound (- (expt m (+ k 1)) 1))) (let ((p (/ (lcm upper-bound n) n)) (q (/ (lcm upper-bound n) upper-bound))) (floor (/ (* (generate k m) q) p))))))

此帖于 2008-04-06 08:21 PM 被 liuxinyu 编辑.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #12 (permalink)  
旧 2008-04-06
Elminster 的头像
超级版主
 
注册日期: 2002-09-09
帖子: 1,764
Elminster 正向着好的方向发展
默认 回复: 随机数问题

引用:
作者: liuxinyu 查看帖子
给一个思路,用一个骰子可以随机获得1到6任何数字,现在用2个骰子,根据乘法原理,可以获得,6x6等于36种不同排列,并且均匀分布,采用6进制数,骰子1的点数-1,乘以6后加上骰子2的点数-1,就可以机会均等表示0-35。因此用k个骰子,就可以均匀表示0到6^k-1的范围。

值得注意的是,并不能用反复掷一个骰子然后将点数相加来获取1到6n之间的随机数,因为这样概率分布不均匀。

但是,如果n不是正好的6^k-1,则严格说,概率并不均匀。例如我希望通过2个dice,获取0到6这7个数字,必然从8到35代表的数字,超出范围,如果仅仅将结果模n,则就会面对鸽笼原理问题(或叫抽屉原则问题),必然某些数字的概率高,令一些概率低。

一个办法是丢弃,我考虑另一个调整办法,从rand ( m ) 生成rand ( n )。不失一般性,假设(m,n)=1。也就是互素。
首先,寻找k使得m^k<=n<m^(k+1)
令n和m^(k+1)-1的最小公倍数为lcm,并且令
n*p=lcm
(m^(k+1)-1)*p=lcm
我们把生成的随机数乘以q再处以p就将0到m^(k+1)-1均匀分布到0到n-1,附带的scheme代码如下,在MIT scheme上测试通过。
代码:
(define (find-power m n) (define (find-power-from k m n) (if (and (< (expt m k) n) (< n (expt m (+ k 1)))) k (find-power-from (+ k 1) m n))) (find-power-from 0 m n)) (define (generate k m) (if (= k 0) (random m) (+ (* (generate (- k 1) m) m) (random m)))) (define (rand-from n m) (let ((k (find-power m n))) (let ((upper-bound (- (expt m (+ k 1)) 1))) (let ((p (/ (lcm upper-bound n) n)) (q (/ (lcm upper-bound n) upper-bound))) (floor (/ (* (generate k m) q) p))))))
你除了之后未必能得到整数。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #13 (permalink)  
旧 2008-04-07
liuxinyu 的头像
高级会员
 
注册日期: 2006-02-09
帖子: 311
文章: 49
liuxinyu 正向着好的方向发展
默认 回复: 随机数问题

引用:
作者: Elminster 查看帖子
你除了之后未必能得到整数。
通常情况下,都不是整数。所以最后一句有floor。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #14 (permalink)  
旧 2008-04-09
Elminster 的头像
超级版主
 
注册日期: 2002-09-09
帖子: 1,764
Elminster 正向着好的方向发展
默认 回复: 随机数问题

引用:
作者: liuxinyu 查看帖子
通常情况下,都不是整数。所以最后一句有floor。
floor 了之后还是均匀分布么?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
回复

书签

主题工具
显示模式

发帖规则
不可以发表新主题
不可以发表回复
不可以上传附件
不可以编辑自己的帖子

启用 BB 代码
论坛启用 表情符号
论坛启用 [IMG] 代码
论坛禁用 HTML 代码
Trackbacks are 启用
Pingbacks are 启用
Refbacks are 启用



所有时间均为格林尼治时间 +9。现在的时间是 11:05 AM


Powered by vBulletin® 版本 3.7.0
版权所有 ©2000 - 2009,Jelsoft Enterprises Ltd.
(C) Copy Right All Right Reserved 2001 - 2007

Search Engine Friendly URLs by vBSEO 3.1.0