浅析大整数运算

        众所周知,所有的编程语言中,每一种基本数据类型都有范围,就拿整数来说,int型的数据能表示的范围是有限的,但有时我们可能进行很大的整型数据的运算。当然,有人会说,有long int 呀?是的,但long int 能表示的数据仍然是有限的。我们要进行一万位的整型的加、减、乘、除的运算怎么办?此时我们就需要考虑如何实现大整型数据的运算。

        要解决这个问题,就必须考虑别的思路或方法,最普遍的做法就是采用数组存储每一位的数据,这样,即使再大的整型也能进行运算。

整体思路:

1)将一个数字字符串(用字符串接收输入的数据)每一位分割存入整型数组中。

一、加法运算:

   加法运算就像小学学加法运算时的方法。例如有两个整型数组NumA[3] = { 1,3,9},NumB[3] = { 4,7, 2},保存结果的Result[6];记录中间结果的整型变量Temp。

  A.先让个位运算:

      1       3           9

      4       7           2

                                

              1[进位]  1[本位]

int low = 0;   //记录低位的进位数字

Temp = NumA[2] + NumB[2];

if(Temp >= 10) //有进位

{

   Result[5] = Temp % 10 + low;

   Result[4]  += Temp / 10;

}

B.然后让十位运算,原理和个位运算一样。依次加完所有的数即可完成加法运算。

二、减法运算:

       减法运算和加法类似,只不过一个是加,一个是减,一个是进位,另一个是借位。

三、乘法运算:

      乘法运算稍微复杂一些。但原理和加法类似,只不过是多加法运算的组合。

就拿上面的书来说:

                                  1                      3                         9

                                  4                      7                        2

                                                                                                       

                                   2               6+1(低位进的数)     8[本位]

                    7+2    1+6                   3

  4+1          2+3        6

  6               5             6                  0                             8

用被乘数的个位与乘数的每一位相乘。

int MidResult[5]; //保存中间计算结果

int low  = 0; //低位的进位

MidResult[4] = NumA[2] * NumB[2] % 10 + low;

low = NumA[2]  / NumB[2];

MidResult[3] = NumA[1] * NumB[2] % 10 + low;

依次计算,得到中间结果MidResult;

low = 0;

Result[4] = (Result[4] +MidResult[4] + low) % 10;

low = Result[4] / 10;

Result[3] = (Result[3] + MidResult[4] + low)% 10;

....

上面是NumB个位计算结果,若是十位,则 Result从Reslut[3]与 MidResult[4]加起。

依次计算就可以得到结果。

四、除法:

