python圆周率测试

利用python测试圆周率是否包含所有6位数密码,及其首次出现的位数

先使用y-cruncher生成圆周率的前2500万位,数据保存在txt文件中,文件大小24MB,修改文件只保留小数点后的数字,接下来就可以对数据进行测试。

1,最直接的办法查找

index()函数可返回开始的索引值,即首次出现的位数,代码如下:

pi_file = r'E:\测试\Pi-25000000.txt'  # 读取文件
with open(pi_file, 'r') as f:
    pi = f.read()
    #print(len(pi))

password_dict = {}  # 字典保存,密码-首次出现位数
for num in range(1000000):  # 所有6位数字密码
    key = ('%06d' % num)
    password_dict[key] = pi.index(key)
    if num % 100000 == 0:  # 查看进度
        print(key)

save_file = r'E:\测试\Pi-password.txt'  # 保存路径
with open(save_file, 'w') as f:
    for key, value in password_dict.items():
        f.write('%s:%s\n' % (key, value))
测试结果:

000000-999999一共100万种密码都在圆周率前2500万位中出现,最后出现的密码是569540,位数14118306(从0开始计数)


密码:首次出现的位数(从0开始计数)

不过代码运行比较慢,圆周率2500万位查找100万种密码,共耗时1059秒。

2,改进代码分段查找

这是由于不断使用index()函数对2500万位数字从左向右查找,重复查找过多,因此可以从数字中查找密码,这样每6位数字只需查找一次,改进代码如下:

pi_file = r'E:\测试\Pi-25000000.txt'  # 读取文件
with open(pi_file, 'r') as f:
    pi = f.read()

password_dict = {}  # 字典保存,密码-首次出现位数,初始位数设为-1
for num in range(1000000):  # 所有6位数字密码
    password_dict['%06d' % num] = -1


k = 100*10000  # 分段查找,每段设置位数
n_max = len(pi) // k  # 防止死循环,最好整除
n = 1
    
while -1 in password_dict.values() and n <= n_max:
    for i in range((n-1)*k, n*k):
        password = pi[i:i+6]
        if password_dict[password] == -1:
            password_dict[password] = i
        elif i < password_dict[password]:
            password_dict[password] = i
    n = n + 1

save_file = r'E:\测试\Pi-password.txt'  # 保存路径
with open(save_file, 'w') as f:
    for key, value in password_dict.items():
        f.write('%s:%s\n' % (key, value))
测试结果是一样的,不过运行速度大幅提高,改进代码仅耗时8.5秒,相差120倍。

3,测试是否包含日期

既然6位数密码都在圆周率的前2500万位中,那么接下来测试一下1921年至2020年所有日期是否也在其中。

按照惯例,先用最直接的办法查找,不过index()函数未找到会报错,改为find()函数查找,代码如下:

pi_file = r'E:\测试\Pi-25000000.txt'  # 读取文件
with open(pi_file, 'r') as f:
    pi = f.read()

birthday_dict = {}  # 生日字典
mmdd = []
for m in range(1, 13):
    for d in range(1, 32):
        mmdd.append('%02d%02d' % (m, d))
temp = ['0229', '0230', '0231', '0431', '0631', '0931', '1131']
for i in temp:
    mmdd.remove(i)
# 直接查找
for year in range(1921, 2021):
    for md in mmdd:
        yyyymmdd = str(year) + md
        birthday_dict[yyyymmdd] = pi.find(yyyymmdd)
    if (year % 4) == 0:
        yyyymmdd = str(year) + '0229'
        birthday_dict[yyyymmdd] = pi.find(yyyymmdd)
    print(year)
   
save_file = r'E:\测试\Pi-birthday.txt'  # 保存路径
with open(save_file, 'w') as f:
    for key, value in birthday_dict.items():
        f.write('%s:%s\n' % (key, value))
测试结果:

1921年至2020年一共36525天只有8020天在圆周率前2500万位中出现,最先出现的日期是20190914,位数243,最后出现的日期是19660505,位数24999789(从0开始计数)


日期:首次出现的位数(从0开始计数)

直接查找自然很慢,耗时731秒,按照之前的方法进行改进,改进代码如下:

# 分段查找
for year in range(1921, 2021):
    for md in mmdd:
        birthday_dict[str(year) + md] = -1
    if (year % 4) == 0:
        birthday_dict[str(year) + '0229'] = -1

k = 100*10000
n_max = len(pi) // k  # 防止死循环,最好整除
n = 1

while -1 in birthday_dict.values() and n <= n_max:
    for i in range((n-1)*k, n*k):
        birthday = pi[i:i+8]
        if birthday in birthday_dict:  # 判断是否为待查找日期
            if birthday_dict[birthday] == -1:
                birthday_dict[birthday] = i
            elif i < birthday_dict[birthday]:
                birthday_dict[birthday] = i
    n = n + 1
改进代码仅耗时4.3秒,相差170倍。

既然2500万位没有测试出所有日期出现的位数,那么再试试看1亿位,结果一共36525天有23163天出现了,最后出现的日期是19640421,位数99995337(从0开始计数)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。