免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: glq2000
打印 上一主题 下一主题

[算法] 已知一个函数f可以得到1-5间的随机数,问怎么得到1-7的随机数 [复制链接]

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
1 [报告]
发表于 2010-07-07 23:35 |显示全部楼层
本帖最后由 bruceteen 于 2010-07-07 23:37 编辑

看了大家的讨论,俺就着大家的思路也写了一个(但有所变形),不知道变形后的思路是否正确,错了就丢人了

int rand7()
{
    int a;
    while( (a=rand5()*5+rand5()) > 26 );
    return (a-3)/3;
}

算法思路是:
1. 通过 rand5()*5+rand5() 产生 6 7 8 9 10 11 …… 26,27 28 29 30 这25个数,每个数的出现机率相等
2. 只需要前面 3*7 个数,所以舍弃后面的4个数
3. 将 6 7 8 转化为 1,9 10 11 转化为 2,……,24 25 26 转化为 7。公式是 (a-3)/3

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
2 [报告]
发表于 2010-07-08 14:20 |显示全部楼层
rand5()*5+rand5() 不就是rand5()*6吗?
noword2k 发表于 2010-07-08 09:02

rand5()*5+rand5() 中 rand5() 和 rand5() 是不一定相等的,它是随机数,每次的返回值都是随机的

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
3 [报告]
发表于 2010-07-09 14:45 |显示全部楼层
题目是从CU上看到的,我的算法是:
int rand7()
{
    int a;
    while( (a=rand5()*5+rand5()) > 26 );
    return (a-3)/3;
}
可惜没办法验证,不知道这个算法是否正确?(问题一)。
(验证方法是通过双循环将两个rand5()分别换成1 2 3 4 5,但剔除掉(5,2)(5,3)(5,4)(5,5)这四个组合)

算法思路是:
1. 通过 rand5()*5+rand5() 产生 6 7 8 9 10 11 …… 26,27 28 29 30 这25个数,每个数的出现机率相等
2. 只需要前面 3*7 个数,所以舍弃后面的4个数
3. 将 6 7 8 转化为 1,9 10 11 转化为 2,……,24 25 26 转化为 7。公式是 (a-3)/3

注:
我觉得不能将 while( (a=rand5()*5+rand5()) > 26 ) 其中一个rand5()移到while之外,即不能写成
int b = rand5();
int a;
while( (a=b*5+rand5()) > 26 ); 或 while( (a=rand5()*5+b) > 26 );
因为出现 >26 的情况,说明 b 有很大机率很大,从而又导致while之后的a有很大机率很大,破坏了平衡性。
这个备注中的看法对么?(问题二)

但,令人惋惜的是,这不是一个严格意义上的算法,因为“计算机算法”比“数学上的算法”多两个限定,是“有限时间有限步骤内……”,而while( (a=rand5()*5+rand5()) > 26 )可能会循环超过可忍耐次数,即某次运行这段代码可能到地球灭亡时还没结束,虽然几率很低,但有可能发生。

------------------------------------------------------------------------------------

google了一下,找到另一种方法:(本质和上面的算法相同,但要使得第二步不产生多余的数)
找到一个五进制的数 444…4,这个数正好能被7整除
于是他找到444444(五进制)这个数,也就是15624
产生nnnnnn(五进制)的方法很简单,就是每位都通过rand5-1来产生
然后将nnnnnn%7+1就得到了均匀分布于1到7的算法。

这个算法是错误的,因为 444444(五进制)内包含有15625个数,不是15624个数,前者不是7的整数倍。
用我的变形算法来描述就是:
通过 r*5^0 + r*5^1 + r*5^2 + r*5^3 + r*5^4 + r*5^5 产生 3906 到 19530 共15625个数的均匀分布,可惜15625不是7的整数倍,还是需要舍弃掉最后一位。作者错误在于马虎的认为 0至n 内有n个数,其实是n+1个数。

虽然作者的结果是错误的,但思路是正确的,只要能找到一个数n,使得 4 + 4*5 + 4*25 + 4*125 + 4*625 + 4*3125 + …… 的结果加一后是7的整数倍。
我用代码暴力求解,在数据溢出之前都没找到这个数。于是从理论上分析,444…4(五进制)+1 也就是 5的x次方,永远不可能是7的倍数。

还google到其它一些巧妙的算法,但可惜作者并没有真正理解“随机”的概念。

------------------------------------------------------------------------------------

思考一下 rand5()+rand5(),将产生 1/25个2,2/25个3,3/25个4,4/25个5,5/25个6,4/25个7,3/25个8,2/25个9,1/25个10。
如果能找到一个公式,使之产生一系列不同几率的数,将这些数分成7组,使得每组数的几率总和为1/7就可以了。
假设这个公式f需要n个rand5()为自变量,则最多产生5^n个数,不是“最多”的情况说明不同参数组合产生了相同的数,无论是不是“最多”的情况,都可以证明每个数的几率都必然是 1/(5^n) 的整数倍。
那么无论怎么分组,每组数的几率总和都应该是 m * 1/(5^n)。
求 m/(5^n) = 1/7 的整数解,即求 5^n = 7m 的整数解,很显然是无解的。(前者的个位数不是0就是5,而后者的个位数不可能是0或5)
因此自此证明这个问题是无解的

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
4 [报告]
发表于 2010-07-10 14:26 |显示全部楼层
re 楼上: 你混淆了现实中的“小概率”概念,和计算机中的“算法”概念

无论你说的概率有多小,都是一个非0的概念,那么它就违背了计算机算法的定义。

