对于给定的一个数n,如何判断其是否是素数呢?
最简单最直观的方法是试除法(下面的算法1、2、3),还有一种方法是Rabin-Miller算法。
- From 2 To n
- 思路:从2到n-1,做取模运算n mod ( i ),若运算结果均为 0 ,则 n 为素数
- 实现:
public boolean isPrimeNumber(int n){ for(int i = 2;i < n; i++){ if(n%i==0) return false; } return true; }
- From 2 To n½
- 思路:对上一个方法的优化,只要循环到 n½ 就足以判断了
- 实现:
public boolean isPrimeNumber(int n){ int target = (int)Math.sqrt(n); for(int i= 2;i<target;i++) if(target%i==0) return false; return true; }
- 思路:对上一个方法的优化,只要循环到 n½ 就足以判断了
- From Prime[min] To Prime[max]
- 思路:将 n½ 之前的所有素数存到数组,在该素数数组内循环
- 实现:
class Solution{ int[] Prime = new int[Integer.MAX]; Prime[0] = 2; count = 1; //与其说是检测是否为素数,本程序其实是从头开始建立素数数组,无法做到针对单一数字的离散判断,而且对于大数而言,空间代价较大 public static boolean isPrime(int n){ int target = (int)Math.sqrt(n); for(int i = 0;i<count;i++) if(target%Prime[i]==0) return false; return true; } }
- Rabin-Miller算法
- 思路:判断 n 是否为素数,首先要确保 n 是奇数。另外已知奇数总能写成 n = (2^r)*s+1,其中 s 也是奇数。Rabin-Miller算法是一种概率素数检测算法,该算法认为:只要奇数 n 能够满足①或者②(通过Rabin-Miller测试),那么他就是一个素数。【但事实是,有些合数也能通过Rabin-Miller测试,所以在实践时,往往会多做几次测试,也就是换个 a 多做几次①和②,如果每次都能通过测试,那么就说 n 是个素数,且正确率极高】
- 验算①:取随机整数 a ,a的取值范围是[1,n-1],a^s = 1 mod n
- 验算②:取随机整数 a ,a^s((2^j)*s) = -1 mod n ,其中0≤j<R.
- 实现:(未验证)
//n是待测数字,s设定Rabin-Miller测试次数 public boolean isPrime(int n, int s){ for(int i=0;i<s;i++){ int a = rand()*(n-2)/RAND_MAX+1; //只要有一次没有通过Rabin-Miller测试,那么 n 就不是素数 if(RabinMiller(a,n)) return false; } return true; } //一次Rabin-Miller测试实现 public boolean RabinMiller(int a,int n){ long i,d=1,x; for(i = (int)Math.ceil(Math.log((double)n-1)/Math.log(2.0))-1; i>=0; i--){ x = d; d = (d*d)%n; if( 1==d && x!=1 && x!=n-1) return true; if((n-1)&(1<0)) d = (d*a)%n; } return d!=1; }
- 思路:判断 n 是否为素数,首先要确保 n 是奇数。另外已知奇数总能写成 n = (2^r)*s+1,其中 s 也是奇数。Rabin-Miller算法是一种概率素数检测算法,该算法认为:只要奇数 n 能够满足①或者②(通过Rabin-Miller测试),那么他就是一个素数。【但事实是,有些合数也能通过Rabin-Miller测试,所以在实践时,往往会多做几次测试,也就是换个 a 多做几次①和②,如果每次都能通过测试,那么就说 n 是个素数,且正确率极高】