zoukankan      html  css  js  c++  java
  • 已知一个函数f可以等概率的得到15间的随机数,问怎么等概率的得到17的随机数

    题目是从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 的整数解,很显然是无解的。(
    前者的个位数是5,而后者的个位数不可能是5)

    从理论上来证明:
    无论是多么复杂,多么稀奇古怪的公式,n个自变量将产生一个n维度的空间。如果产生了低于n维度的空间,那说明其还是n维度,但某些维度被压缩成了零。
    因为rand5()在每个维度上只有5个“自由度”,因此这个空间只有5*5*5……=5^n个点。
    即:任意一个含有n个自由度为5的自变量的公式,无论多么稀奇古怪,都将产生5^n个值,虽然某些值可能相同。(这其实很显然,根本不需要上面用n维空间来说明)
    5^n 不可能是 7 的倍数。(前者的个位数是5,而后者的个位数不可能是5)

    自此证明这个问题是无解的

    m/(5^n)=1/7这个推导出来的数学公式和本文一开始的算法非常的匹配,就像一对同卵孪生姐妹^_^,可以互相印证。

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

    还有一位说话很冲的仁兄,给出了一个自谓“总体随机”的算法。他的算法是什么不重要,因为根本不存在这种算法,他将“等概率”误当成了“总体随机”。
    所谓“总体随机”是指在一个大的分组上实现了“随机”,在大分组上可能是等概率1/7随机吗?
    我将他,及他们,的算法化简得更“雷”人一点就是
    int rand7() { 依次循环返回 1 2 3 4 5 6 7 }
    这是等概率的,但不“随机”,当然也可以说它是个“伪随机”算法,但规律性这么明显,只能算是个暴烂的伪随机算法。
    (BTW,数字计算机经由软件产生的随机算法,其实都是有规律的,所以都不是真实的随机算法,只是它们的规律太复杂,复杂到需要收集足够多的序列集,才可以推断出下一个值。但要知道无论多么复杂,在本质上都不比{ 依次循环返回 1 2 3 4 5 6 7 }更高级。)
    因此,部分人对这道题给出的算法其本质都是 自己写了个自认为还可以接受的伪随机算法混杂着真随机的rand5(),便自以为是真随机了。

  • 相关阅读:
    C开发注意事项
    Teamcenter ITK
    Teamcenter SOA开发源码: 打印对象信息
    Teamcenter服务端开发环境配置
    Teamcenter中UID和对象之间相互转化
    Teamcenter 打开数据集
    Teamcenter中SOA调用user service
    63.display:none与visibility:hidden的区别?
    60.为什么要初始化CSS样式
    58.用纯CSS创建一个三角形的原理是什么?
  • 原文地址:https://www.cnblogs.com/waka401/p/2627356.html
Copyright © 2011-2022 走看看