大整数运算包的实现(Java)(1) --加、减、乘、除、模取余、模加(考虑负数)

下一篇博客---->大整数运算包的实现(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);
		}
	}

猜你喜欢

转载自blog.csdn.net/H_X_P_/article/details/104108794
今日推荐