1 . 问题点: “ 有限时间 ”、“ 尽可能大”、“ 素数 ”
“素数“ :需要经过素性测试合格后的数字
“有限时间”:测试一个数字,可接受的时间内,并非无穷尽的依靠暴力求解
“尽可能大”:可检测数的上限
2 . 问题点求解
2 . 1 “ 素 数 ”
1) 概 念: 大于 1 的自然数中,除了 1 和它本身以外不再有其他因数的数称为质数,
素数有无限个。
2) 素性测试待测方法:
方法一: 根据定理检测 (真 素 数 测 试)
方法二: 改进版定理检测 (真 素 数 测 试)
方法三: 一般筛选法 (真 素 数 测 试)
方法四: 改进版筛选法 (真 素 数 测 试)
方法五: Miller Rabin 算法(概 率 素 数 测 试)
1) 待测方法介绍
· 根据定理检测
顾名思义,这种方法是根据概念进行试除计算,即:一个数字仅能被 1 和本身
整除。若存在其他数字可以整出此数字,则为合数,反之为素数(质数) 。
优点 : 易理解素数概念
缺点 : 每对一个数字进行素性测试,都需要从 2试除至待测数字的上一个数
字,效率低下。
· 改进版定理检测
根据概念,是否为素数,是判断存在数字能整除待测数字(1 和本身除外)。而一旦存在此数字,由于数字是成对出现,因此只需要判断数字对中最小的一个数字即可。得到:“ 任意一个数的最大质因数都小于或等于这个数的平方根 ”。因此,在对待测数字进行素性测试时,仅需要从 2 试除至待测数字的平方根即可,可以减少一些测试时间。
优点 : 能稍微减少一些测试时间
缺点 : 每对一个数字进行素性测试,都需要从 2试除至待测数字的平方根,效
率依然低下。
· 一般筛选法
我们知道,2 是素数,可以得出,2的倍数都是合数。我们还知道,3 是素数,可以得出,3 的倍数也都是合数。有:“ 素数的倍数都是合数 ”所以根据以上,我们可以通过几个初始的素数表,找到所有的合数,并将素数筛选出来。
优点 : 能大幅减少测试时间
缺点 : 依然对于很多数字进行重复筛选,影响效率。
· 改进筛选法
例如:需要找 100 之内的素数,对于 30 这个数字 :
30= 2 X 15
30 既是 2 的倍数,也是 15 的倍数,因此在一般的筛选法的过程中,30 在 2 的时候被筛选一次,在 15 的时候会被再次筛选一次。当数量级较大时,这种情况就会十分影响效率。所以,在改进的筛选方法中,这种情况应被避免,可以更大幅度的减少测试时间。
优点 : 继续大幅减少测试时间
缺点 : 存在内存泄漏风险。
· Miller-Rabin 算法
Miller-Rabin 算法是一种基于概率的素性测试算法,因此该算法与一般的基于事实的真素性测试方法的区别是:存在一定的误判率。但是在对于某个较大的待测数字进行多次测试的情况下,误判率可以控制在可忽略范围内。Miller-Rabin 算法基于 Fermat 算法,属于后者的变形、改进。首先引入 Fermat 定理:n是一个奇素数,a是任何整数(1≤ a≤n-1) ,则a^(n-1)≡1(mod n)根据此定理可以知道,对于给定的待测数字 n,可以通过设定素性测试算法,计算 w = a^(n-1)%n 的结果来判定。
W!=1,n一定不是素数;
W==1,n可能是素数;
再引入二次探测定理,如果 n 是一个整数,且 0
借助 Fermat 定理,进行如下测试:a^(m)%n、a^(2m)%n、a^(4m)%n、a^(m*(2^q))%n。进行这些测试的过程为:Miller-Rabin 测试。
误判率:若 n 是素数,a 是小于 n 的正整数,则 n 对以 a 为基的Miller 测试,结果为真。Miller 测试进行 k次,将合数当成素数处理的错误概率最多不会超过 4(-k)。
算法:输入:大于 3 的奇整数 n 和大于等于 1 的安全参数 t(测试几轮)返回:是否是素数
1 .把 n-1 表示为:2s * r
2 .对 i 从 i 到 t 做如下操作:
3 .选择一个随机整数 a(2<=a<=n-2)
4 .计算 y = a*r mod n
5 .如果 y≠1 并且 y ≠n-1 作下面的操作,否则转 3:
5.1 j←1;
5.2 当 j≤s-1 并且 y≠n-1 循环作下面操作,否则跳到 5.3;计算 y ←y2 mod n;如果 y=1 返回合数;否则 j←j+1;
5.3 返回素数
优点 : 对于大数能对其素性进行有效检测,广泛用于密码学等安全领域缺点 : 检测速度受限
2) 比 较
测试条件:
操作系统:Windows 10
处理器:Intel(R) Core(TM) i5-4460 CPU @3.20GHz 3.20 GHz 内存:4.00 GB
系统类型: 64 位操作系统运行模式: Debug 下
· 1 亿级检测时间对比(单位:秒(s),表 2-2-1)
根据定理检测 改进定理检测 一般筛选法 改进筛选法 Miller Rabin |
/ |
/ |
/ |
/ |
196.855 |
196.709 |
194.882 |
196.149 |
|
4.884 |
4.338 |
4.408 |
4.543 |
|
1.303 |
1.204 |
1.227 |
1.245 |
|
( 大数 ) |
( 大数 ) |
( 大数 ) |
( 大数 ) |
表 2-2-1
· 时 间 复 杂 度( 表 2-2-2 )
根据定理检测 改进定理检测 一般筛选法 改进筛选法 Miller Rabin |
O(n),随着问题规模上升急剧上升 |
O(√n),随着问题规模上升急剧上升 |
|
O(n),优化得当可达线性筛选 |
|
O(n),优化得当可达线性筛选 |
|
O(log32 (n)),最坏 |
表 2-2-2
2 . 3 “ 尽可能大 ”
· 数据类型(表 2-3-1)
int unsigned int long unsigned long long long unsigned long long __int64 unsigned __int64 |
-2147483648 |
2147483647 |
0 |
4294967295 |
|
-2147483648 |
2147483647 |
|
0 |
4294967295 |
|
-9223372036854775808 |
9223372036854775807 |
|
0 |
18446744073709551615 |
|
-9223372036854775808 |
9223372036854775807 |
|
0 |
18446744073709551615 |
表 2-3-1
根据表 2-3-1,常用数据类型的最大值为“18446744073709551615 ”,数据类型为unsigned long long或unsigned __int64,依然是有限的,虽然素数是无限的,但是目前常用的数据类型的范围跟素数的范围依然远远不在一个数量级。并且在大数的素性测试中,普通的测试方法依然是能力有限,因此针对相对比较大(10亿级别以上)的数字采用Miller-Rabin 算法,而相对较小的数字(10 亿级别以下)采用改进版的筛选法。
理论上,有限时间内,Prime 程序可输出的素数最大可以到 263 ~ 265之间。
· 算法
Prime程序的 Millmer-Rabin 算法在测试轮数的合理安排下,对一个大数素性测试,可以达到 99%左右的识别率, 因此认为是可靠的算法。
· 大数
素性测试虽然没有问题,但是在“大数”的生成方面依然受限于数据类型。假设存在:int a[2017],而 a[0]可以存储的数字最大为 2147483647。同理,a[1]至 a[2016]每个数组元素存储的最大数字为 2147483647。那么,数字“1102147483647”可以被写成“a[1] 合并 a[0]”即: a[1] = 110 , a[0] = 2147483647根据以上,则 a[2017]可以合并存储的数字最大为“ 231 次方的 2017 次方 ”。因此,大数生成方式以及自定义大数运算与素性测试结合是程序需要改进的部分。
注意:需要目标机处于 64 位 Windows 系统下。
参 考
[1]曽加:如何编程最快速度求出两百万以内素数个数(不限语言和算法)?[DB/0L].
ZhiHu,2014[2017].https://www.zhihu.com/question/24942373
[2]LCCN:sh85093218,GND:4047263-2,NDL:00571462: Prime
number[G/OL].Wikipedia,2017[2017]. https://en.wikipedia.org/wiki/Prime_number[3]Unknown author : Miller-Rabinprimality test.Wikipedia,2016[2017].
https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
[4]nash_:素性测试[DB/OL].CSDN,2013[2017].
http://blog.csdn.net/zmazon/article/details/8290774