第1关:割圆法
任务描述
本关任务:编写一个割圆术计算圆周率的小程序。
相关知识
割圆术
国魏晋时期的数学家刘徽于公元263年撰写《九章算术注》,其中就有数学史上著名的“割圆术”。刘徽形容他的“割圆术”说:割之弥细,所失弥少,割之又割,以至于不可割,则与圆合体,而无所失矣。这包含了求极限的思想。通过求圆内接正多边形的周长来近似求圆的周长,并使正多边形的周长无限接近圆的周长,进而求得较为精确的圆周率。
设圆半径为1,圆内接正6边形边长也为1,
可如下计算正12边形的边长:
OC=
OB
2
−BC
2
=
1−(AB/2)
2
AB=OD=OA=1
CD=1−OC
新的边长AD 值为:
AD=
AC
2
+CD
2
=
(AB/2)
2
+CD
2
编程要求
根据提示,在右侧编辑区补充代码,编程实现割圆法计算圆周率,输出在正六边形基础上分割n次时得到多边形的边数、圆周率值以及math库中的圆周率值。
测试说明
平台会对你编写的代码进行测试:
输入格式
输入为一行,一个正整数n ,表示在内接正六边形的基础上割圆的次数。
输出格式
输出为两行,第一行输出在内接正六边形基础上再次分隔n次,分隔得到的正多边形的边数m,以及割圆法计算得到的圆周率pi(保留六位小数);第二行输出math库里的pi值(保留六位小数)。
具体输出格式见示例。
示例
输入:
4
输出:
分割4次,边数为96,圆周率为3.141032
math库中的圆周率常量值为3.141593
import math
def cutting_circle(n): # n为分割次数
"""接收表示分割次数的整数n为参数,计算分割n次时正多边形的边数和圆周率值,返回边数和圆周率值"""
side_length = 1 # 初始边长
edges = 6 # 初始边数
for _ in range(n):
oc = math.sqrt(1 - (side_length / 2) ** 2)
cd = 1 - oc
side_length = math.sqrt((side_length / 2) ** 2 + cd ** 2)
edges *= 2
pi = edges * side_length / 2
return edges, pi
if __name__ == '__main__':
times = int(input()) # 割圆次数
edges, pi = cutting_circle(times)
print(f"分割{times}次,边数为{edges},圆周率为{pi:.6f}")
print(f"math库中的圆周率常量值为{math.pi:.6f}")
第2关:无穷级数法
任务描述
本关任务:编写一个无穷级数法计算圆周率的小程序。
相关知识
为了完成本关任务,你需要掌握:
无穷级数法
无穷级数法
π 是个超越数,圆周率的超越性否定了化圆为方这种尺规作图精确求解问题的可能性。有趣的是,π 可以用无穷级数表示:
1
1
−
3
1
+
5
1
−
7
1
+⋯=
4
π
左边的展式是一个无穷级数,被称为莱布尼茨级数(Leibniz),这个级数收敛到 π/4,它通常也被称为格雷戈里-莱布尼茨级数,用以纪念莱布尼茨同时代的天文学家兼数学家詹姆斯·格雷戈里。
编程要求
根据提示,在右侧编辑区补充代码,编程用莱布尼茨级数计算 π值。输入一个较小的数作为阈值,当最后一项的绝对值小于给定阈值时停止计算并输出得到的 π 值。
测试说明
平台会对你编写的代码进行测试:
输入格式
输入为一行,一个正浮点数 threshold,用以限定级数法求解 pi 值时,迭代累加只加绝对值大于 threshold 的项。
输出格式
输出为一个浮点数,是程序使用级数法求解的 pi 值,要求保留小数点后八位。
输入输出示例
示例 1
输入:
0.000002
输出:
3.14158865
示例 2
输入:
1e-6
输出:
3.14159065
def leibniz_of_pi(error):
"""接收用户输入的浮点数阈值为参数,返回圆周率值"""
# 初始化变量
series_sum = 0
denominator = 1
sign = 1
while True:
term = sign / denominator
if abs(term) < error:
break
series_sum += term
denominator += 2
sign = -sign
pi = series_sum * 4
return pi
if __name__ == '__main__':
threshold = float(input())
print("{:.8f}".format(leibniz_of_pi(threshold)))
第3关:蒙特卡洛法
任务描述
本关任务:编写一个蒙特卡洛法计算圆周率的小程序。
相关知识
为了完成本关任务,你需要掌握:
1.蒙特卡洛法原理
2.随机数种子
蒙特卡洛法
蒙特卡洛(Monte Carlo)方法是由数学家冯·诺伊曼提出的,诞生于上世纪40年代美国的“曼哈顿计划”。蒙特卡洛是一个地名,位于赌城摩纳哥,象征概率。蒙特卡洛方法的原理是通过大量随机样本,去了解一个系统,进而得到所要计算的值。
用蒙特卡洛方法计算圆周率π的原理如下:一个边长为2r 的正方形内部相切一个半径为 r 的圆,圆的面积是πr
2
,正方形的面积为4r
2
,二者面积之比是π / 4,因为比值与r大小无关,所以可以假设半径r的值为1。
在这个正方形内部,随机产生n个点,坐标为(x, y),当随机点较多时,可以认为这些点服从均匀分布的规律。计算每个点与中心点的距离是否小于圆的半径(x
2
+y
2
<r
2
),以此判断是否落在圆的内部。统计圆内的点数c,c与n的比值乘以4,就是π的值。理论上,n越大,计算的π值越准,但由于随机数不能保证完全均匀分布,所以蒙特卡洛法每次计算结果可能不同。
随机数种子
计算机中的随机数是通过算法产生,相同的随机数种子可以帮助我们获得相同的随机数序列,所以自动评测的题目都要求使用随机数种子。本题中只需要执行以下语句就可以。
sd = int(input()) # 读入随机数种子
random.seed(sd) # 设置随机数种子
编程要求
根据提示,在右侧编辑器补充代码,编程实现用蒙特卡洛方法计算π值,为了自动测评的需要,请先读入一个正整数sd作为随机数种子,并要求使用下面语句来生成随机点的坐标值:
x, y = random.uniform(-1, 1), random.uniform(-1, 1)
测试说明
平台会对你编写的代码进行测试:
** 示例 **
输入:
100
100000
输出:
3.15316
import random
def monte_carlo_pi(num):
"""接收正整数为参数,表示随机点的数量,利用蒙特卡洛方法计算圆周率
返回值为表示圆周率的浮点数"""
# 初始化圆内点的数量
inside_circle = 0
for _ in range(num):
# 生成随机点的坐标
x, y = random.uniform(-1, 1), random.uniform(-1, 1)
# 判断点是否在圆内
if x ** 2 + y ** 2 < 1:
inside_circle = inside_circle + 1
# 计算圆周率
pi = 4 * (inside_circle / num)
return pi
if __name__ == '__main__':
sd = int(input()) # 读入随机数种子
random.seed(sd) # 设置随机数种子
times = int(input()) # 输入正整数,表示产生点数量
print(monte_carlo_pi(times)) # 输出圆周率值,浮点数
第4关:梅钦法
任务描述
本关任务:编写一个梅钦公式计算圆周率大小的小程序。
相关知识
为了完成本关任务,你需要掌握:
梅钦公式
梅钦公式
1706 年,英国人 约翰·梅钦( John Machin) 发明了一个用于计算π / 4值的公式:
4
π
=4arctan
5
1
−arctan
239
1
梅钦公式是格里高利/莱布尼茨计算的公式的变体,但是更实用,它的收敛速度显著增加,这使得它成为了更实用的计算的方法,虽然有若干种类梅钦(Machin-like)公式,但梅钦公式仍然是计算值的主要公式。
编程要求
根据提示,在右侧编辑器补充代码,计算并输出圆周率的大小。
测试说明
平台会对你编写的代码进行测试:
输入:
无
输出:
3.1415926535897936
'''
利用梅钦公式计算圆周率的大小
'''
import math
def machin_of_pi():
"""用梅钦级数计算圆周率,返回圆周率值"""
# 计算 4 * arctan(1 / 5)
term1 = 4 * math.atan(1 / 5)
# 计算 arctan(1 / 239)
term2 = math.atan(1 / 239)
# 根据梅钦公式计算圆周率
pi = 4 * (term1 - term2)
return pi
if __name__ == '__main__':
cal_pi = machin_of_pi() # 调用判断类型的函数
print(cal_pi) # 输出函数运行结果
第5关:拉马努金法
任务描述
本关任务:编写一个拉马努金公式计算圆周率大小的小程序。
相关知识
为了完成本关任务,你需要掌握:
拉马努金公式
拉马努金公式
拉马努金曾经提出过很多关于求π的公式,这些公式都有以下几个特点: 等号右边的构造超乎常人想象,收敛速度极快!
π
1
=
9801
2
2
∑
k=0
∞
(k!)
4
396
4k
(4k)!(1103+26390k)
输入一个正整数 n,根据些公式计算累加 n 次时的圆周率值。
编程要求
根据提示,在右侧编辑器补充代码,调用math库中的阶乘函数计算并输出圆周率的大小。
测试说明
平台会对你编写的代码进行测试:
测试输入:
1
预期输出:
3.1415927300133055
import math
def ramanujan_of_pi(n):
"""接收一个正整数n为参数,用拉马努金公式的前n项计算圆周率并返回。"""
total = 0
for k in range(n):
numerator = math.factorial(4 * k) * (1103 + 26390 * k)
denominator = (math.factorial(k) ** 4) * (396 ** (4 * k))
term = numerator / denominator
total = total + term
pi = (9801 / (2 * math.sqrt(2) * total))
return pi
if __name__ == '__main__':
n = int(input())
cal_pi = ramanujan_of_pi(n)
print(cal_pi)