圆周率里包含你的银行卡密码吗?

这个问题挺有意思,非数学专业,就从计算机的角度分析一下这个问题吧。


-----我是条分割线-----


为了分析这个问题,我先用y-cruncher跑出了π的前10亿位,感觉应该够用!

不够用也没办法了,内存有限,而且跑程序时CPU占用率100%,风扇吹的我心慌。

让人无奈的占用率


计算前10亿位共用时190.515秒,数据以txt的格式保存,大小976.563MB。



下面开始我们的分析工作。


先简单的搜索一下,发现自己能想到的几个六位数字都出现了(包括我的银行卡密码)

举几个例子:

000000出现在小数点后第1,699,927位


111111出现在小数点后第255,945位


222222出现在小数点后第963,024位


123456出现在小数点后第2,458,885位


注:每行有1024个字符,所以计算公式应为1024*(行数-1)+列数-2,其中2为开头的“3.”


但是不可能手动把000000~999999全验证一遍吧(虽然我今天很闲),还是要写个程序跑一下。


不考虑复杂度问题的话,代码很快就写完了,只有短短的14行。

pwds = []
for num in range(1000000):
    pwds.append("0" * (6 - len(str(num))) + str(num))

with open("Pi-1000000000.txt","r")as f:
    pai=f.read()

#输出字符串的长度和π的前109位
print(len(pai),pai[0:110])
stat = []

for pwd in pwds:
    stat.append([pwd,pai.index(pwd)-1])
    if len(stat) % 1000 == 1:
        print(stat[-1])

with open("Pi-stat.txt","w")as f:
    for data in stat:
        f.write(data[0]+':'+str(data[1])+'\n')


因为我用的是index,如果密码不存在的话,则会直接抛出异常。但是我的直觉是000000~999999是都存在的(其实是我懒得多写代码了)


检索的速度大概是1000条/秒,接下来就是耐心的等待过程。


程序跑完了!不出所料,所有的六位银行卡密码在π中都是存在的。

最后出现的密码是569540,位于小数点后14,118,307位.(10亿位有点过剩啊!)

统计数据截图

同时我也把数据上传到百度网盘了,感兴趣的朋友们可以下载看一下。所有需要的文件都在最下方。需要的朋友自取。


-----又是条分割线-----

第一次收到这么多的赞。

于是我又写了个程序把π前10亿位中的生日给跑了出来,生日的范围为1920~2020共计101年。

上代码~供有兴趣的朋友研究,可以一起讨论如何计算的更快。(感觉这个完全可以出一个面试题的!我水平是不太行,下面是我想到的方法。)

month = {'01':31,'02':28,'03':31,
         '04':30,'05':31,'06':30,
         '07':31,'08':31,'09':30,
         '10':31,'11':30,'12':31}

def judge(Jdate):
    if int(Jdate[0:4]) < 1920 or int(Jdate[0:4]) > 2021:
        return False
    else:
        if int(Jdate[4:6]) > 12 or int(Jdate[4:6]) == 0:
            return False
        else:
            p = month[Jdate[4:6]]
            if int(Jdate[4:6]) == 2 and int(Jdate[0:4])%4 == 0:
                p = p+1
            if int(Jdate[6:8]) > p or int(Jdate[6:8]) == 0:
                return False
            else:
                return True


with open("Pi-1000000000.txt","r")as f:
    pai=f.read()

#输出字符串的长度和π的前109位
print(len(pai),pai[0:110])
stat = []

for num in range(2,len(pai)-8):
    if judge(pai[num:num+8]):
        stat.append([pai[num:num+8],num-1])
    if num % 1000000 == 0:
        print(num)

stat.sort()

with open("Pi-birthday.txt","w")as f:
    for data in stat:
        f.write(data[0]+':'+str(data[1])+'\n')



-----还是条分割线-----


大家不要私信给我发银行卡密码了!很危险的!真要查的话,可以看评论置顶,有个朋友分享了在线查询的链接。范围精确到2亿位。


下面的内容非程序员可忽略...

经评论区的朋友们启发,而且实在受不了别人喷我程序运行的慢了。又写了一个更快的检索6位数字(就是所谓的银行卡密码)的算法。

感兴趣的程序员可以看一下。我感觉速度还行。十几秒钟就能检索完毕。更快的我暂时也还没想到..毕竟答主还只是一个大二在校生,也没搞过ACM竞赛,水平有限。

#将000000~999999存到字典中,初始化出现的位置为正无穷(用10亿+1代替)
dic = {}
for num in range(1000000):
    dic["0" * (6 - len(str(num))) + str(num)] = 1000000001

#读取π
with open("Pi-1000000000.txt","r")as f:
    pai=f.read()

#输出字符串π的长度和π的前109位
print(len(pai),pai[0:110])

stat = []
#p=1,跳过了"3."
p = 1
#p允许的最大数值
p_max = len(pai)-1000000


'''
倒序查找,开始时从第1000001位向第1位检索,
检索到第1位时,若字典中仍存在无穷大,则从
2000001位向1000001位检索。以此类推,直到
字典中不存在无穷大或者p大于p_max
'''

while 1000000001 in dic.values() and p<p_max:
    for i in range(p+1000000,p,-1):
        pwd = pai[i:i+6]
        if i < dic[pwd]:
            dic[pwd] = i-1
        if i%100000 == 0:
            print(i)
    p = p+1000000

with open("pi-stat.txt",'w')as f:
    for item in dic.items():
        f.write(item[0]+':'+str(item[1])+'\n')


需要的文件在这里~


六位银行卡密码出现位置

文件:Pi-stat.txt

密码:8rc9


生日出现位置

文件:Pi-birthday.txt

密码:v4o4


10亿位圆周率

文件:Pi-1000000000.txt

密码:drq8


2500万位圆周率

文件:Pi-25000000.txt

密码:0aq8


------------2018.08.06--------

从今天起禁止任何形式的转载。

编辑于 2018-09-26 15:03

Published

Category

Zhihu

Tags