“计算机中硬盘挂掉,……” ------ 在计算机算法中对计算机的定义是运行无误的,但有时间和能量供应的限制。你不能要求一个算法可能会运行操过可接受的时间(比如到宇宙灭亡),也能要求一个算法可能会用掉可接受的能量(比如整个太阳系的能量)。
假如你还不理解,那么我给你一个 int main() {return 0; } 你认为这么代码正确吗?按照你的逻辑,那就是这么代码不能100%正确,因为运行期间可能停电,计算机中硬盘挂掉,cpu计算出现错误都有一个概率,……
而我认为的,“计算机中硬盘挂掉,……”和这段代码是否正确无关。我说的是代码正确性,不是某次程序是否能执行成功。即使某次因为硬盘挂掉而运行失败,这段代码依然是100%正确的。

“比如密钥是128位,那我随便猜一个也有1/(2^12的概率命中” ------ 你说得很正确,但我所知的所有加密算法定义都不是要求0%命中,而是要求低于某个实际的安全值。当然,如果你一定要篡改某加密算法的定义为0%命中,那么次密码算法自然是错误的。

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
5 [报告]
发表于 2010-07-10 17:41 |显示全部楼层
对死抠定义的表示无语。那么修改一下好了,运行10000次还没有产生要求的随机数,那么随便挑个在(1-7)之间的 ...
jerryz920 发表于 2010-07-10 16:30


“那么随便挑个在(1-7)之间的数” ------ 随机 和 均值 的概念不同
随机:当你抛硬币,连续10000000000000000次都是正面朝上,第10000000000000001次反面朝上的概率还是只有1/2
均值:当你第一次取得A,则第二次取得B的几率比取得A的几率高;如果第二次还是取得A,则第三次取得B的几率会更高……

“对死抠定义的表示无语” ----- 什么叫“死抠定义”?如果你连“计算机算法”这个定义都可以抛弃的话,那你不如直接将题目中“随机”的概念改为“伪随机”,这样问题变得更简单,直接用C库中的rand()函数来实现。

A: 已知一个人被雷电劈中的几率是a,一个人中六合彩的概率是b,请问即中六合彩又遭雷劈的概率是不是a*b?
B: 不是a*b,是0,因为两者概率都极低,相乘后更低,所以是0而不是a*b。
A: 我问的是数学上的几率概念
B: 对死抠定义的你表示无语:(
A: ……-_-!!……

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
6 [报告]
发表于 2010-07-10 17:46 |显示全部楼层
回复  churchmice
我的方法只是一种思路,提出时我就指出了:可能不是真正随机的。没有时间细想了。
只是 ...
guoruimin 发表于 2010-07-10 16:38


你的思路确实是无解的,因为每个数的出现几率的最小粒度是1/5^n,在整数范围内无解

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
7 [报告]
发表于 2010-07-10 18:04 |显示全部楼层
是不是一个严格的计算机算法 和 能不能在实际生活中使用 是两个不同点。
很多严格的计算机算法并不能在实际生活中使用,实际生活中使用的好多不是严格的计算机算法,比如GUID生产算法。

不能因为windows有bug,就认为windows不可以使用;不能因为windows被使用着,就认为windows无bug。两个完全不同的概念,不要混为一谈

两个概念都有其适用范围,我也可以列举一个相冲突的例子:
hash表的统计学效率比平衡二叉树高,但在要求实时的算法片段中(“实时”的概念不是要求响应速度快)从来不用hash表,因为hash表可能在某次操作时花费超额的时间。

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
8 [报告]
发表于 2010-07-10 20:25 |显示全部楼层
纯数学意义上,只要1+7*(f-1)/5就可以了
不知道ls的大部分人为什么把话题扯到那么远
------ 因为他们看到的题目是“1-5间的随机数”,而你看到的是“1.0-5.0间的随机数”,讨论的题目不一样呀:)

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
9 [报告]
发表于 2010-07-11 16:11 |显示全部楼层
回复 62# gcd0318
你是怎么证明的?如果不介意的话,教教我吧

我原先的证明方法是:
立出所有可能的运算符,比如+ - *等,因为rand5的几率为1/5,所以+ - * 等的几率“最小粒度”为1/5^n
当然运算符还有/等等,但用/等时需要有限制,不能产生小数。这样的话就可以将/变形为*a*1/5,根号等操作亦然。
即无论给出的公式是如何的复杂,其结果都应该是1/5^n的整数倍。(n可以取任意整数)
m / 5^n = 1/7 在整数范围内无解

昨天想出了一个更直观的证明方法,直接用几率参与运算
因为几率的运算符,只有+ - * max min等有限的几个,而且都可以转化为*操作。另外100%可以转化为1/5+1/5+1/5+1/5+1/5,200%可以转化为2*1
所以1/5^n粒度的几率无论怎么参与计算,其结果都可以化简为m / 5^n
m / 5^n = 1/7 在整数范围内无解

假如可以引入极限的话,要想使得 m / 5^n = 1/7 有解,只有当n是无穷大时

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
10 [报告]
发表于 2010-07-11 18:02 |显示全部楼层
本帖最后由 bruceteen 于 2010-07-11 18:10 编辑

我收回上面的证明方法,不但繁杂,而且还有一个画蛇添足引出的bug

我现在的证明方式是:
任意一个含有n个自由度为5的自变量的公式,无论多么稀奇古怪,都将产生5^n个值,虽然某些值可能相同。
5^n 不可能是 7 的倍数。(前者个位数为5,后者个位数不可能是5)
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP