小练习:python简单验证哥德巴赫猜想(数据范围:2 ~ 2亿 内的偶数),判断是否为素数(质数),同时基于数论优化判断素数的算法。

小练习: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内的偶数)

一、库

二、生成列表

三、验证哥德巴赫猜想

四、验证是否为素数

Version 1.0

Version 1.1

Version 1.2

Version 1.2.1

Version 2.0

Version 2.1

五、代码



一、库

导入所需的包

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)

参数:

参数名数据类型说明
numint需要判断的数
leftint左边的加数
rightint右边的加数

说明:使用递归的方法,判断一个数是否是由两个素数相加,若是则打印并返回,若不是则将左边加数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

早上起来又跑去研究素数的特征去了,然后从数论的角度发现,若存在大于\sqrt{n}的因子k,那么\frac{n}{k} 的值一定在 2 ~ \sqrt{n}中,所以只需遍历的范围由(2,num-1)变为(2, \sqrt{num}由此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 ~ \sqrt{n}中,只考虑奇数。

对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)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值