您的位置:首页 > 编程语言 > Python开发

【原创】(一)用Python玩转初等数论之质数

2018-01-31 00:47 465 查看


目录

(一)用Python玩转初等数论之质数

一、数论相关内容及文章声明

本系列文章讲些啥

数论是啥?

初等数论又是啥

质数又是啥?

阅读本篇文章需要的知识

同余

取模

整除

在Python中基本的除法有三种,分别是除、取模、取整除

二、进入正题——如何判断质数

法-1

定义-1

程序-1

法-2

定义-2

程序-2

三、准备进阶——生成素数

以程序-2为基本算法

埃拉托斯特尼筛法

四、引用

一、数论相关内容及文章声明

本系列文章讲些啥

正如标题所说的那样,本系列文章讲的就是用Python编程的方法来解决初等数论当中的一些有趣的问题。为什么是初等数论呢?因为笔者能力有限,只能讲初等数论QAQ。 文章中若有错误还望大家指出,我会不断更正的。如果大家有更好的方式方法,不妨在文章下面留言交流。本系列文章会不定期更新,希望大家多多关注哦!OvO

注:未经授权,禁止转载!

数论是啥?

数论(Number Theory)是纯粹数学的分支之一,它研究各种数之间深刻而微妙的关系。被誉为“最纯”的数学领域。

数论包含许多分支,如初等数论、几何数论、代数数论、分析数论等等。由于其分支过于复杂,就不一一介绍了。

前段时间,望月新一关于ABC猜想的证明(天书)刷了一波朋友圈(可能只是刷了我的朋友圈)。ABC猜想也是典型的数论问题(怕是最难的之一)。但对于望月新一的那四篇天书(其实不止四篇)来说,小编我无能为力。。。只能发个表情感慨一下/(ㄒoㄒ)/~~



读到这里可能会有人觉得“ 数论这么害怕,劳资不看了(╯‵□′)╯︵┻━┻ ”

数论难归难,但也有其有趣的地方。

比如各位都非常熟悉的勾股定理

a2+b2=c2a2+b2=c2

由此引申出来的勾股数组 (国外称为:毕达哥拉斯三元组 Pythagorean triple),即满足a2+b2=c2a2+b2=c2的正整数组。如十分著名的 (3,4,5)、(5,12,13)、(7,24,25)等等。实际上像 (3,4,5) 扩展n倍(n为正整数)所构成的 (3n,4n,5n)也是勾股数组。而像(3,4,5) 这样不是由其他勾股数组扩展而来的三元组就叫做本原勾股数组素三元组 (primitive Pythagorean triples)。更为严格的定义是: (a, b, c) 三者互质(它们的最大公因数是 1),它们就称为素三元组(嘿嘿,这就是互质的一个应用)。从勾股数组中诞生勾股数组定理给出了更为一般的本原勾股数的产生规则,这将会在以后的文章中讲述。

初等数论又是啥

初等数论是几乎所有数论分支的基础,相对来说较为简单(大概吧。。毕竟数论都不简单)

它使用不超过高中(奥赛!?)程度的初等代数处理的数论问题,最主要的工具包括整数的整除性与同余。重要的结论如中国余数定理、费马小定理、二次互反律等。

总而言之,就是数论所有分支中最简单最基础的那个,也是历史上最早出现的。

质数又是啥?

质数(Prime Numbers),又称为素数,指在大于1的自然数中,除了1和其本身外,无法被其他自然数整除的数(也可定义为只有1与该数本身两个正因数的数)。大于1的自然数若不是素数,则称之为合数

2、3、5、7为素数,4、6、8、9为合数。

质数有很多定义,有一些定义都能够作为我们判别质数的算法,这将会在后文举例。

阅读本篇文章需要的知识

同余

若记5除以3余数为25 mod 3 = 2

同理两个整数ab,若 a除以 bc ,则记作 a mod b = c

若两个整数 ab 它们除以正整数 m 所得余数相同,则称 ab 同余

8 ≡≡ 5 (mod 3 )

取模

即求除法的余数,如 5 mod 3 = 253 取模得 2

整除

整除很容易理解的,简而言之就是数 a 除以数 b 的余数为 0

记作 a mod b = 0

