用rand7()函数构造函数rand10()

题目要求:用一个已知均匀随机的rand7()(生成1~7等概率)来构造rand10()(生成1~10等概率)。

思路:题目要求用均匀分布生成另一个均匀分布。

1.前提:rand7()可以均匀生成1,2,3,4,5,6,7,目标是rand10()均匀生成1 ~ 10。

2.不能用简单的(rand7() * 10 / 7)之类的方法,因为它们不是均匀的(会偏向某些数)。

举例:

rand7()取值:1,2,3,4,5,6,7

乘以10:10,20,30,40,50,60,70

除以7:1,2,4,5,7,8,10

目标应该是1~10每个数的概率都为1/10,结果1,2,4,5,7,8,10的概率为1/7,3,6,9的概率为0,不合题意。

3.拒绝采样法:利用(rand7() - 1) * 7 + rand7()可以生成1 ~ 49之间的等概率随机数。

证明:

(1)令a = rand7() - 1,取值:0,1,2,3,4,5,6(均匀)。

(2)令b = rand7(),取值:1,2,3,4,5,6,7(均匀)。

(3)公式变成了a * 7 + b。这实际上是在构造一个两位的7进制数。

(4)a * 7只能取0,7,14,21,28,35,42。

(5)a * 7 +rand7(),其实就是0,7,14,21,28,35,42分别加上了1~7之间的数,正好组成了1~49的所有整数。

当a固定时:

a = 0:0 * 7 + b = 1 ~ 7。

a = 1:1 * 7 + b = 8 ~ 14。

a = 2: 2 * 7 + b = 15 ~ 21。

a = 3: 3 * 7 + b = 22 ~ 28。

a = 4: 4 * 7 + b = 29 ~ 35。

a = 5: 5 * 7 + b = 36 ~ 42。

a = 6: 6 * 7 + b = 43 ~ 49。

完美覆盖了1 ~ 49的所有整数。

之所以a * 7 + b这样构造是均匀的,是因为a和b是独立的随机变量,也就是两次独立的rand7()调用。概率计算:P(得到某个特定数 x) = P(a = 某值) × P(b = 某值)。实际上是在做笛卡尔积。通过 (a'-1)*7 + b 映射到 1~49,这是一个双射(一一对应),所以分布保持均匀。

举例:

复制代码
P(得到23) = P(a=3) × P(b=2) = (1/7) × (1/7) = 1/49

任何1 ~ 49的数都能唯一表示为a * 7 + b的形式,所以每个数的概率都是1/49。

4.(rand7() - 1) * 7 + rand7()生成等概率随机数的步骤:从1 ~ 49中只取1 ~ 40的数字映射到1 ~ 10,遇到41 ~ 49则重试。这是因为转换为rand10()的话,最大概率是将1 ~ 49分成10组,每组4个数(但49不是10的倍数),因此必须让num落在1 ~ 40范围内才有用,否则丢弃重新生成,保证1 ~ 10均匀。

附代码:

java 复制代码
class Solution {
    private Random random = new Random();

    // 假设提供的 rand7() 是均匀的
    private int rand7() {
        // random.nextInt(7)是生成一个0到6之间的随机整数(包含0,不包含7)
        //random.nextInt(7) + 1就是生成一个1到7之间的随机整数
        return random.nextInt(7) + 1;
    }

    public int rand10() {
        while (true) {
            int num = (rand7() - 1) * 7 + rand7(); // 1 ~ 49 均匀
            if (num <= 40) {
                // 将1 ~ 40的数映射到1 ~ 10
                // 如果是num % 10,那么1 % 10 + 1 = 2,映射错误,所以是(num - 1) % 10
                // 要求返回1 ~ 10,而不是0 ~ 9,所以应该 + 1,不加1的映射范围是0 ~ 9
                return (num - 1) % 10 + 1;
                // 如果 num = 41~49,则丢弃,重新生成
            }
        }
    }
}

ACM模式:

java 复制代码
import java.util.Random;
import java.util.Scanner;

class Solution {
    private Random random = new Random();

    // 假设提供的 rand7() 是均匀的
    private int rand7() {
        // random.nextInt(7)是生成一个0到6之间的随机整数(包含0,不包含7)
        //random.nextInt(7) + 1就是生成一个1到7之间的随机整数
        return random.nextInt(7) + 1;
    }

    public int rand10() {
        while (true) {
            int num = (rand7() - 1) * 7 + rand7(); // 1 ~ 49 均匀
            if (num <= 40) {
                // 将1 ~ 40的数映射到1 ~ 10
                // 如果是num % 10,那么1 % 10 + 1 = 2,映射错误,所以是(num - 1) % 10
                // 要求返回1 ~ 10,而不是0 ~ 9,所以应该 + 1,不加1的映射范围是0 ~ 9
                return (num - 1) % 10 + 1;
                // 如果 num = 41~49,则丢弃,重新生成
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt(); // 需要生成多少个随机数

        Solution solution = new Solution();
        for (int i = 0; i < n; i++) {
            System.out.print(solution.rand10());
            if(i < n - 1){
                System.out.print(" ");
            }
        }
        System.out.println();
        scanner.close();
    }
}
相关推荐
NashSKY3 天前
EM 算法完整推导与本质剖析
算法·机器学习·概率论
AI科技星6 天前
数理原本·卷零:信息本源与震动论
人工智能·线性代数·架构·概率论·学习方法·量子计算
初心未改HD8 天前
机器学习之朴素贝叶斯分类器详解
人工智能·机器学习·概率论
the sun3410 天前
概率论:二维随机变量、随机变量组合函数的分布求解
概率论
初心未改HD12 天前
AI应用开发之概率论与贝叶斯定理
人工智能·概率论
做cv的小昊15 天前
【TJU】研究生应用统计学课程笔记(8)——第四章 线性模型(4.1 一元线性回归分析)
笔记·线性代数·算法·数学建模·回归·线性回归·概率论
做cv的小昊19 天前
【TJU】研究生应用统计学课程笔记(6)——第二章 参数估计(2.4 区间估计)
人工智能·笔记·线性代数·算法·机器学习·数学建模·概率论
-cywen-19 天前
扩散模型相关的概率论基础
概率论
风落无尘20 天前
第二章《概率与生存》完整学习资料
人工智能·矩阵·概率论