Miller-Rabin素性测试(POJ3641)

一.概念引入

        在以往判断一个数n是不是素数时,我们都是采用i从2到sqrt(n)能否整除n.如果能整除,则n是合数;否则是素数.但是该算法的时间复杂度为O(sqrt(n)),当n较大时,时间性能很差,特别是在网络安全和密码学上一般都是需要很大的素数.而从目前来看,确定性算法判断素数的性能都不好,所以可以用MC(蒙特卡洛)概率算法来解决,其中Miller Rabin算法就是其中的很经典的解决方法.下面首先介绍下相关的数学理论。

        理论基础:Fermat小定理:若n是素数,则对所有1≤a≤n-1的整数a,有a^(n-1)mod n=1;该定理的逆否命题也成立,即a^(n-1)mod n!=1,则n为合数。但是如果n是素数,就不一定成立了,比如当a=4,n=15时,4^14mod15=1,但是4不是素数而是合数。

        不过,从大量数据统计来看,如果满足a^(n-1)mod n=1,则n较大概率为素数。那么,我们把那些使得n原本为合数而被看成素数的a叫做伪证据,n为伪素数。同样从大量数据看出有些伪素数n有很多伪证据a,比如当n=561,a有318个可使得结果判为素数。所以,读者可以去查查强伪素数的概念。

二.POJ3641

  判断p是否是基于a的伪素数。

import java.util.Random;
import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        
        int p,a;
        Scanner sc = new Scanner(System.in);
        while(true) {
            p = sc.nextInt();
            a = sc.nextInt();
            if(p==0&&a==0) {
                break;
            }
            boolean flag1 = fermat(a,p-1,p);
            boolean flag2 = millerRabin(p);
            //System.out.println(flag1+" "+flag2);
            if(flag2) {//如果是素数,那肯定不是伪素数
                System.out.println("no");
            }else {
                if(flag1) {
                    System.out.println("yes");
                }else {
                    System.out.println("no");
                }
            }
        }
    }

    private static boolean millerRabin(int p) {//进行20次
        
        boolean flag = p==1 || (p!=2&&(p%2)==0) || (p!=3&&(p%3)==0) || (p!=5&&(p%5)==0) || (p!=7&&(p%7)==0);
        if(flag) {
            return false;//表示合数
        }
        int times = 20;
        Random r = new Random();
        for(int i=0; i<times; i++) {
            if(fermat(r.nextInt(p-1)+1,p-1,p)==false) 
                return false;
        }
        return true;
    }

    private static boolean fermat(int a, int b, int n) {

        //a^(p-1)modp=1
        int ans = 1;
        for(int i=0; i<b; i++) {
            ans = ans*a%n;
        }
        return ans==1;
        /*
         * 或者
         * while(b>0) {
             if(b&1) {
                 ans=ans*a%n;
             }
             b>>=1;
             a=a*a%n;
         * }
         */
    }
}
posted @ 2013-07-28 14:29  加拿大小哥哥  阅读(2083)  评论(0编辑  收藏  举报