在Python中基本的除法有三种,分别是除、取模、取整除

示例如下

a / b               #除,即常规除法,返回值为int型或float型
'''
>>> 5 / 3
1.6666666666666667
'''

a % b               #取模,返回除法的余数,值为int型或float型
'''
>>> 5 % 3
2
'''

a // b              #取整除,返回商的整数部分,值为int型或float型
'''
>>> 5 // 3
1
'''


二、进入正题——如何判断质数

法-1

定义-1

就是之前的那个定义:在大于1的自然数中,除了1和其本身外,无法被其他自然数整除的数(也可定义为只有1与该数本身两个自然数因数的数)。

换句话说,数n除以(2n-1)之间任何数的余数都不为0,则n就是质数

程序-1

根据定义-1的思路可设计程序如下

while True:
n = input('Please input a *natural number*: ')
#一般来说数论中的自然数不包括0,但本程序中的自然数默认包含0
if n.isdigit():
break
#isdigit()检测输入是否只由数字组成
else:
print(n,' is not a *natural number*')
'''
使用While循环保证输入的值为纯数字
'''
n = int(n)
'''
input输入的数据类型为str,只有将其转换为int型才能继续以下操作
'''
if n < 2:
print(n,' is not a prime number')
#0和1都不是质数
elif n == 2:
print('2 is a prime number')
#2是质数,但为了以下循环能够完美运行,故将2单独做一个判断
else:
for i in range(2, n):
#当n大于等于2时进入循环
if n % i == 0:
print(n,' is not a prime number')
print(n, '=', i,'*', int(n/i), sep=' ')
break
#若n有除1和n本身以外的因数,则n必为合数
else:
i += 1
if i == n:
print(n,' is a prime number')
break
#当i=n时退出循环并输出n为质数
'''
根据质数的定义
若自然数n除以(2,n-1)范围内所有自然数,其余数都不为零
则n必为素数
'''


9971001是不是质数



此算法有一个弊端:若有质数n则该算法需运行for循环n-2次才能判断n为质数,对于很大的质数来说效率偏低。

法-2

定义-2

n为自然数,若n不为任一在2与n−−√n之间的整数之倍数,则n质数

为什么要这样定义呢,因为n=n−−√×n−−√n=n×n,若n有一对因子 (m,k) 使得n合数,则必有

1<m≤n−−√,n>k≥n−−√1<m≤n,n>k≥n

或者

1<k≤n−−√,n>m≥n−−√1<k≤n,n>m≥n

这也不难理解,比如6的一对因子 (2,3) 就满足

1<2≤6–√,6>3≥6–√1<2≤6,6>3≥6

程序-2

程序-1类似

import math

while True:
n = input('Please input a *natural number*: ')
#一般来说数论中的自然数不包括0,但本程序中的自然数默认包含0
if n.isdigit():
break
#isdigit()检测输入是否只由数字组成
else:
print(n,' is not a *natural number*')
'''
使用While循环保证输入的值为纯数字且大于等于2
'''
n = int(n)
'''
input输入的数据类型为str,只有将其转换为int型才能继续以下操作
'''
if n < 2:
print(n,' is not a prime number')
#0和1都不是质数
elif n == 2:
print('2 is a prime number')
#2是质数,但为了以下循环能够完美运行,故将2单独做一个判断
else:
for i in range(2, int(round(math.sqrt(n)))+1):
#当n大于等于2时进入循环
#通过math.sqrt()函数求n的平方根,并将该值通过round()函数四舍五入,最后转换为int型
if n % i == 0:
print(n,' is not a prime number')
print(n, '=', i,'*', int(n/i), sep=' ')
break
#若n有除1和n本身以外的因数,则n必为合数
else:
i += 1
if i == int(round(math.sqrt(n))) + 1:
print(n,' is a prime number')
break
#当i=(√n + 1)的四舍五入值时退出循环并输出n为质数
'''
根据质数的定义-2
测试n是否为任一在2与√n之间的整数之倍数。
若不是,则n必为素数
'''


111119991是不是质数



尽管代码看上去比程序-1多了几行,但对于大素数的判别要比其快一些

