c语言检验素数eratosthenes,质数(素数),检测素数的N种方法

什么是质数?

质数(Prime number)又称素数, 质数是大于

math?formula=1而且只能被

math?formula=1和自身整除的自然数。大于

math?formula=1的自然数如果不是素数,就称为合数(Composite number)。

算术基本定理

算术基本定理最早由欧几里得证明, 是表示任何合数都可以不断分解成素数的组合,如

math?formula=108可以分解为

math?formula=2%EF%BC%8C3两个素数,欧几里得发现把这些素数因子的次方相乘可以得到原来的数字

math?formula=108%3D2%5E2%C3%973%5E3,而且这种分解为素数乘积的方式是唯一的。素数因子分解就像是一个锁,而且只有一把开锁的钥匙,这也是现代密码学的基础。

素数定理

素数定理描述素数在自然数中分布的渐进情况,就是小于

math?formula=n中素数的个数随着

math?formula=n的增大素数的密度就越来越小。当

math?formula=n越来越大时它的图像就越来越接近

math?formula=%5Cfrac%7Bx%7D%7Bln(x)%7D。所以一个数字内素数的数量

math?formula=x约等于

math?formula=%5Cfrac%7Bx%7D%7Bln(x)%7D,当

math?formula=x越大时误差越小。所以比如要生成

math?formula=s大小的素数序列,使用这个方法的话就要提高反推出来上界

math?formula=x的大小。

试除法

那么怎么判断一个数是不是素数?这也是很多面试题里面问到的。一种简单的方法是试除法。

比如判断

math?formula=n是不是素数,可以让

math?formula=n除以

math?formula=1

math?formula=n之间的整数,如果可以除尽则表示是合数否则是质数。

def isPrime(n):

if n < 2: return False

for i in range(2, n):

if n % i == 0:

return False

return True

但是可以发现大于

math?formula=2偶数都不是质数,因为它们可以被

math?formula=2整除,所以这可以减少迭代次数。

def isPrime(n):

if n == 2: return True

if n < 2 or n % 2 == 0: return False

for i in range(3,n,2):

if n % i == 0:

return False

return True

还有没有更快的方法?有,就是迭代到

math?formula=%5Csqrt%7Bn%7D,因为一个数字分解为两个因子,其中必然有一个小于或等于

math?formula=%5Csqrt%7Bn%7D,不然两个都大于

math?formula=%5Csqrt%7Bn%7D它们相乘就大于

math?formula=n了。

def isPrime(n):

if n == 2: return True

if n < 2 or n % 2 == 0: return False

for i in range(3, int(n ** 0.5) + 1, 2):

if n % i == 0:

return False

return True

试除法还能不能更快?根据算术基本定理任何合数最终都可以分解为素数的组合,所以只用除小于

math?formula=n的素数就行了。

筛选法

筛选法(sieve of Eratosthenes)可以给出小于

math?formula=n的素数序列,比如要生成

math?formula=100内的素数序列,首先可以生成2到100间数字表,然后将列表第一个没被标记的数字标记为素数然后将数字表中它的倍数标记为合数,然后不断重复这个步骤。

12907d4fa358

image

对于给定

math?formula=n只需要遍历到

math?formula=%5Csqrt%20n,剩下的就都是素数了。

def sieve(n):

composite = {}

primes = [2]

for i in range(3, int(n ** 0.5) + 1, 2):

if i not in composite:

for j in range(i ** 2, n + 1, i): composite[j] = 1

for k in range(3, n + 1, 2):

if k not in composite: primes.append(k)

return primes

对于不指定

math?formula=n的大小可以这么写。

def genPrimes():

primes = [2]

i = 1

yield 2

while True:

i += 2

for p in primes:

if i % p == 0:

break

else:

primes.append(i)

yield i

费马小定理

虽然一般判断是不是素数用试除法就行了,但是当要判断一个大数是不是素数时,也还是太慢了。

费马小定理是欧拉定理的一个特殊情况,它是说一个正整数

math?formula=a的质数

math?formula=p次方减

math?formula=a可以被

math?formula=p次方整除。用公式表示可以为

math?formula=a%5E%7Bp-1%7D%20%5Cequiv%201%5C%20(mod%5C%20p)

但是也不能完全正确,比如

math?formula=227%5E%7B561-1%7D%20%5Cequiv%201%5C%20(mod%5C%20561) 但是

math?formula=561%3D3%C3%9711%C3%9717,所以可以随机生成多个

math?formula=a来测试,这样就可以降低将出错概率。

import random

def gcd(a, b):

while b != 0:

a, b = b, a % b

return a

def randA(p):

return random.randint(1, p - 1)

def fastMod(f, p, m):

ans = 1

whlie p > 0:

if p % 2 == 1:

ans = (ans * f) % m

p -= 1

p //= 2

f = (f ** 2) % m

return ans

def isPrime(p):

trials = 30

for i in range(trials):

a = randA(p)

if gcd(a, p) != 1: return False

if fastMod(a, p - 1, p) != 1: return False

return True

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值