Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
526 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Pi Search | ||
|
||
从 π 的小数点后 **1,000,000,000** 位中搜索指定的数字串位置 | ||
|
||
Demo: [快速寻找 8 位生日](https://jasongzy.com/pi-search.php) | ||
|
||
## π 的数据来源 | ||
|
||
使用 [y-cruncher](http://www.numberworld.org/y-cruncher/) 生成了包含 10 亿位十进制数字字符的文本文档 `./data/Pi - Dec - Chudnovsky.txt`(约 950 MB,未包含在仓库内) | ||
|
||
为了加快 8 位生日的查询速度,预先遍历了 从 1900-01-01 至 2050-12-31 的所有合法日期,并将它们的位置存入了 SQLite 数据库(`./data/pi.db`)。`date_search_sqlite.py` 和 `pi-search.php` 均调用了此数据库以实现高速查询。 | ||
|
||
## 查询速度 | ||
|
||
如果直接遍历匹配原始的 txt 文件,搜索耗时将与目标出现的位置有关,最长约为 1.6 秒。 | ||
|
||
采用 SQLite 后,8 位生日的查询平均耗时在 1 ms 以下。 | ||
|
||
## 查询到的概率 | ||
|
||
从 N 位随机数中发现 d 位连续数字(N >> d)的概率为: | ||
|
||
<img src="http://latex.codecogs.com/gif.latex?1-(1-0.1^d)^N" /> | ||
|
||
因此可以推测,在 π 的前 10 亿位中找到任意 8 位数字的概率约为 99.995%,实测从 1900 年至 2050 年的所有合法 "年月日" 8 位字符串都能从中找到。 | ||
|
||
## Inspired by | ||
|
||
- [The Pi-Search Page](https://www.angio.net/pi/) | ||
- [Irrational Numbers Search Engine](http://www.subidiom.com/pi/) | ||
- [北大数院人 微信公众号](https://mp.weixin.qq.com/s?__biz=MzU3NzA0OTA5Mg==&mid=2247492451&idx=1&sn=e14e794bae706d7c2a4f964325d2e404) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import datetime | ||
import sqlite3 | ||
|
||
from pisearch import get_digits, search_in_Pi | ||
|
||
|
||
def dateRange(start, end, step=1, format=r"%Y%m%d"): | ||
strptime, strftime = datetime.datetime.strptime, datetime.datetime.strftime | ||
days = (strptime(end, format) - strptime(start, format)).days | ||
return [ | ||
strftime(strptime(start, format) + datetime.timedelta(i), format) | ||
for i in range(0, days, step) | ||
] | ||
|
||
|
||
conn = sqlite3.connect(r"data/pi.db") | ||
c = conn.cursor() | ||
|
||
c.execute( | ||
"""CREATE TABLE BIRTHDAY | ||
(DATE INT PRIMARY KEY, | ||
POSITION INT UNIQUE);""" | ||
) | ||
|
||
date_list = dateRange("19000101", "20510101") | ||
digits = get_digits(r"data/Pi - Dec - Chudnovsky.txt") | ||
if digits: | ||
for date in date_list: | ||
position = search_in_Pi(date, digits) | ||
if position: | ||
t = (int(date), position) | ||
c.execute( | ||
"INSERT INTO BIRTHDAY (DATE,POSITION) \ | ||
VALUES (?, ?)", | ||
t, | ||
) | ||
print("success: " + date) | ||
conn.commit() | ||
else: | ||
print("Not found: " + date) | ||
else: | ||
print("Pi file error!") | ||
|
||
conn.commit() | ||
conn.close() |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import sys | ||
import time | ||
|
||
from pisearch import get_digits, search_pi | ||
|
||
|
||
def judge_birthday(number: str): | ||
day_in_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, | ||
} | ||
if not (number.isdecimal()): | ||
return False | ||
if len(number) < 8: | ||
# number = "19" + number | ||
return False | ||
year = int(number[:4]) | ||
month = int(number[4:6]) | ||
day = int(number[6:]) | ||
if (year > 2050) or (year < 1900): | ||
return False | ||
if (month > 12) or (month < 1): | ||
return False | ||
else: | ||
day_correct = day_in_month[number[4:6]] | ||
if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0): | ||
day_correct += 1 | ||
if (day < 1) or (day > day_correct): | ||
return False | ||
return True | ||
|
||
|
||
if __name__ == "__main__": | ||
digits = get_digits(r"data/Pi - Dec - Chudnovsky.txt") | ||
if digits: | ||
if len(sys.argv) > 1: | ||
date = sys.argv[1] | ||
else: | ||
print("Enter birthday (8 digits): ", end="") | ||
date = input() | ||
if judge_birthday(date) or True: | ||
start_time = time.time() | ||
position = search_pi(date, digits) | ||
end_time = time.time() | ||
print("Query takes %.2f ms" % ((end_time - start_time) * 1000.0)) | ||
if position: | ||
print('position of "%s" : %s' % (date, position)) | ||
else: | ||
print("Not found!") | ||
else: | ||
print("Invalid birthday!") | ||
else: | ||
print("Pi file error!") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import sqlite3 | ||
import sys | ||
import time | ||
from date_search import judge_birthday | ||
|
||
|
||
def query_pi(datebase: str, date: int): | ||
try: | ||
conn = sqlite3.connect(datebase) | ||
c = conn.cursor() | ||
cursor = c.execute("SELECT POSITION from BIRTHDAY where DATE=?", (date,)) | ||
result = cursor.fetchone() | ||
if not result: | ||
return None | ||
conn.close() | ||
return result[0] | ||
except Exception as e: | ||
print(e) | ||
|
||
|
||
if __name__ == "__main__": | ||
if len(sys.argv) > 1: | ||
date = sys.argv[1] | ||
else: | ||
print("Enter birthday (8 digits): ", end="") | ||
date = input() | ||
if judge_birthday(date): | ||
start_time = time.time() | ||
position = query_pi(r"data/pi.db", int(date)) | ||
end_time = time.time() | ||
print("Query takes %.2f ms" % ((end_time - start_time) * 1000.0)) | ||
print(position) | ||
else: | ||
print("Invalid birthday!") |
Oops, something went wrong.