小练习:python简单验证哥德巴赫猜想(数据范围:2 ~ 200000000内的偶数)
考研休息的间隙,顺手敲了敲练习的算法,验证哥德巴赫猜想
ps:本想验证20亿以内的,但是改了几次之后才发现随机数少打了个0
pps:计算机专业,没有学过数论,如果有错的地方欢迎指正。
补充知识:
加法算式中,两个相加的数叫做加数。(doge)
合数是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。
题目:任何一个大于2的偶数总能表示为两个素数之和,比如 24 = 5 + 19,其中5和19都是素数。本实验的任务是设计一个程序,验证2亿以内的偶数都可以分解成两个素数之和。
要求:每一个大于2的偶数只需输出,左边加数最小的等式,如:24 = 5 + 19
示例:
输入:2
输出:[10944780, 12629962]
10944780 = 17 + 10944763
12629962 = 11 + 12629951
解释:程序自动生成2个范围在20亿内的两个数,并以列表形式打印,然后依次输出左边加数最小的等式,该等式为两个素数相加且等于程序生成的数。
目录
小练习:python简单验证哥德巴赫猜想(数据范围:2 ~ 200000000内的偶数)
一、库
导入所需的包
import random as rd
import time
random包用于生成数列,time用于查看算法运行时间,便于优化。
二、生成列表
frequency = int(input())
question = rd.sample(range(2, 2000000000, 2), frequency)
说明:输入需要生成数的个数frequency,然后随机生成一个元素个数为frequency个的不重复且为偶数的随机数列。
三、验证哥德巴赫猜想
def Goldbach_conjecture(num, left, right):
global check
if left > right:
return
if prime_num(left) and prime_num(right) and num == left + right:
print(str(num)+' = '+str(left)+' + '+str(right))
check += 1
return
Goldbach_conjecture(num, left+1, right-1)
参数:
参数名 | 数据类型 | 说明 |
---|---|---|
num | int | 需要判断的数 |
left | int | 左边的加数 |
right | int | 右边的加数 |
说明:使用递归的方法,判断一个数是否是由两个素数相加,若是则打印并返回,若不是则将左边加数left加1,右边加数right减1,直至这个数是由两个素数相加结束,或若该数不能由两个素数相加,则返回,此判断条件是左边的加数left大于右边的加数right。
(更新于2020年7月5日,如能优化会重新编辑文章,如果有更优的方法欢迎评论)
四、验证是否为素数
Version 1.0
# version 1.0
def prime_num(num):
division = num-1
while division > 1:
if num % division == 0:
return False
division -= 1
return True
# 当需要验证的数为:[78287612, 72907810]
# 78287612 = 211 + 78287401
# 72907810 = 23 + 72907787
# 算法运行时间: 537.9213174
算法思想:传入参数为需要判断是否为素数的数,将该数num与其依次减1的数division求余数,若无余数,说明该数可以被某一个数(division或division -= 1)相除,且可以除尽。
Version 1.1
def prime_num(num):
list = [2, 3, 4, 5, 6, 7, 8, 9]
if num > 9 :
for i in list:
if num % i == 0:
return False
division = num-1
while division > 1:
if num % division == 0:
return False
division -= 1
return True
# [78287612, 72907810]
# 78287612 = 211 + 78287401
# 72907810 = 23 + 72907787
# 算法运行时间: 183.9283179
算法思想:相较于Version 1.0 添加了一个判断,当需要判断的是否为素数的数大于9时,将其依次与2~9求余数,若无余数,说明该数可以被2~9里的某一个数相除,且可以除尽。
这个版本的算法运行速度比Version 1.0的运行速度明显增加。
对100个数的判断,所需要的时间约为 4758.3389348s
Version 1.2
def prime_num(num):
list = [2, 3, 4, 5, 6, 7, 8, 9]
if num > 9 :
for i in list:
if num % i == 0:
return False
division = 10
while division < num:
if num % division == 0:
return False
division += 1
return True
# [78287612, 72907810]
# 78287612 = 211 + 78287401
# 72907810 = 23 + 72907787
# 算法运行时间: 18.5473815
算法思想:这个版本对Version 2.0增添的判断没有改动,但是修改了Version 1.0的版本的内容,将除数division的判断从从大到小更改至了从小到大,因为此程序的主要实现是左边加数最小。
对100个数的判断,所需要的时间约为 1097.4823412s
Version 1.2.1
def prime_num(num):
# list = [2, 3, 4, 5, 6, 7, 8, 9]
# if num > 9 :
# for i in list:
# if num % i == 0:
# return False
division = 2
while division < num:
if num % division == 0:
return False
division += 1
return True
发现前面的代码多余了。简化代码。
Version 2.0(试除法)
def prime_num(num):
division = 2
while division < pow(num, 1/2)+1:
if num % division == 0:
return False
division += 1
return True
# [78287612, 72907810]
# 78287612 = 211 + 78287401
# 72907810 = 23 + 72907787
# 算法运行时间: 0.0111007
早上起来又跑去研究素数的特征去了,然后从数论的角度发现,若存在大于的因子k,那么 的值一定在 2 ~ 中,所以只需遍历的范围由(2,num-1)变为(2, ),由此division的遍历范围大幅缩小。
对100个数的判断,所需要的时间约为 0.4791687s
Version 2.1
def prime_num(num):
if num % 2 == 0:
return False
division = 3
while division < pow(num, 1/2)+1:
if num % division == 0:
return False
division += 2
return True
# [78287612, 72907810]
# 78287612 = 211 + 78287401
# 72907810 = 23 + 72907787
# 算法运行时间: 0.0064577
此方法根据另一个补充的性质,如果n % 2 != 0,那么就可以从3 ~ 中,只考虑奇数。
对100个数的判断,所需要的时间约为 0.2224611s
(更新于2020年7月6日,如能优化会重新编辑文章,如果有更优的方法欢迎评论)
五、代码
import random as rd
import time
def prime_num(num):
if num % 2 == 0:
return False
division = 3
while division < pow(num, 1/2)+1:
if num % division == 0:
return False
division += 2
return True
check = 0
def Goldbach_conjecture(num, left, right):
global check
if left > right:
return
if prime_num(left) and prime_num(right) and num == left + right:
print(str(num)+' = '+str(left)+' + '+str(right))
check += 1
return
Goldbach_conjecture(num, left+1, right-1)
frequency = int(input())
start = time.clock()
question = rd.sample(range(2, 200000000, 2), frequency)
# 验证集(100个) question = [10944780, 12629962, 19031146, 141007808, 141675580, 31130808, 88336616, 83578662, 80111316, 78454552, 15260056, 10897002, 133766786, 113882600, 7322396, 12011436, 188010002, 173641636, 508332, 196126192, 44820410, 861158, 28593492, 83008190, 1983600, 185990690, 130989756, 171930118, 47246302, 20073510, 187805842, 27120494, 18226334, 43006556, 4150812, 82166286, 1126444, 141296498, 28155052, 51958928, 7190786, 126995632, 8551270, 171296222, 24139592, 103984150, 52544966, 199110410, 80983282, 74456790, 119835496, 72437244, 56849960, 113753482, 134114958, 32076258, 60988480, 134858552, 69681422, 103452536, 131960018, 157717166, 52922590, 83850390, 51966750, 25303274, 168000454, 103240106, 121733868, 113316662, 113139292, 104768496, 72713560, 42728330, 147354146, 66098936, 197099406, 149400582, 42283186, 180273972, 190736934, 11284844, 3197754, 191765768, 39967964, 121326934, 91341678, 67086736, 63300872, 167487516, 191491576, 14627672, 82814362, 127879244, 88721208, 53518212, 107488852, 109438340, 98809284, 125370598]
# 验证集 question = [78287612, 72907810]
print(question)
for i in question:
Goldbach_conjecture(i, 2, i-2)
end = time.clock()
print('算法运行时间:',end-start)
print(check)