java生成大素数_用BigInteger实现大素数生成算法

一.通过素数的基本性质

根据素数的性质(除了1和此整数(n)自身外,无法被其他自然数整除的数):即从2到n/2的数都不能整除n。

1 public static booleanisPrime(BigInteger num)2 {3 BigInteger two = BigInteger.valueOf(2);4 for(BigInteger i = two; !(i.compareTo(num.divide(two)) == 1); i =i.add(BigInteger.ONE))5 {6 if(num.remainder(i) == BigInteger.ZERO)7 {8 return false;9 }10 }11

12 return true;13 }

用大于2^63的数去测试,结果因为运算量太大,运行半个来小时也没有结果出现。

二.通过素数表

要提高速度就要减少进入判断方法中的循环:

1.偶数可以排除

2.大的合数(即素数的积)可以排除

排除偶数直接增加一个判断即可实现,而排除大的合数也通过产生一个素数表实现。

这里引援51CTO网友 梦朝思夕的BOLG,即“一般来说整除100以内的所有素数可排除76%不是素数的可能性整除256以内的所有素数可排除80%不是素数的可能性。” 而我同样地建大小为2000的表,private static BigInteger[] primeList = new BigInteger[2000]

primeList[1999] = 17389

for(int i = 0, j = 2; i < 2000; j++)

{if(isPrime(j))

{

primeList[i]=BigInteger.valueOf(j);

i++;

}

}

再来一个方法判断新生成的大数判断是否为几个素数的积

public static booleanisNotPrimeProduct(BigInteger num)

{for(int i=0;i< 2000; i++)

{if(num.remainder(primeList[i]) ==BigInteger.ZERO)

{return false;

}

}return true;

}

素数表太大也减慢速度,而且数值越大,素数表判别的确定性就越小。要知道,我们要的是2^63。

三.通过费马(Fermat)素数检验

在网上查阅资料,知道可以运用费马小定理检验一个数是否不是合数。

费马小定理是数论中的一个定理:假如a是一个整数,p是一个质数,那么10af6afd443321d1cc585338757ec2bd.png

如果a不是p的倍数,这个定理也可以写成

0800f88a4296d70f613b08e7c7da2c65.png

根据费马小定理:如果p是素数,

85b4cc25d04fac6e1efbb7e1ae4544a5.png,那么0800f88a4296d70f613b08e7c7da2c65.png

如果我们想知道n是否是素数,我们在中间选取a,看看上面等式是否成立。如果对于数值a等式不成立,那么n是合数。如果有很多的a能够使等式成立,那么我们可以说n 可能是素数,或者伪素数。

在我们检验过程中,有可能我们选取的a都能让等式成立,然而n却是合数。这时等式

8720e7621f1234f7872f317e4ed314bc.png

被称为Fermat liar。如果我们选取满足下面等式的a

3e0dc7b84768b4da754ef6a4e75314db.png

那么a也就是对于n的合数判定的Fermat witness。

而在这里我从cnblogs的Knuth_档案学到了大量理论知识和算法的实现。(特别是蒙哥马利快速积模算法:计算大数(x^y)%z)

用java实现如下

public staticBigInteger Montgomery(BigInteger n, BigInteger p, BigInteger m)

{

n=n.remainder(m) ;

BigInteger k=BigInteger.ONE;while(p.compareTo(BigInteger.ONE) == 0)

{if(!(p.remainder(BigInteger.ONE) ==BigInteger.ZERO))

{

k=(k.multiply(n)).remainder(m);

}

n=(n.multiply(n)).remainder(m);

p= p.divide(BigInteger.valueOf(2));

}return(n.multiply(k)).remainder(m);

}

接下来,我们就可以对一个大数使用费马素数检验可以判定这个大数是伪素数。

从前2000素数一一检验,而费马素数检验只是随机化了。

public static booleanfermatPrimalityTest(BigInteger num)

{for(int i = 0; i < 2000; i++)

{if(!(Montgomery(primeList[i], num.subtract(BigInteger.ONE), num).compareTo(BigInteger.ONE) == 1)) //(x^y)%z

{return false;

}

}return true;

}

使用素数表的前十个结果:

9223372036854775809

9223372036854775811

9223372036854775813

9223372036854775815

9223372036854775817

9223372036854775819

9223372036854775821

9223372036854775823

9223372036854775825

9223372036854775827

使用费马素数检验过的前十个结果:

9223372036854775817

9223372036854775837

9223372036854775889

9223372036854775903

9223372036854775907

9223372036854775931

9223372036854775937

9223372036854775939

9223372036854775949

9223372036854775963

四.总结

现在我们可以通过结果简单的分析出出只是使用素数表的结果有很多都通不过费马素数检验,因为素数表总有上界。最后可以通过Knuth所说的 拉宾米勒测试排除掉那些卡尔麦克(Carmichael)数。

最后再次感谢 梦朝思夕和 Knuth 两位技术前辈,可以说我在这里只是把他们的心得进一步总结。权当笔记。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值