python找出素数_[Python 1] 如何使用Python找质数?

学习生物信息需要熟练掌握一门甚至多门编程语言,比如Python、R、C++,这取决于你的需求。

但语言只是工具,最关键的是如何合理使用工具去解决生物学问题,这需要你去多写、多查、多看来锻炼。不然给你把屠龙刀,你不去修炼,它也只是块废铁。工具有多好不仅取决于自身,更在于使用的人。

为了领略生物信息学的意义、美好、乐趣,之后我会分享更多文章,敬请期待~

本文内容主要包括:质数和孪生质数的定义

质数分布的规律

两种实现方法,逐步优化~

为了更好的解决问题,我们先把“如何使用Python找质数”范围缩小一下,变成“如何使用Python找出100以内的素数”。

接下来,先明确概念,以便精确下手。

什么是质数?

质数( Prime number ):又称素数,指在大于1的自然数中,除了1和自身外,无法被其他自然数整除的数(也可定义为只有1和本身两个因素的数)。

与之相对的是合数,指自然数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。

试除法

根据质数的定义,可以有一个直观的思路:将

equation?tex=n 除以每个大于

equation?tex=1 且小于等于

equation?tex=%5Csqrt%7Bn%7D 的整数,如果不能被整除,结果有余数,那么

equation?tex=n 就为质数。

这种方法也叫试除法。

#!/usr/bin/env python

# coding=utf-8

# file: is_prime.py

"""试除法,判断质数"""

import math

def is_prime(n):

"""Define whether the number is a prime number"""

if n <= 1:

return False # 质数要是大于1的自然数

for i in list(range(2, int(math.sqrt(n) + 1))): # 注意要开方后加1

if n % i == 0:

return False

break

return True

if __name__ == "__main__":

primes = [i for i in list(range(2,100)) if is_prime(i)] # range从2开始

print(primes)

最终得到 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]。和搜索结果一致~1到100的质数

在Python中,一个.py文件就是一个模块。一般情况下,模块名就是文件名。

__name__ 存放当前模块名,当模块被直接运行时模块名为 __main__ 。

所以,if __name__ = ' __main__' 表示:当模块被直接运行时,该行以下的代码块将被运行;当模块是被导入(import)时,代码块不被运行。

试除法虽然简单,但是在测试大整数时很快会变得不切实际。因为可能的约数数量会随着n的增加而迅速增加。根据素数定理,小于

equation?tex=+%5Csqrt%7Bn%7D+++ 的素数之数量大约为

equation?tex=++%7B%5Cdisplaystyle+%7B%5Cfrac+%7B%5Csqrt+%7Bn%7D%7D%7B%5Cln+%7B%5Csqrt+%7Bn%7D%7D%7D%7D%7D 。也就是说,采用试除法判断

equation?tex=%7B%5Cdisplaystyle+n%3D10%5E%7B20%7D%7D ,要除4.5亿次,对许多实际应用而言都太过庞大。

那么,有没有改进的方法呢?接着看下去吧~

质数分布规律

首先看一个关于质数分布的规律:大于等于5的质数一定和6的倍数相邻,例如5和7,11和13,17和19。

用符号表示更容易理解:当n≥5时,如果n-1和n+1都为质数,那么n一定是6的倍数。

如何证明这个规律呢?

证明:设

equation?tex=x%5Cgeq1

equation?tex=x 为整数。

则大于等于

equation?tex=5 的自然数可表示如下:

equation?tex=%C2%B7%C2%B7%C2%B7%C2%B7%C2%B7%C2%B76x-2%EF%BC%8C6x-1%EF%BC%8C6x%EF%BC%8C6x%2B1%EF%BC%8C6x%2B2%EF%BC%8C6x%2B3%EF%BC%8C6x%2B4%EF%BC%8C6x%2B5%EF%BC%8C6x%2B6%EF%BC%8C6x%2B7%C2%B7%C2%B7%C2%B7%C2%B7%C2%B7%C2%B7

即:

equation?tex=%C2%B7%C2%B7%C2%B7%C2%B7%C2%B7%C2%B72%283x-1%29%EF%BC%8C6x-1%EF%BC%8C6x%EF%BC%8C6x%2B1%EF%BC%8C2%283x%2B1%29%EF%BC%8C3%282x%2B1%29%EF%BC%8C2%283x%2B2%29%EF%BC%8C6x%2B5%EF%BC%8C6%28x%2B1%29%EF%BC%8C6%28x%2B1%29%2B1%C2%B7%C2%B7%C2%B7%C2%B7%C2%B7%C2%B7

注意可以因式分解的式子。其中,

equation?tex=6x+ 可以被

equation?tex=6 整除,而

equation?tex=6x%2B2

equation?tex=6x%2B3

equation?tex=6x%2B4 分别可以写成

equation?tex=2%283x%2B1%29

equation?tex=3%282x%2B1%29

equation?tex=2%283x%2B2%29 的形式,所以它们都一定不是质数。

剩下的就是

equation?tex=6x-1

equation?tex=6x%2B1

equation?tex=6x%2B5 ,代入几个数字试一下:

x = 1 时,为5,7,11

x = 2 时,为11,13,17

可以看到11被计算了两次。能不能减少计算,更好的表示大于等于5的质数呢?

实际上,可以用

equation?tex=6x-1 表示

equation?tex=6x%2B5 。为什么呢?因为

equation?tex=6x%2B5+%3D+6%28x%2B1%29-1

所以大于等于5的质数可以表示为:

equation?tex=6x-1

equation?tex=6x%2B1 。这两个数都在

