zoukankan      html  css  js  c++  java
  • 蒙特卡罗方法求非概率分布的随机数

    问题

    假如有四个选项ABCD,每个选项的概率不一样,比如A-0.01 B-0.45 C-0.35 D-0.19 。
    如果要从四个选项中任选一个的话,选出的选项尽可能的符合对应的概率。如选100次,才会选出一个A出来。怎么实现?
    概率图

    算法

    请参考 蒙特卡罗方法

    思路

    从ABCD中,随机选择一个作为候选选项,然后在从0,1中随机产生一个随机数,如果此随机数大于候选选项对应的概率,那么重新选择。若随机数小于等于候选选项的概率,那么此候选选项就是我们要的随机数。

        val array = Array("A", "B", "C", "D")
        val map = Map("A" -> 0.01, "B" -> 0.45, "C" -> 0.35, "D" -> 0.19)
    
      /**
        * 返回0-$(length-1)的随机整数
        *
        * @param length
        * @return
        */
      private def nextInt(length: Int): Int = {
        (random * length).toInt
      }
    
      /**
        * 随机从ABCD中选择一个选项,作为X,然后在从0-1中选择一个数值作为Y,那么如果Y大于X对应的概率,递归重头开始选,否则,X就是我们要选择的值。
        *
        * @param array 选项数组
        * @param map   选项对应的概率
        * @return 本次选出的选项
        */
      private def nextValue(array: Array[String], map: Map[String, Double]): String = {
        val x = array(nextInt(array.length))
        val y = random
        if (y > map(x)) {
          //继续nextValue
          nextValue(array, map)
        } else {
          x
        }
      }
      //此处用到了尾递归
    

    测试代码

      def main(args: Array[String]): Unit = {
        //测试长度
        val length = 100000000
        val start = System.currentTimeMillis()
        val allResult = (0 to length).map(x => nextValue(array, map))
        val end = System.currentTimeMillis()
        println(s"计算${length}个随机数,共花费${(end - start) / 1000}秒")
    
        array.foreach(x => {
          val count = allResult.count(_.equals(x))
          println((s"${x}共随机获得${count}次,概率为${BigDecimal.valueOf(count) / 		BigDecimal.valueOf(length).toDouble}"))
        })
      }
    

    输出结果

    计算100000000个随机数,共花费29秒
    A共随机获得998503次,概率为0.00998503
    B共随机获得44999964次,概率为0.44999964
    C共随机获得35003001次,概率为0.35003001
    D共随机获得18998533次,概率为0.18998533
    
  • 相关阅读:
    spring-boot-swagger2 使用手册
    mall整合Swagger-UI实现在线API文档
    MyBatis Generator 详解
    1046 划拳 (15分)
    1043 输出PATest (20分)
    1042 字符统计 (20分)
    1041 考试座位号 (15分)
    1040 有几个PAT (25分)
    1039 到底买不买 (20分)
    1038 统计同成绩学生 (20分)
  • 原文地址:https://www.cnblogs.com/luckuan/p/5705937.html
Copyright © 2011-2022 走看看