下一篇博客---->大整数运算包的实现(Java)(2) --快速幂取模、最大公约数、乘法逆元、素数判定、生成大素数
/**
* 大数加法
* @param one 加数
* @param two 加数
* @return 结果
*/
public static String Add(String one,String two) {
if(one.equals("0")) //加数中的其中一个为0则直接返回另一个
return two;
if(two.equals("0"))
return one;
int length1=one.length(); //获取长度
int length2=two.length();
char[] Long=null,Short=null;
int i,max=0,min=0,carry=0,num1,num2,front1=0,front2=0,isNegative1=0,isNegative2=0,oneLong=0;
if(one.charAt(0)=='-') { //第一个数是负数
isNegative1=1; //标记
front1++; //前驱,去掉负号
length1--; //长度减1
}
if(two.charAt(0)=='-') {
isNegative2=1;
front2++;
length2--;
}
if(length1>length2) { //将数值大的数放到Long[],数值小的数放到Short[],方便操作
max=one.length(); //指向数值大的数的最低位
min=two.length(); //指向数值小的数的最低位
Long=one.toCharArray();
Short=two.toCharArray();
oneLong=1; //第一个数大
}
else if(length1<length2){
max=two.length();
min=one.length();
Long=two.toCharArray();
Short=one.toCharArray();
}
else { //数值长度相等
int j,k;
for(j=front1,k=front2;j<one.length();j++,k++) {
if(one.charAt(j)>two.charAt(k)) { //第一个数大
max=one.length();
min=two.length();
Long=one.toCharArray();
Short=two.toCharArray();
oneLong=1;
break;
}else if(one.charAt(j)<two.charAt(k)){
max=two.length();
min=one.length();
Long=two.toCharArray();
Short=one.toCharArray();
break;
}
}
if(j==one.length()) { //两个数的数值相等
if(isNegative1==isNegative2) { //符号相等
max=one.length();
min=two.length();
Long=one.toCharArray();
Short=two.toCharArray();
}else { //两个数的数值相等,符号不同,正数+负数=0
//System.out.println("Add result=0");
return "0";
}
}
}
int[] result=new int[length1>length2?length1+1:length2+1]; //可能有进位
String number="";
if(isNegative1==isNegative2) { //符号相等,无论是正数+正数还是负数+负数,都是数值相加再加符号
for(i=0;min>front1;i++) { //front1=front2
num1=Long[--max]-48;
num2=Short[--min]-48;
result[i]=(num1+num2+carry)%10;
carry=(num1+num2+carry)/10;
}
while (max>front1) { //剩下的继续加
num1=Long[--max]-48;
result[i++]=(num1+carry)%10;
carry=(num1+carry)/10;
}
if(carry==1) //最高位有进位
result[i]=1;
if(isNegative1==1) //负数
number+='-';
if(result[i]!=0)
number+=String.valueOf(result[i--]);
else
i--; //如果首位是0则跳过
for(;i>=0;i--) //转化为字符串
number+=String.valueOf(result[i]);
}else { //符号不同,正数数值大结果为正数,负数数值大结果为负数
if(oneLong==1) {
length1=front2;
length2=front1;
if(isNegative1==1)
number+="-";
}else {
length1=front1;
length2=front2;
if(isNegative2==1)
number+="-";
}
for(i=0;min>length1;i++) { //减法
num1=Long[--max]-48;
num2=Short[--min]-48;
result[i]=(num1-num2+10+carry)%10;
if(num1-num2+carry<0)
carry=-1;
else
carry=0;
}
while(max>length2) { //多余的继续减
num1=Long[--max]-48;
result[i++]=(num1+10+carry)%10;
if(num1+carry<0)
carry=-1;
else
carry=0;
}
while(i>0&&result[--i]==0); //如果是0则跳过
for(;i>=0;i--)
number+=String.valueOf(result[i]);
}
//System.out.println("Add result="+number);
return number;
}
/**
* 大数减法
* @param one 被减数
* @param two 减数
* @return 结果
*/
public static String Subtract(String one,String two) {
if(one.equals(two)) { //两个数的数值和符号均相同,结果为0
//System.out.println("Sub result=0");
return "0";
}
if(two.equals("0"))
return one;
int length1=one.length();
int length2=two.length();
char[] Big=null,Small=null;
int i=0,num1,num2,carry=0,front1=0,front2=0,isNegative1=0,isNegative2=0,min=0,max=0,oneLong=0;
if(one.charAt(0)=='-') { //第一个数是负数
isNegative1=1;
front1++; //前驱
length1--; //长度减1
}
if(two.charAt(0)=='-') {
isNegative2=1;
front2++;
length2--;
}
if(length1>length2) { //保证第一个数大于第二个数,如果是负数只是符号不同,数值还是一样的
max=one.length();
min=two.length();
Big=one.toCharArray();
Small=two.toCharArray();
oneLong=1;
}else if(length1<length2) {
max=two.length();
min=one.length();
Big=two.toCharArray();
Small=one.toCharArray();
}else { //长度相等
int j,k;
for(j=front1,k=front2;j<one.length();j++,k++) {
if(one.charAt(j)>two.charAt(k)) {
max=one.length();
min=two.length();
Big=one.toCharArray();
Small=two.toCharArray();
oneLong=1;
break;
}else if(one.charAt(j)<two.charAt(k)){
max=two.length();
min=one.length();
Big=two.toCharArray();
Small=one.toCharArray();
break;
}
}
if(j==one.length()) { //数值相同,符号不同
max=one.length();
min=two.length();
Big=one.toCharArray();
Small=two.toCharArray();
oneLong=1;
}
}
String number="";
int[] result=new int[max+1];
if(isNegative1==isNegative2) { //符号相同
for(i=0;min>front2;i++) { //front1==front2
num1=Big[--max]-48;
num2=Small[--min]-48;
result[i]=(num1-num2+10+carry)%10;
if(num1-num2+carry<0)
carry=-1;
else
carry=0;
}
while(max>front1) { //多余的继续减
num1=Big[--max]-48;
result[i++]=(num1+10+carry)%10;
if(num1+carry<0)
carry=-1;
else
carry=0;
}
while(i>0&&result[--i]==0); //如果是0则跳过
if((isNegative1==0&&oneLong!=1)||(isNegative1==1&&oneLong==1))
number+="-"; //正减正,第一个小 或 负减负,第一个大
for(;i>=0;i--)
number+=String.valueOf(result[i]);
}else { //符号不同
if(oneLong==1) {
length1=front2;
length2=front1;
}else {
length1=front1;
length2=front2;
}
for(i=0;min>length1;i++) { //加法
num1=Big[--max]-48;
num2=Small[--min]-48;
result[i]=(num1+num2+carry)%10;
carry=(num1+num2+carry)/10;
}
while (max>length2) { //剩下的继续加
num1=Big[--max]-48;
result[i++]=(num1+carry)%10;
carry=(num1+carry)/10;
}
if(carry==1) //最高位有进位
result[i]=1;
if(isNegative1==1) //正-负=正,负-正=负
number+='-';
if(result[i]!=0)
number+=String.valueOf(result[i--]);
else
i--; //如果首位是0则跳过
for(;i>=0;i--) //转化为字符串
number+=String.valueOf(result[i]);
}
//System.out.println("Sub result="+number);
return number;
}
/**
* 大数乘法
* @param one 乘数
* @param two 乘数
* @return 结果
*/
public static String Multiply(String one,String two) {
if(one.equals("0")||two.equals("0")) //有一个是0,结果是0
return "0";
int length1=one.length();
int length2=two.length();
char[] One=one.toCharArray();
char[] Two=two.toCharArray();
int isNegative=0,front1=0,front2=0;
if(One[front1]=='-') { //一个数是负数,结果为负数;两个数都是负数,结果为正数
isNegative^=1;
front1++;
}
if(Two[front2]=='-') {
isNegative^=1;
front2++;
}
int i,j,k=0,carry,num1,num2,temp,carry1;
int[] result=new int[length1+length2]; //结果的长度最长是两个数的长度之和
for (i = length1-1; i >= front1; i--) { //最多执行乘数的长度次
num1=One[i]-48;
k=length1-i-1; //每乘完一次,乘数向左移一位
carry=0;
for (j = length2-1; j >= front2; j--,k++) {
num2=Two[j]-48;
temp=(num1*num2+carry)%10;
carry1=(result[k]+temp)/10;
result[k]=(result[k]+temp)%10;
carry=(num1*num2+carry)/10+carry1; //相乘产生的进位和之后相加产生的进位
}
if(carry!=0) //有进位
result[k]=carry;
}
String number="";
if(isNegative==1)
number+='-';
if(result[k]!=0) //如果首位是0则跳过
number+=String.valueOf(result[k--]);
else
k--;
for(;k>=0;k--)
number+=String.valueOf(result[k]);
//System.out.println("Multiply result="+number);
return number;
}
每一轮做减法,最终减法的次数就是商,被除数最终剩下的就是余数。所以大数除法和大数取模的做法相差不大。
大数除法示意图如下:
/**
* 大数除法
* @param one 被除数
* @param two 除数
* @return 结果
*/
public static String Division(String one,String two) {
if(one.equals("0")) //被除数为0,结果为0
return "0";
if(one.equals(two)) { //两个数的数值相等,符号也相等,商为1,余数为0
//System.out.println("Division result=1");
return "1";
}
int length1=one.length(); //被除数长度
int length2=two.length(); //除数长度
int isNegative=0,front1=0,front2=0;
if(one.charAt(0)=='-') {
isNegative^=1;
length1--;
front1++;
}
if(two.charAt(0)=='-') {
isNegative^=1;
length2--;
front2++;
}
char[] Big=null,Small=null;
int difference=0; //两个数相差的位数,循环difference+1次
if(length1<length2) { //被除数小于除数,商为0,余数为被除数
//System.out.println("Division result=0");
return "0";
}else if(length1>length2) { //被除数大于除数
Big=one.toCharArray();
Small=two.toCharArray();
difference=length1-length2;
}else {
for(int i=front1,j=front2;length1!=0;i++,j++,length1--) {
if(one.charAt(i)>two.charAt(j)) { //被除数大于除数
Big=one.toCharArray();
Small=two.toCharArray();
difference=0;
break;
}else if(one.charAt(i)<two.charAt(j)) { //被除数小于除数,商为0,余数为被除数
//System.out.println("Division result=0");
return "0";
}
}
if(length1==0) { //两个数的数值相等,但符号不同
//System.out.println("Division result=-1");
return "-1";
}
length1=length2;
}
//转化为整型数组
int[] Long=new int[length1];
int[] Short=new int[length2];
for(int i=0,j=front1;i<length1;i++,j++)
Long[i]=Big[j]-48;
for(int i=0,j=front2;i<length2;i++,j++)
Short[i]=Small[j]-48;
int[] result=new int[length1];
int front=0,back,length=0,flag,carry,num,point=0;
//front和back确定每轮的被除数,front确定被除数第一位,back确定被除数最后一位
//flag是是否可以做减法的标记
for(back=length1-difference-1;back<length1;back++,point++) { //循环difference+1次
while(front<=back&&Long[front]==0){ //front不能超过back,如果front指着的是0则后移
front++;
length=back-front+1; //长度+1
}
length=back-front+1; //被除数长度
flag=0;
if(length==length2) { //被除数和除数长度相等,判断被除数是否够减
for(int i=front,j=0;i<=back;i++,j++) {
if(Long[i]<Short[j]) { //被除数小于除数,不能做减法
flag=1;
break;
}else if(Long[i]>Short[j])
break;
}
if (flag==1)
continue;
}else if(length<length2) //被除数长度小于除数,不能做减法
continue;
while(flag==0) { //允许做减法
result[point]++; //记录商
int temp=0;
carry=0; //进位
for(int i=back,j=length2-1;j>=0;i--,j--) { //减法
temp=i;
num=Long[i];
Long[i]=(num-Short[j]+10+carry)%10;
if(num-Short[j]+carry<0)
carry=-1;
else
carry=0;
}
while(temp!=front) { //多出来的继续减
num=Long[--temp];
Long[temp]=(num+10+carry)%10;
if(num+carry<0)
carry=-1;
else
carry=0;
}
while(front<=back&&Long[front]==0){ //front不能超过back,如果front指着的是0则后移
front++;
length=back-front+1;
}
if(length==length2) {
for(int i=front,j=0;i<=back;i++,j++) {
if(Long[i]<Short[j]) {
flag=1;
break;
}else if(Long[i]>Short[j]) //继续做减法
break;
}
}else if(length<length2)
flag=1;
}
}
String number="";
if(isNegative==1)
number+='-';
int i=0;
while(result[i++]==0);
for(i--;i<point;i++)
number+=String.valueOf(result[i]);
//System.out.println("divide result="+number);
return number;
}
/**
* 大数取模
* @param one 数
* @param mod 模
* @return 结果
*/
public static String Mod(String one,String mod) {
if(one.equals("0")) {
//System.out.println("Mod result=0");
return one;
}
if(one.equals(mod)) { //两个数相等,商为1,余数为0
//System.out.println("Mod result=0");
return "0";
}
int length1=one.length(); //被除数长度
int length2=mod.length(); //除数长度
char[] Big=null,Small=null;
int difference=0,front1=0,front2=0,isNegative1=0; //两个数相差的位数,循环difference+1次
if(one.charAt(0)=='-') { //第一个数是负数
isNegative1=1;
front1++; //前驱
length1--; //长度减1
}
if(mod.charAt(0)=='-') {
front2++;
length2--;
}
if(length1<length2) { //被除数小于除数,商为0,余数为被除数
//System.out.println("Mod result="+one);
return one;
}else if(length1>length2) { //被除数大于除数
Big=one.toCharArray();
Small=mod.toCharArray();
difference=length1-length2;
}else {
for(int i=0;i<length1;i++) {
if(one.charAt(i)>mod.charAt(i)) { //被除数小于除数,商为0,余数为被除数
Big=one.toCharArray();
Small=mod.toCharArray();
difference=0;
break;
}else if(one.charAt(i)<mod.charAt(i)) { //被除数小于除数,商为0,余数为被除数
//System.out.println("Mod result="+one);
return one;
}
}
}
//转化为整型数组
int[] Long=new int[length1];
int[] Short=new int[length2];
for(int i=front1;i<length1;i++)
Long[i]=Big[i]-48;
for(int i=front2;i<length2;i++)
Short[i]=Small[i]-48;
int front=0,back,length=0,flag,carry,num;
//front和back确定每轮的被除数,front确定被除数第一位,back确定被除数最后一位
//flag是是否可以做减法的标记
for(back=length1-difference-1;back<length1;back++) { //循环difference+1次
while(front<=back&&Long[front]==0){ //front不能超过back,如果front指着的是0则后移
front++;
length=back-front+1; //长度+1
}
length=back-front+1; //被除数长度
flag=0;
if(length==length2) { //被除数和除数长度相等,判断被除数是否够减
for(int i=front,j=0;i<=back;i++,j++) {
if(Long[i]<Short[j]) { //被除数小于除数,不能做减法
flag=1;
break;
}else if(Long[i]>Short[j])
break;
}
if (flag==1)
continue;
}else if(length<length2) //被除数长度小于除数,不能做减法
continue;
while(flag==0) { //允许做减法
int temp=0;
carry=0; //进位
for(int i=back,j=length2-1;j>=0;i--,j--) { //减法
temp=i;
num=Long[i];
Long[i]=(num-Short[j]+10+carry)%10;
if(num-Short[j]+carry<0)
carry=-1;
else
carry=0;
}
while(temp!=front) { //多出来的继续减
num=Long[--temp];
Long[temp]=(num+10+carry)%10;
if(num+carry<0)
carry=-1;
else
carry=0;
}
while(front<=back&&Long[front]==0){ //front不能超过back,如果front指着的是0则后移
front++;
length=back-front+1;
}
if(length==length2) {
for(int i=front,j=0;i<=back;i++,j++) {
if(Long[i]<Short[j]) {
flag=1;
break;
}else if(Long[i]>Short[j]) //继续做减法
break;
}
}else if(length<length2)
flag=1;
}
}
if(length==0) { //余数为0,说明除数整除被除数
//System.out.println("Mod result=0");
return "0";
}
else {
back--;
String number="";
if(isNegative1==1)
number+='-';
for(int i=front;i<=back;i++)
number+=String.valueOf(Long[i]); //被除数最终就是余数
//System.out.println("Mod result="+number);
return number;
}
}
有了大数取模我们就可以进行模加、模减、模乘、模除。由于这四个运算的做法相差不大,这里只给出模加的做法。
/**
* 大数模加
* @param one 加数
* @param two 加数
* @param mod 模
* @return 结果
*/
public static String Add(String one,String two,String mod) {
String number=Add(one, two);
if(number.charAt(0)!='-')
return Mod(number, mod);
else {
String result="";
for(int i=1;i<number.length();i++)
result+=number.charAt(i);
result=Mod(result, mod);
if(result.equals("0"))
return "0";
return Subtract(mod, result);
}
}