上一篇博客 大整数运算包的实现(Java)(1) --加、减、乘、除、模取余、模加(考虑负数),我们实现了基本的大数加、减、乘、除、取余。这篇博客将基于它们实现大数的快速幂取模、最大公约数、乘法逆元、素数判定以及大素数的生成。
一、快速幂取模
假如我们要计算 2100 mod 19,最简单的做法是做99次乘法再模上19。
但这样会有两个问题,1、一直做乘法会很消耗时间;2、数最终会变得很大而难以存储
所以我们会使用快速幂取模(类似二元法),这样我们算7次就可以了。
其中我们还会用到下面两个公式,这样我们得到的数就不至于非常大。
/**
* 快速幂取模
* @param one 底数
* @param two 指数
* @param mod 模
* @return 结果
*/
public static String Power(String one,String two,String mod) {
if(two.equals("0")) {
//0次幂结果为1
//System.out.println("Power result=1");
return "1";
}else if(two.equals("1")){
//1次幂结果为它本身
return Mod(one, mod);
}
String count=two,result="1",temp=one;
while(!count.equals("0")){
if(Mod(count, "2").equals("1")) //看它二进制最后一位是不是1
result=Multiply(result, temp, mod);
if(!count.equals("1")) //这里避免最后一次做没用的乘法
temp=Multiply(temp, temp, mod);
count=Division(count, "2"); //次数减1,相当于二进制右移一位
}
//System.out.println(result);
return result;
}
运行结果:
25 mod 7 = 4
210 mod 13 = 10
2100 mod 19 = 17
21000 mod 1777 = 1775
210000 mod 49999 = 100
2100000 mod 998111 = 802658
二、最大公约数(欧几里得算法)
求最大公约数可以使用欧几里得算法,又称辗转相除法。
现在求 52 和 36 的最大公约数:
当余数为 0 时,当前算式的除数就是最大公约数。
/**
* 最大公约数
* @param one
* @param two
* @return 结果
*/
public static String GCD(String one,String two) {
if(one.equals(two)) {
//相等则GCD=任意一个
//System.out.println("GCD="+one);
return one;
}
int length1=one.length();
int length2=two.length();
String first=null,second=null,temp=null;
if(length1>length2) {
//保证第一个数大于第二个,当然也可以不用这么做
first=one;
second=two;
}else if(length1<length2) {
first=two;
second=one;
}else {
for (int i = 0; i < length1; i+&