equation?tex=6x 身边不离不弃。

以上即证明了质数分布的规律:大于等于

equation?tex=5 的质数一定和

equation?tex=6 的倍数相邻。

我们来试试用Python实现这种思路,建议新手先自行尝试再看下面代码,更容易理解:

#!/usr/bin/env python

#coding:utf-8

# file: is_prime.py

"""质数分布规律,判断质数"""

def is_prime(n):

"""Define whether the number is a prime number"""

if n <= 1:

return False # 质数要是大于1的自然数

elif n == 2 or n == 3: # 小于5且大于1的数中,只有2和3是质数

return True

elif n % 6 != 1 and n % 6 !=5: # n = 6x+1 或 n = 6x+5 (6x-1), 质数一定在6倍数的两侧

return False

else:

return True

if __name__ == "__main__":

primes = [i for i in list(range(2,100)) if is_prime(i)] # range从2开始

print(primes)

结果是[2, 3, 5, 7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49, 53, 55, 59, 61, 65, 67, 71, 73, 77, 79, 83, 85, 89, 91, 95, 97]。

相比之前试除法得出的[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97],多了几个合数,如25,55,49。

抓抓脑壳,究竟出了什么差错?

事实上,虽然质数是出现在

equation?tex=6x%2B1 或是

equation?tex=6x-1 的数列中,但是满足这个条件的数却并不一定是质数。举个例子,6的4倍是24,它的两侧分别是23和25 ,但25不是质数。

问题来啦~为什么满足

equation?tex=6x%2B1 或是

equation?tex=6x-1 (

equation?tex=x%5Cgeq1 )的数不一定是质数?

如何从满足

equation?tex=6x%2B1 或是

equation?tex=6x-1 (

equation?tex=x%5Cgeq1 )的数中进一步筛出质数?

先着手第一个问题,我们“改造”一下这两个式子:

equation?tex=6x+%2B+1+++%3D6%28x%2B1%29-5+%3D+6%28x-1%29+%2B+7+

equation?tex=6x+-1+%3D+6%28x-1%29+%2B+5+%3D+6%28x%2B1%29-7

可以看到,如果

equation?tex=x%2B1

equation?tex=x-1 是5或7的倍数,那么

equation?tex=6x%2B1

equation?tex=6x-1 (

equation?tex=x%5Cgeq1 )也是5或是7的倍数,它俩就不是质数了。

所以满足

equation?tex=6x%2B1 或是

equation?tex=6x-1 (

equation?tex=x%5Cgeq1 )的数不一定是质数。

所以如果想解决第二个问题,就得在代码中增加判断 n 是否为5或7的倍数。注意,这里n要大于7,不然会把5和7漏掉,它俩也是质数。

#!/usr/bin/env python

#coding:utf-8

# file: is_prime.py

"""质数分布规律,判断质数"""

def is_prime(n):

"""Define whether the number is a prime numbern <= 1, false1 <= n <= 7, output 2,3,5,77 < n, first determine n % 6 == 1 or n % 6 == 5, than filter n % 5 == 0 and n % 7 == 0"""

if n <= 1:

return False

elif n == 2 or n == 3 or n == 5 or n == 7:

return True

elif n % 6 != 1 and n % 6 !=5:

return False

elif n % 5 !=0 and n % 7 !=0: # 改进的地方

return True

if __name__ == "__main__":

primes = [i for i in list(range(2,100)) if is_prime(i)] # range从2开始

print(primes)

返回的结果是[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97],和试除法的结果一致。

同样的思路可以换一种方式写代码,另外也可以进一步使用time模块比较两种的时间:

#!/usr/bin/env python

#coding:utf-8

"""质数分布规律,判断质数"""

from math import sqrt

import time # 比较代码运行时间

start = time.time()

def is_prime(n):

if n % 5 == 0 or n % 7 == 0: # 判断n能否被5或7整除

return False # 是,则为假

else:

return True

if __name__ == "__main__":

n = 1 #输入n值

if n > 7:

num = list(range(5, n+1, 6)) + list(range(7, n+1, 6))

primes = [x for x in num if is_prime(x)]+[2,3,5,7]

primes.sort()

elif n == 7:

primes = [2,3,5,7]

elif 5 <= n <= 6:

primes = [2,3,5]

elif 3 <= n <= 4:

primes = [2,3]

elif n == 2:

primes = [2]

else:

primes = ""

print("Prime number don't exist")

print(primes)

end = time.time()

print(str(end-start))

到这里就大功告成啦~

想理解算法时间复杂度的表示法,先要搞明白何谓“算法时间复杂度”。

如果你学过开车的话(没有的话,回忆一下初中物理),就会知道,挂一档时,可能发动机转十几圈,车轮才转一圈;但挂5档时,可能发动机转一圈,车轮就转了一圈。

换句话说,在不同挡位,发动机转一圈,车轮转多少是不一样的。

这个玩意儿背后,其实就是初中学过的轮轴原理。

作者:invalid s

最后补充下“孪生质数猜想”:孪生素数的问题已经有约200年的历史。

“孪生质数”是指两个相差为2的质数,所以上面我们说的

equation?tex=6x%2B1

equation?tex=6x-1 也互为孪生质数。

“孪生素数猜想”是说,存在无穷对孪生质数。在1900年的国际数学家大会上,希尔伯特将孪生质数猜想列入了他那著名的23个数学问题。

关于质数还有很多有趣的东西,比如梅森素数、数论。你可以自行了解,这里就不展开了。

现在,你学会了如何用Python找质数了吗?

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值