这和小学学的除法运算也是一样的。

                       1    1   3                                 

    9       [   1   0    2   4

                       1   2

                             9

                             3  4

                             2  7

                                 7

正如上面的运算一样,采用从0 - 9 依次在每一位试,直到有10  - 1[试]*9 的值 >= 0;则改位商 1,依次计算。

具体的代码如下:

/**
 * @计算超大整型
 */
public class LargeInteger {
	
	String FirstNumStr;   //第一个数的字符串
	
	LargeInteger(String var){  //构造方法(给第一个数字符串赋值)
		this.FirstNumStr = var;
	}
	/**
	 * 加方法
	 * @param SecondNumStr 被加数
	 * @return 相加的结果
	 */
	public String add(String SecondNumStr){ //加方法
		
		int LengthA = FirstNumStr.length(); //求出第一个数字符串长度
		int LengthB = SecondNumStr.length();//求出第二个数字符串长度
		
		boolean IsMinus = false; //是否带负号
		if((FirstNumStr.charAt(0) == '-') && (SecondNumStr.charAt(0) == '-')){//都带负号
			IsMinus = !IsMinus;
		}else if(FirstNumStr.charAt(0) == '-'){ //第一个数带负号
			FirstNumStr = FirstNumStr.substring(1);
			String second = FirstNumStr;
			FirstNumStr = SecondNumStr;
			return  subtract(second);
		}else if(SecondNumStr.charAt(0) == '-'){ //第二个数带负号
			SecondNumStr = SecondNumStr.substring(1);
			return subtract(SecondNumStr);
		}
		
		int MaxLength = LengthA >= LengthB?LengthA:LengthB; //求出最大的长度
		MaxLength += 1; //加1是为了给可能的进位留出一位
		
		int []FirstNum = new int[MaxLength];  //定义第一个数整型数组
		int []SecondNum = new int[MaxLength]; //定义第二个数整型数组
			
		int []Result = new int[MaxLength];    //定义存放结果数组
		int MidResult = 0;  //中间结果
        int num = 0;    //记录将字符转为整型的数
	    for(int i = LengthA-1,j = MaxLength-1; i >= 0; i--,j--){ //将第一个数字符串转为整型数组
	    	switch(FirstNumStr.charAt(i)){
	    	case '0':num = 0;break;
	    	case '1':num = 1;break;
	    	case '2':num = 2;break;
	    	case '3':num = 3;break;
	    	case '4':num = 4;break;
	    	case '5':num = 5;break;
	    	case '6':num = 6;break;
	    	case '7':num = 7;break;
	    	case '8':num = 8;break;
	    	case '9':num = 9;break;
	    	default:num = 0;break;
	    	}
	    	FirstNum[j] = num;
	    }
	    num = 0;
	    for(int i = LengthB-1,j = MaxLength-1; i >= 0; i--,j--){//将第二个数字符串转为整型数组
	    	switch(SecondNumStr.charAt(i)){
	    	case '0':num = 0;break;
	    	case '1':num = 1;break;
	    	case '2':num = 2;break;
	    	case '3':num = 3;break;
	    	case '4':num = 4;break;
	    	case '5':num = 5;break;
	    	case '6':num = 6;break;
	    	case '7':num = 7;break;
	    	case '8':num = 8;break;
	    	case '9':num = 9;break;
	    	default:num = 0;break;
	    	}
	    	SecondNum[j] = num;
	    }
	    
	   
		for(int i = MaxLength-1; i >= 0; i--){       //从个位开始加
			MidResult = FirstNum[i] + SecondNum[i];  //记录两数相加的中间结果
			if(MidResult >= 10){    //进位
				Result[i] = MidResult % 10;  //本位的数
				FirstNum[i-1] = FirstNum[i-1] + 1; //进位
			}else{
				Result[i] = MidResult; //没有进位直接赋值
			}
		}
		
		String ResultStr = "";
		if(IsMinus){        //
			ResultStr = "-";
		}
	
		boolean flag = false;
		for(int j = 0 ; j < MaxLength; j++){ //将整型数组转为字符串
			if(Result[j] != 0){	//数组前面有0不赋值给字符串		    
			    flag = true;
			}
			if(flag){
				ResultStr += Result[j];
			}
		}

		return ResultStr;
	}
	/**
	 * 减方法
	 * @param SecondNumStr
	 * @return 相减的结果
	 */
	public String subtract(String SecondNumStr){
		
		int LengthA = FirstNumStr.length(); //求出第一个数字符串长度
		int LengthB = SecondNumStr.length();//求出第二个数字符串长度
		
		if((FirstNumStr.charAt(0) == '-') && (SecondNumStr.charAt(0) == '-')){
			String second = FirstNumStr;
			FirstNumStr = SecondNumStr.substring(1);
			return add(second);
			
		}else if(FirstNumStr.charAt(0) == '-'){
			SecondNumStr = "-"+SecondNumStr;
			return  add(SecondNumStr);
		}else if(SecondNumStr.charAt(0) == '-'){
			SecondNumStr = SecondNumStr.substring(1);
			return add(SecondNumStr);
		}
		
		int MaxLength = LengthA >= LengthB?LengthA:LengthB; //求出最大的长度
		
		int []FirstNum = new int[MaxLength];  //定义第一个数整型数组
		int []SecondNum = new int[MaxLength]; //定义第二个数整型数组
			
		int []Result = new int[MaxLength];    //定义存放结果数组
		int MidResult = 0;  //中间结果
        int num = 0;    //记录将字符转为整型的数
	    for(int i = LengthA-1,j = MaxLength-1; i >= 0; i--,j--){ //将第一个数字符串转为整型数组
	    	switch(FirstNumStr.charAt(i)){
	    	case '0':num = 0;break;
	    	case '1':num = 1;break;
	    	case '2':num = 2;break;
	    	case '3':num = 3;break;
	    	case '4':num = 4;break;
	    	case '5':num = 5;break;
	    	case '6':num = 6;break;
	    	case '7':num = 7;break;
	    	case '8':num = 8;break;
	    	case '9':num = 9;break;
	    	default:num = 0;break;
	    	}
	    	FirstNum[j] = num;
	    }
	    num = 0;
	    for(int i = LengthB-1,j = MaxLength-1; i >= 0; i--,j--){//将第二个数字符串转为整型数组
	    	switch(SecondNumStr.charAt(i)){
	    	case '0':num = 0;break;
	    	case '1':num = 1;break;
	    	case '2':num = 2;break;
	    	case '3':num = 3;break;
	    	case '4':num = 4;break;
	    	case '5':num = 5;break;
	    	case '6':num = 6;break;
	    	case '7':num = 7;break;
	    	case '8':num = 8;break;
	    	case '9':num = 9;break;
	    	default:num = 0;break;
	    	}
	    	SecondNum[j] = num;
	    }
	    
	    boolean FirstNumLarger = false;
Breakflag:for(int i = 0; i <MaxLength; i++){  //判断第一个数是否大于第二个数
	    	if(FirstNum[i] > SecondNum[i]){
	    		FirstNumLarger = true;
	    		break Breakflag;
	    	}else if(FirstNum[i] == SecondNum[i]){
	    		continue;
	    	}else{
	    		break Breakflag;
	    	}
	    }
	   
		for(int i = MaxLength-1; i >= 0; i--){       //从个位开始加
			if(FirstNumLarger){ //大数减小数
			    MidResult = FirstNum[i] - SecondNum[i];  //记录两数相减的中间结果			    
			}else{
				MidResult = SecondNum[i] - FirstNum[i];
			}
			if(MidResult < 0){    //借位
				Result[i] = 10 + MidResult ;  //本位的数
				if(FirstNumLarger){
					FirstNum[i-1] = FirstNum[i-1] - 1; //借位
				}else{
					SecondNum[i-1] = SecondNum[i-1] - 1;
				}
				
			}else{
				Result[i] = MidResult; //没有进位直接赋值
			}
		}
		
		String ResultStr = "";
		if(!FirstNumLarger){
			ResultStr = "-";
		}
		boolean flag = false;
		for(int j = 0 ; j < MaxLength; j++){ //将整型数组转为字符串
			if(Result[j] != 0){	//数组前面有0不赋值给字符串		    
			    flag = true;
			}
			if(flag){
				ResultStr += Result[j];
			}
		}
        if(ResultStr == "-"){ //相减为0时,赋值0
        	ResultStr = "0";
        }
		return ResultStr;
	}
	/**
	 * 乘方法
	 * @param SecondNumStr
	 * @return 相乘的结果
	 */
	public String multiply(String SecondNumStr){
		
	    boolean IsMinus = false; //是否带负号
		if(FirstNumStr.charAt(0) == '-'){
			IsMinus = !IsMinus;
			FirstNumStr = FirstNumStr.substring(1);
		}
		if(SecondNumStr.charAt(0) == '-'){
			IsMinus = !IsMinus;
			SecondNumStr = SecondNumStr.substring(1);
		}
		int LengthA = FirstNumStr.length(); //求出第一个数字符串长度
		int LengthB = SecondNumStr.length();//求出第二个数字符串长度
		
		int MaxLength = LengthA >= LengthB?LengthA:LengthB; //求出最大的长度
		MaxLength++; //多预留一个空间
		int ResultLength = MaxLength*2; //两个数相乘最多为两个数中最大长度的2倍
		
		int []FirstNum = new int[MaxLength];  //定义第一个数整型数组
		int []SecondNum = new int[MaxLength]; //定义第二个数整型数组
		int []TempNum = new int[MaxLength];   //临时整型数组存储中间计算结果
			
		int []Result = new int[ResultLength];    //定义存放结果数组
		int MidResult = 0;  //中间结果
        int num = 0;    //记录将字符转为整型的数
        
        for(int i = LengthA-1,j = MaxLength-1; i >= 0; i--,j--){ //将第一个数字符串转为整型数组
	    	switch(FirstNumStr.charAt(i)){
	    	case '0':num = 0;break;
	    	case '1':num = 1;break;
	    	case '2':num = 2;break;
	    	case '3':num = 3;break;
	    	case '4':num = 4;break;
	    	case '5':num = 5;break;
	    	case '6':num = 6;break;
	    	case '7':num = 7;break;
	    	case '8':num = 8;break;
	    	case '9':num = 9;break;
	    	default:num = 0;break;
	    	}
	    	FirstNum[j] = num;
	    }
	    num = 0;
	    for(int i = LengthB-1,j = MaxLength-1; i >= 0; i--,j--){//将第二个数字符串转为整型数组
	    	switch(SecondNumStr.charAt(i)){
	    	case '0':num = 0;break;
	    	case '1':num = 1;break;
	    	case '2':num = 2;break;
	    	case '3':num = 3;break;
	    	case '4':num = 4;break;
	    	case '5':num = 5;break;
	    	case '6':num = 6;break;
	    	case '7':num = 7;break;
	    	case '8':num = 8;break;
	    	case '9':num = 9;break;
	    	default:num = 0;break;
	    	}
	    	SecondNum[j] = num;
	    }
	    int PriorNum = 0; //进位
	    int k = ResultLength - 1; //Result[k]从个位向前赋值
	    
	    for(int i = MaxLength-1; i > 0; i--){      //控制第二个数的个、十、百向前推移
	    	for(int j = MaxLength-1; j > 0; j--){  //使第二个数与第一个数的每一位相乘
	    		MidResult = SecondNum[i]*FirstNum[j]; //保存两个数相乘的中间结果
	    		PriorNum = MidResult / 10;  //进位数
	    	//	if(MidResult >= 10){    //乘的结果需要进位
	    			TempNum[j] += MidResult % 10; //本位的值
	    			if(TempNum[j] >= 10){    //如果本位的值仍需进位,则再进一位
	    				TempNum[j] = TempNum[j] % 10; //本位的最终值
	    				PriorNum++; //需要的进位数再加一
	    			}
	    			TempNum[j-1] = TempNum[j-1]+PriorNum; //进位
	    	//	}
	    	}
	    	int m = k;
	    	for(int n = MaxLength-1; n >= 0; n--,m--){  //将临时存储的数组复制给最终结果数组
	    		Result[m] += TempNum[n]; //赋值
	    		if(Result[m] >= 10){  //若赋值相加需要进位,则进位
	    			Result[m-1] += Result[m]/10; //先进位
	    			Result[m] = Result[m] % 10;  //后算本位的值(这两句代码不能颠倒)	
	    		}
	    		TempNum[n] = 0; //临时数组置0,以便下一个循环用
	    	}
	    	k--;//下一次临时数组赋值时徐翔高位移一位
	    }
	    String ResultStr = "";
		if(IsMinus){
			ResultStr = "-";
		}
		
	    boolean flag = false;
		for(int j = 0 ; j < ResultLength; j++){ //将整型数组转为字符串
			if(Result[j] != 0){	//数组前面有0不赋值给字符串		    
			    flag = true;
			}
			if(flag){
				ResultStr += Result[j];
			}
		}
		if(ResultStr == ""){ //相乘为0时,显示0
        	ResultStr = "0";
        }
		return ResultStr;
	}
	/**
	 * 除方法
	 * @param SecondNumStr
	 * @return 除的结果
	 */
    public String divide(String SecondNumStr){
				
		boolean IsMinus = false; //是否带负号
		if(FirstNumStr.charAt(0) == '-'){    //第一个数带了负号
			IsMinus = !IsMinus;
			FirstNumStr = FirstNumStr.substring(1);			
		}
		if(SecondNumStr.charAt(0) == '-'){ //第二个数带了负号
			IsMinus = !IsMinus;
			SecondNumStr = SecondNumStr.substring(1);			
		}
		int LengthA = FirstNumStr.length(); //求出第一个数字符串长度
		int LengthB = SecondNumStr.length();//求出第二个数字符串长度
		
		if(LengthA < LengthB){   //因为是整除,所以第一个数小与第二个数时,直接返回 0
			return "0";
		}else if(LengthA == LengthB){ //字符串相等
			String result = subtract(SecondNumStr); 
			if(result.charAt(0) == '-'){ //第一个数小,直接返回0
				return "0";
			}else if(result.charAt(0) == '0'){ //两个数相等,则返回1
				return "1";
			}
		}
		
		int []Result =  new int[LengthA]; //存放最终结果的整型数组
		
		String SubTemp = ""; //存放字串
		String Temp = "";
		String result = "";
		String StoreFirstNumStr = FirstNumStr;//临时存放第一个数
		
		for(int i = LengthB-1 ; i < LengthA; i++ ){
			if(i == LengthB-1){
			    SubTemp = FirstNumStr.substring(0,LengthB);
			}else{
				FirstNumStr = SubTemp;
				SubTemp = subtract(Temp)+StoreFirstNumStr.substring(i,i+1);
			}
			for(int j = 9; j >= 0 ;j--){ //每一位的商值从9-0挨个试
				
				FirstNumStr = Integer.toString(j); //将整型转为字符串
				Temp = multiply(SecondNumStr);     //9-0中的数与被除数相乘
				
				FirstNumStr = SubTemp;
				result = subtract(Temp);//计算差值
				
				if(result.charAt(0) == '-'){ //若差值为负,则继续
					continue;
				}else{                      //否则,确定商,并跳出循环
					Result[i] = j;
					break;
				}
			}
		}
		 String ResultStr = "";//最终返回值的字符串
			if(IsMinus){      //计算结果为负
				ResultStr = "-";
			}
		
		boolean flag = false;  //标记变量,标记从Result[0]-Reslult[n-1]哪一位开始不为0,才赋值给ResultStr
		for(int j = 0 ; j < LengthA; j++){ //将整型数组转为字符串
			if(Result[j] != 0){	//数组前面有0不赋值给字符串		    
			    flag = true;
			}
			if(flag){
				ResultStr += Result[j];
			}
		}
		if(ResultStr == ""){ //相乘为0时,显示0
        	ResultStr = "0";
        }
		
		return ResultStr;
	}
	
}

测试代码:

import java.math.BigInteger;

/**
 *  @author ZhangyaChao(张亚超)
 *  @version 1.0
 *  @date 2013/9/17
 *  @last modify 2013/9/18
 */

public class Basic {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
                  //测试代码
		LargeInteger One = new LargeInteger("1024546448494645445444464545454545456546546548897454644");
		String Two = "1024546448494645454654";

		String result1 = One.add(Two);
		String result2 = One.subtract(Two);
		String result3 = One.multiply(Two);
		String result4 = One.divide(Two);
		
		BigInteger one = new BigInteger("1024546448494645445444464545454545456546546548897454644");
		
		BigInteger Result1 = one.add(new BigInteger("1024546448494645454654"));
		BigInteger Result2 = one.subtract(new BigInteger("1024546448494645454654"));
		BigInteger Result3 = one.multiply(new BigInteger("1024546448494645454654"));
		BigInteger Result4 = one.divide(new BigInteger("1024546448494645454654"));
		
		System.out.println(""+result1+"\n"+Result1+"\n\n");
		System.out.println(""+result2+"\n"+Result2+"\n\n");
		System.out.println(""+result3+"\n"+Result3+"\n\n");
		System.out.println(""+result4+"\n"+Result4+"\n\n");
	}

}



 

                  

           

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012027907/article/details/12191465
个人分类: JAVA
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