博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于质数(素数)
阅读量:7222 次
发布时间:2019-06-29

本文共 2432 字,大约阅读时间需要 8 分钟。

什么是质数?

质数(Prime number)又称素数, 质数是大于1而且只能被1和自身整除的自然数。大于1的自然数如果不是素数,就称为合数(Composite number)。

算术基本定理

算术基本定理最早由欧几里得证明, 是表示任何合数都可以不断分解成素数的组合,如108可以分解为2,3两个素数,欧几里得发现把这些素数因子的次方相乘可以得到原来的数字108=2^2×3^3,而且这种分解为素数乘积的方式是唯一的。素数因子分解就像是一个锁,而且只有一把开锁的钥匙,这也是现代密码学的基础。

素数定理

素数定理描述素数在自然数中分布的渐进情况,就是小于n中素数的个数随着n的增大素数的密度就越来越小。当n越来越大时它的图像就越来越接近\frac{x}{ln(x)}。所以一个数字内素数的数量x约等于\frac{x}{ln(x)},当x越大时误差越小。所以比如要生成s大小的素数序列,使用这个方法的话就要提高反推出来上界x的大小。

试除法

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

比如判断n是不是素数,可以让n除以1n之间的整数,如果可以除尽则表示是合数否则是质数。

def isPrime(n):    if n < 2: return False    for i in range(2, n):        if n % i == 0:            return False    return True复制代码

但是可以发现大于2偶数都不是质数,因为它们可以被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复制代码

还有没有更快的方法?有,就是迭代到\sqrt{n},因为一个数字分解为两个因子,其中必然有一个小于或等于\sqrt{n},不然两个都大于\sqrt{n}它们相乘就大于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复制代码

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

筛选法

筛选法(sieve of Eratosthenes)可以给出小于n的素数序列,比如要生成100内的素数序列,首先可以生成2到100间数字表,然后将列表第一个没被标记的数字标记为素数然后将数字表中它的倍数标记为合数,然后不断重复这个步骤。

对于给定n只需要遍历到\sqrt n,剩下的就都是素数了。

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复制代码

对于不指定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复制代码

费马小定理

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

费马小定理是欧拉定理的一个特殊情况,它是说一个正整数a质数p次方减a可以被p次方整除。用公式表示可以为a^{p-1} \equiv 1\ (mod\ p)

但是也不能完全正确,比如227^{561-1} \equiv 1\ (mod\ 561) 但是561=3×11×17,所以可以随机生成多个a来测试,这样就可以降低将出错概率。

import randomdef gcd(a, b):    while b != 0:        a, b = b, a % b    return adef 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 ansdef 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复制代码

转载于:https://juejin.im/post/5c19d072e51d45490253100a

你可能感兴趣的文章
快速排序就这么简单
查看>>
老腊肉级干货 | OOD面试备战攻略
查看>>
Google 回归中国,你准备好成为 Googler 了吗?
查看>>
React Native 项目(One 【一个】客户端)
查看>>
万套源码分享系列一
查看>>
util.promisify 的那些事儿
查看>>
vue3.0 尝鲜 -- 摒弃 Object.defineProperty,基于 Proxy 的观察者机制探索
查看>>
PHP 文件操作的各种姿势
查看>>
Linux 探索之旅 | 第一部分第六课:Linux 如何安装在虚拟机中
查看>>
Jquery第一篇【介绍Jquery、回顾JavaScript代码、JS对象与JQ对象的区别】
查看>>
【火炉炼AI】机器学习039-NLP文本分类器
查看>>
java通过JDBC链接SQLServer2012【转载!!!超详细】
查看>>
cmake使用教程(八)-macro和function
查看>>
掘金广告产品介绍
查看>>
小猪的Python学习之旅 —— 7.Python并发之threading模块(1)
查看>>
腾讯冯宇彦:基于大数据与人工智能的智慧交通云
查看>>
eclipse再见,android studio 新手入门教程(二)项目的导入
查看>>
OpenGL ES 2 0 (iOS) 笔记大纲
查看>>
简述HTTP
查看>>
css笔记
查看>>