ψ(`∇´)ψ

三、准备进阶——生成素数

以程序-2为基本算法

为什么要用程序-2的算法呢,因为我乐意( ̄▽ ̄)”

哈哈~Just a joke!(~ ̄▽ ̄)~

说正经的,程序-2要优秀一些,之前也提到过,所以用它。

说干就干,用以下程序生成[2, k]内的所有素数

import math

while True:
k = input('Please input upper limit: ')
#输入上限,默认范围为[2,k]
if k.isdigit():
if int(k) >= 2:
break
#isdigit()检测输入是否只由数字组成
else:
print(k,' is not >= 2')

k = int(k)

def prime(n):
if n < 2:
n = 0
#0和1都不是质数
elif n == 2:
n = 1
#2是质数,但为了以下循环能够完美运行,故将2单独做一个判断
else:
for i in range(2, int(round(math.sqrt(n)))+1):
#当n大于等于2时进入循环
#通过math.sqrt()函数求n的平方根,并将该值通过round()函数四舍五入,最后转换为int型
if n % i == 0:
n == 0
break
else:
i += 1
if i == int(round(math.sqrt(n))) + 1:
n = 1
break
#当i=(√n + 1)的四舍五入值时退出循环
return n
'''
使用该函数判断n是否为质数,是则prime(n)=1,否则prime(n)=0
'''

for n in range(2, k+1):
if prime(n) == 1:
print(n)
n += 1
#判断n是否为素数,是则输出n
elif n == k+1:
break


这里将程序-2修改之后定义为 prime() 函数,方便调用。

现在来打印下20以内所有的素数试试( •̀ ω •́ )✧



埃拉托斯特尼筛法

埃拉托斯特尼筛法(希腊语:κόσκινον Ἐρατοσθένους,英语:sieve of Eratosthenes ),简称埃氏筛,是一种简单且年代久远的筛法,用来找出一定范围内所有的质数

所使用的原理是从2开始,将每个素数的各个倍数,标记成合数。一个素数的各个倍数,是一个差为此素数本身的等差数列。此为这个筛法和试除法不同的关键之处,后者是以素数来测试每个待测数能否被整除。

埃拉托斯特尼筛法是列出所有小素数最有效的方法之一,其名字来自于古希腊数学家埃拉托斯特尼,并且被描述在尼科马库斯所著 Introduction to Arithmetic 中。

尽管该算法相比我之前给出的算法运算步骤要少得多,但它也有一个局限。就是判断n为质数之前必须知道n之前所有的素数。

其算法用伪代码表示如下

Input: an integer n > 1
Let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.
for i = 2, 3, 4, ..., not exceeding √n:
if A[i] is true:
for j = i
2, i
2+i, i
2+2i, i
2+3i, ..., not exceeding n :
A[j] := false
Output: all i such that A[i] is true


不多说了,直接上代码

while True:
k = input('Please input upper limit: ')
#输入上限,默认范围为[2,k]
if k.isdigit():
if int(k) >= 2:
break
#isdigit()检测输入是否只由数字组成
else:
print(k, ' is not >= 2')
'''
使用While循环保证输入的值为纯数字且大于等于2
'''
k = int(k)

def eratosthenes(n):
P = [i for i in range(2, n + 1)]
p = 0
while True:
if P[p]**2 > P[-1]:
break
for i in P[p + 1:]:
if i % P[p] == 0:
P.remove(i)
p += 1
return P
#这函数不是我写的,一看就比我写的高级多了>﹏<

if __name__ == "__main__":
print(eratosthenes(k))


运行一下,输出1000以内的质数试试



四、引用

https://zh.wikipedia.org/wiki/%E6%95%B0%E8%AE%BA

https://zh.wikipedia.org/wiki/%E5%88%9D%E7%AD%89%E6%95%B8%E8%AB%96

https://zh.wikipedia.org/wiki/%E7%B4%A0%E6%95%B0

https://zh.wikipedia.org/wiki/%E5%9F%83%E6%8B%89%E6%89%98%E6%96%AF%E7%89%B9%E5%B0%BC%E7%AD%9B%E6%B3%95

Silverman.J.H. (2015), A Friendly Introduction to Number Theory (Fourth Edition), ISBN 978-7-111-52200-3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Python 数学 数论