Miller-Rabin素数检测算法笔记

2024-02-19 14:38

本文主要是介绍Miller-Rabin素数检测算法笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

摘自:https://blog.csdn.net/u010646250/article/details/51927085

 

本文内容主要参考《程序员的数学思维修炼》一书中对素数和余数的讲解及这篇博文:
Miller-Rabin素数测试学习笔记
以及这篇文章:
数论部分第一节:素数与素性测试(这篇文章非常好,很清晰的讲解了从素数定义到素数检测算法的过程,比我看到的其他所有资料都好,就是有点长)


先介绍一个概念:互素(或叫互质)

如果a和b两个数的公约数只有1,那么a和b互质,记做(c,m)=1。

根据素数定义,素数与所有小于它的正整数互素。

再介绍几个余数的性质及推广出的几个变换:
(a + b) mod p == (a mod p + b mod p) mod p
(a * b) mod p == ((a mod p) * (b mod p)) mod p
ab mod p == (a mod p)b


要想理解Miller-Rabin,需要先了解一下费马小定理。

Miller-Rabin素数检测算法是基于费马小定理的改进概率算法。

费马小定理

假如p是质数,且(a,p)=1,那么 a^(p-1)≡1(mod p)[或( ap-1 mod p ≡ 1),mod是取模的意思,下同]。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。

(摘自百度百科)

费马小定理是关于素数判定的必要非充分条件,即可以说p是质数且a、p互质的情况下a(p-1)≡1(mod p),而不能说只要满足恒等式且a、p互质,p就一定是素数。由此引出伪素数的概念:

伪素数,又叫做伪质数:它满足费马小定理,但其本身却不是素数。若n能整除2^(n-1)-1 [或(2n-1-1)],并且n是非偶数的合数,那么n就是伪素数。

(摘自百度百科)

事实上,偶伪素数也是存在的,并且已被证明有无穷多个。

在伪素数中,存在一组特殊的数,叫做卡迈克尔数,定义为:

对于合数n,如果对于所有正整数b,b和n互素,都有同余式b^(n-1)≡ 1 (mod n) [或(bn-1 mod n ≡ 1)]成立,则合数n为Carmichael数。

(摘自百度百科)

可见,卡迈克尔数一定是合数,且满足费马小定理。卡迈克尔数也被证明有无穷多个,而前一亿个数中,只有255个卡迈克尔数。

庆幸的是,虽然费马小定理的逆定理不完全成立,但在大多数情况下还是有效的。

Fermat素性测试

基于费马小定理 ap-1 mod p≡1公式,(随机地)选取若干个小于p的正整数为a,若所有的a都满足p-1 mod p≡1,则基本认为p是素数。

Fermat素性测试实际上就是对费马小定理的应用。

统计表明,在前10亿个自然数中共有50847534个素数,而满足2^(n-1) mod n = 1的合数n有5597个,这些合数都是以2为底的伪素数。其中一些合数可能在a=2时通过了测试,却不能通过a=3时的测试。能同时通过a=2和a=3的测试的合数叫做以2和3为底的伪素数,前10亿中只有1272个。所以,Fermat素性测试需要做相互独立的若干轮随机测试来降低出错的可能性。

然而,坑爹的是,即使取遍1到n-1的所有整数进行素性测试,仍然会存在一些伪素数没有被查出来,这些数被称为卡迈克尔数(上文有介绍),前10亿中有600多个。

Miller-Rabin素数测试

Miller-Rabin素数测试基于下面的新定理:

如果p是素数,x是小于p的正整数,且x2 mod p = 1,那么要么x=1,要么x=p-1。这是显然的,因为x2 mod p = 1相当于p能整除x2-1,也即p能整除(x+1)(x-1)。由于p是素数,那么只可能是x-1能被p整除(此时x=1)或x+1能被p整除(此时x=p-1)。(ps:素数p只能整除0和它自己)

(摘自数论部分第一节:素数与素性测试)
通过上面这个定理来加强费马小定理,可以得到这个公式:
ad*2r mod p =1
根据上面的定理和公式,在进行Fermat测试时,还需测试d*2r-1时ad*2r mod p是否等于1或者p-1,如果通过则测试d*2r-2时是否成立,直到r=0或者ad*2r-s mod p = p-1,其中0≤s≤r-1。

要测试N是否为素数,首先将N-1分解为 2sd。在每次测试开始时,先随机选一个介于[1,N-1]的整数a,之后如果对所有的r∈[0,s-1],若ad mod N≠1且a2rd≠-1则N是合数。否则,N有3/4的概率为素数。

(摘自维基百科)

上面用新定理加强费马小定理的原理我本人并不是很理解,所以这里用一种自己想到的方法来解释(可能是错的,不要介意 ʅ(‾◡◝))。

ap-1 mod p=1 –>
ad*2r mod p=1 –>
(ad*2r-1)2 mod p=1 –>
(ad*2r-1 mod p)*(ad*2r-1 mod p)=1
所以(ad*2r-1 mod p)的结果只能是±1,其中-1等价于p-1。

如果最上面的式子成立,那么后面的式子都应该成立,并且可以重复其中的过程直到r=1,或者等式右边是p-1。如果右边是p-1,那么式子就不能继续分解下去,过程到此为止。

有人将上面利用加强费马小定理测试素性的过程叫做Miller测试。

通过上面的素性测试可以有效筛掉大部分伪素数。比如,基于原本的费马小定理,341是个最小的底为2的伪素数,而用加强费马小定理,最小的底为2的伪素数是2047,最小的底为2和3的伪素数则是1 373 653,可见效果是非常显著的。

完整的Miller-Rabin素数检测过程就是:进行相互独立的k轮测试,每轮在小于待测素数p的正整数中随机选取a的值,利用加强费马小定理进行Miller测试,通过所有测试的p就可以认为是素数,p被误判的概率是4-k。

有一些非常实用的现成结论可以在进行素数测试时降低算法运行时间:如果被测数小于4 759 123 141(47亿),那么只需要测试三个底数2, 7和61就足够了;如果每次都用前7个素数(2, 3, 5, 7, 11, 13和17)进行测试,所有不超过341 550 071 728 320(3百万亿)的数都是正确的;如果选用2, 3, 7, 61和24251作为底数,那么10^16内唯一的强伪素数为46 856 248 255 981(4.6*1013)。

下面是Miller-Rabin素数检测的流程图:

开始将p-1表示成d*2^r 选择底数a,素数测试论述s计算 a^(d*2^r) mod p结果等于1?r>0?s>1?r=r-1,s=s-1是素数结束结果等于p-1?不是素数yesnoyesnoyesnoyesno

变量s是控制测试轮数的,实时上没有必要将0~s之间所有的数都测一遍,就像上面所说,选择几个特定的数就足以覆盖大部分情况。

 

这篇关于Miller-Rabin素数检测算法笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/724981

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形