博客主页:程序喵正在路上 的博客主页
欢迎关注点赞收藏留言
本文由 程序喵正在路上 原创,CSDN首发!
系列专栏:Python学习
首发时间:2022年5月1日
✅如果觉得博主的文章还不错的话,希望小伙伴们三连支持一下哦
随机数在计算机应用中十分常见,Python 内置的 random 库主要用于产生各种分布的伪随机数序列。random 库采用梅森旋转算法生成伪随机数序列,可用于除随机性要求更高的加解密算法外的大多数工程应用。
使用 random 库的主要目的是生成随机数,因此,我们只需要查阅该库中随机数生成函数,找到符合使用场景的函数即可。该库提供了不问类型的随机数函数,所有函数都是基于最基本的 random.random() 函数扩展实现。
随机数或随机事件是不确定性的产物,其结果是不可预测、产生之前不可预见。无论计算机产生的随机数看起来多么 “随机”, 它们也不是真正意义上的随机数。因为计算机是按照一定算法产生随机数的,其结果是确定的、可预见的,称为 “伪随机数”。 真正意义上的随机数不能评价。如果存在评价随机数的方法,即判断一个数是否是随机数,那么这个随机数就有确定性,将不再是随机数。
下面是 random 库中常用的9个随机数生成函数:
函数 | 描述 |
---|---|
seed(a=None) | 初始化随机数种子,默认值为当前系统时间 |
random() | 生成一个 [0.0, 1.0) 之间的随机小数 |
randint(a, b) | 生成一个 [a,b] 之间的整数 |
getrandbits(k) | 生成一个 k 比特长度的随机整数 |
randrange(start, stop[, step]) | 生成一个 [start, stop) 之间以 step 为步数的随机整数 |
uniform(a, b) | 生成一个 [a, b] 之间的随机小数 |
choice(seq) | 从序列类型,例如列表中随机返回一个元素 |
shuffle(seq) | 将序列类型中的元素随机排列,返回打乱后的序列 |
sample(pop, k) | 从 pop 类型中随机选取 k 个元素,以列表类型返回 |
random 库的引用方法与 math 库一样, 可以采用下面两种方式实现:
import random;
或者
from random import *
使用 random 库的一些例子如下, 请注意,这些语句每次执行后的结果不一定一样:
from random import * # 别忘记导入库哦
print(random()) # 生成一个 [0.0, 1.0) 之间的随机小数
0.2790886106827162
print(uniform(1,10)) #生成一个 [1,10] 之间的随机小数
2.9713215929978967
print(randrange(0,100,4)) #从 0 开始到 100 以 4 递增的元素中随机返回
8
print(choice(range(100))) # 从 0 到 99 随机返回一个元素
50
ls = list(range(10))
print(ls)
shuffle(ls) # 将序列类型中的元素随机排列,返回打乱后的序列
print(ls)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[5, 1, 7, 0, 9, 3, 4, 6, 2, 8]
生成随机数之前可以通过 seed() 函数指定随机数种子,随机数种子一般是一个整数,只要种子相同,每次生成的随机数序列也相同。这种情况便于测试和同步数据,例如:
from random import * # 导入库
seed(125) # 随机数种子赋值125
print("{}.{}.{}".format(randint(1, 10), randint(1, 10), randint(1, 10)))
print("{}.{}.{}".format(randint(1, 10), randint(1, 10), randint(1, 10)))
print("\n")
seed(125) # 再次给随机数种子赋值125
print("{}.{}.{}".format(randint(1, 10), randint(1, 10), randint(1, 10)))
程序运行结果如下:
4.4.10
5.10.3
4.4.10
由上述语句可以看出,在设定相同种子后,每次调用随机函数生成的随机数是相同的。这是随机数种子的作用,也是伪随机序列的应用之一。
这是一个采用蒙特卡罗方法计算圆周率的实例。
π (圆周率)是数学和物理学普遍存在的常数之一,它定义了一个标准圆周长与直径之比。众所周知,π 是一个无理数,即无限不循环小数。精确求解圆周率 π 是几何学、物理学和很多工程学科的关键。
对 π 的精确求解曾经是数学历史上一直难以解决的问题之一,因为 π 无法用任何精确公式表示,在电子计算机出现以前,π 只能通过一些近似公式的求解得到,直到 1948 年,人类才以人工计算方式得到 π 的 808 位精确小数。
迄今为止求解圆周率最好的方法是利用 BBP 公式,该公式如下:
随着计算机的出现,数学家找到了求解 π 的另类方法:蒙特卡罗方法,又称随机抽样或统计试验方法。该方法属于计算数学的一个分支,由于其能够真实地模拟实际物理过程,因此,解决问题与实际非常符合,可以得到很圆满的结果。蒙特卡罗方法广泛应用于数学、物理学和工程领域。
当所要求解的问题是某种事件出现的概率,或者是某个随机变量的期望值时,它们可以通过某种 “试验” 的方法,得到这种事件出现的频率,或者这个随机变数的平均值,并用它们作为问题的解。这是蒙特卡罗方法的基本思想。
应用蒙特卡罗方法求解 π 的基本步骤如下:随机向下图所示的单位正方形和圆结构,圆的半径为 1,抛酒大量“飞镖”点,计算每个点到圆心的距离从而判断该点在圆内或者圆外,用圆内的点数除以总点数就是 π 值。随机点数量越大,越充分覆盖整个图形,计算得到的 π 值越精确。实际上,这个方法的思想是利用离散点值表示图形的面积,通过面积比例来求解 π 值。
为了简化计算,一般利用图形的1/4 求解π值,如下图所示:
该问题的 IPO 表示如下:
输入:抛点数
处理:计算每个点到圆心的距离,统计在圆内点的数量
输出: π 值
采用蒙特卡罗方法求解 π 值的 Python 程序如下:
import time
from random import random # 导入相关库
from math import sqrt
from time import perf_counter
DARTS = 1000 # 要抛的点数
hits = 0.0 # 在圆内的点数
start_time = time.perf_counter() # 启动一个计时器
for i in range(1, DARTS + 1):
x, y = random(), random()
dist = sqrt(pow(x, 2) + pow(y, 2)) # 落点到圆心的距离
if dist <= 1.0: # 落点在圆内
hits = hits + 1
pi = 4 * (hits / DARTS)
end_time = time.perf_counter() # 程序结束时间
print("Pi值是{}.".format(pi))
print("运行时间是:{:.5f}s".format(end_time - start_time ))
上述代码中,random() 函数随机返回一个在 [0,1) 之间的浮点数,用两个随机数给出随机抛点 (x,y) 的坐标。sqrt() 函数来自于数学库 math,用来求解输入数据的平方根。第一次调用perf_counter() 函数启动一个新的计时器,第二次调动 perf_counter() 返回启动计时器后的运行时间。代码中 DARTS 表示抛点数,初始设定为 1000。该程序运行结果如下:
Pi值是3.22.
运行时间是:0.00087s
计算得到的 π 值为 3.22,与大家熟知的 3.14 相差较远,原因是 DARTS 点数量较少,无法更精确刻画面积的比例关系。
下表列出了不同DARTS值情况下该程序的运行情况。
DARTS | π | 运行时间 |
---|---|---|
210 | 3.109 375 | 0.011 s |
211 | 3.138 67 1 | 0.012 s |
212 | 3.150390 | 0.014 s |
213 | 3.143 554 | 0.018 s |
214 | 3.141 357 | 0.030 s |
215 | 3.147 827 | 0.049 s |
216 | 3.141 967 | 0.116 s |
218 | 3.144 577 | 0.363 s |
220 | 3.142 669 677 7 | 1.255 s |
225 | 3.141 697 883 6 | 40.13 s |
可以看到,随着 DARTS 数量的增加,当达到 220 数量级时,π 的值就相对准确了。进一步增加 DARTS 数量,能够进一步增加 π 的精度。
这次的分享就到这里啦,继续加油哦^^
有出错的地方欢迎在评论区指出来,共同进步,谢谢啦