likes
comments
collection
share

Python入门篇之random库

作者站长头像
站长
· 阅读数 23

random 库简介

随机数在计算机应用中十分常见,Python 内置的 random 库主要用于产生各种分布的伪随机数序列。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 公式,该公式如下:

Python入门篇之random库

随着计算机的出现,数学家找到了求解 π 的另类方法:蒙特卡罗方法,又称随机抽样或统计试验方法。该方法属于计算数学的一个分支,由于其能够真实地模拟实际物理过程,因此,解决问题与实际非常符合,可以得到很圆满的结果。蒙特卡罗方法广泛应用于数学、物理学和工程领域

当所要求解的问题是某种事件出现的概率,或者是某个随机变量的期望值时,它们可以通过某种 “试验” 的方法,得到这种事件出现的频率,或者这个随机变数的平均值,并用它们作为问题的解。这是蒙特卡罗方法的基本思想

应用蒙特卡罗方法求解 π 的基本步骤如下:随机向下图所示的单位正方形和圆结构,圆的半径为 1,抛酒大量“飞镖”点,计算每个点到圆心的距离从而判断该点在圆内或者圆外,用圆内的点数除以总点数就是 π 值。随机点数量越大,越充分覆盖整个图形,计算得到的 π 值越精确。实际上,这个方法的思想是利用离散点值表示图形的面积,通过面积比例来求解 π

Python入门篇之random库

为了简化计算,一般利用图形的1/4 求解π值,如下图所示:

Python入门篇之random库

该问题的 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π运行时间
2^10^3.109 3750.011 s
2^11^3.138 67 10.012 s
2^12^3.1503900.014 s
2^13^3.143 5540.018 s
2^14^3.141 3570.030 s
2^15^3.147 8270.049 s
2^16^3.141 9670.116 s
2^18^3.144 5770.363 s
2^20^3.142 669 677 71.255 s
2^25^3.141 697 883 640.13 s

可以看到,随着 DARTS 数量的增加,当达到 2^20^ 数量级时,π 的值就相对准确了。进一步增加 DARTS 数量,能够进一步增加 π 的精度