用rand(7)构造rand(10)

题目:假如有了一个从自然数中随机取一个数的函数rand(0,7)——从0到7中随机取一个自然数出来,问如何用这个函数构造rand(0,10)——随机从0到10中取一个自然数出来。

PS:该题目是在rand(10)没有现成函数的前提下实现的,必须通过rand(7)去构造

(提示:需要注意函数的分布,可以用蒙特卡洛的方法进行验证)

错误思路:

设A为rand(0,7),B为rand(0,7),这两个都是从0到7中随机取得数,然后把取到的结果相加,如果结果大于10,就重新执行,否则就返回相加的结果。python实现代码如下:

import random
def rand_10():
    C = 11
    while C>10:
        A = random.randint(0,7)    
        B = random.randint(0,7)
        C = A+B
    return C

python执行0次的获得的结果如下:

这种解题思路获得的结果是0到10之间的自然数,但是结果却是不对的,先看正确的解题思路,再说明为什么这样取值不对。

正确思路:

设A为rand(0,7),B为rand(0,7),这两个都是从0到7中随机取得数。A作为高位(十位),B作为低位(个位),计算A*8+B的值,得到的是63以内的整数,得到的数据仍为均匀分布,然后我们把结果模11,得到0到10以内的自然数,但是63模11结果为8,那么0~8比9、10结果就会多一次,所以我们只取0~54的数,去模11,代码如下:

def rand_10_2():
    rand_all = 55
    while rand_all >= 55:    #A*8+B最大取值为63,模11得8,0~8比9,10就会多一次,所以计算到54,每个数平均出现5次
        A = random.randint(0,7)   #8进制高位
        B = random.randint(0, 7)  #8进制低位
        rand_all = A*8+B
        C = rand_all%11    #0~10的自然数,包含0和10
    return C

也执行20次 ,得到的数都是0到10之间的整数。

, 验证结果:

要验证两种结果哪种是对的,首先我们得明白,rand函数是从一组数中随机取一个数的函数,那么它要服从均匀分布,这样才能保证每个数取到的概率都一样。我们用蒙特卡洛方法进行验证,即模拟100000或更多次数,然后统计每个数出现的次数,看统计出的结果的直方图,从直方图就能看出是不是服从均匀分布。

1、验证系统自带的函数服从的分布,代码如下:

import random
import numpy as np
import matplotlib.pyplot as plt

y = [0]*8      # 存放rand函数得到的值的个数
for i in range(100000):   # 十万个数据中取值,进行验证
    num_1 = random.randint(0,7)
    for j in range(0,8):
        if j == num_1:
            y[j] +=1

x = np.linspace(0, 7, num=8)
plt.bar(x, y, align='center', alpha=0.7)
plt.xlabel('num for rand')
plt.ylabel('count for rand')
plt.title('rand(7)')
plt.show()             #用直方图显示得到的结果

运行后得到的直方图如下:

8个数得到的结果基本相等,说明python 系统自带的函数是服从均匀分布的。

 2、两个rand函数相加的方法得到rand(10)的方法,用该方法进行验证

代码如下:

import random
import numpy as np
import matplotlib.pyplot as plt

def rand_10():
    C = 11
    while C>10:
        A = random.randint(0,7)
        B = random.randint(0,7)
        C = A+B
    return C

y = [0]*11      # 存放rand函数得到的值的个数
for i in range(150000):   # 十万个数据中取值,进行验证
    num_1 = rand_10()
    for j in range(0,11):
        if j == num_1:
            y[j] +=1

x = np.linspace(0, 10, num=11)
plt.bar(x, y, align='center', alpha=0.7)
plt.xlabel('num for rand')
plt.ylabel('count for rand')
plt.title('rand(10)_add')
plt.show()             #用直方图显示得到的结果

运行后得到的直方图如下:

从图中可以看出该分布不是均匀分布,而是服从泊松分布即正态分布的,至于为什么服从这种分布,后面有时间再讲解。

3、高位*进制+低位的方法得到的结果进行验证


def rand_10_2():
    rand_all = 55
    while rand_all >= 55:    #A*8+B最大取值为63,模11得8,0~8比9,10就会多一次,所以计算到54,每个数平均出现5次
        A = random.randint(0,7)   #8进制高位
        B = random.randint(0, 7)  #8进制低位
        rand_all = A*8+B
        C = rand_all%11    #0~10的自然数,包含0和10
    return C

y = [0]*11      # 存放rand函数得到的值的个数
for i in range(150000):   # 十万个数据中取值,进行验证
    num_1 = rand_10_2()
    for j in range(0,11):
        if j == num_1:
            y[j] +=1

x = np.linspace(0, 10, num=11)
plt.bar(x, y, align='center', alpha=0.7)
plt.xlabel('num for rand')
plt.ylabel('count for rand')
plt.title('rand(10)_ocx')
plt.show()             #用直方图显示得到的结果

 运行后得到结果如下:

从直方图可以看到该结果服从均匀分布。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

映之123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值