两个大整数的加、减、乘、除操作(C++实现)


大整数的相关操作

1、给定条件下的数据范围:1 <= A <= 1 0 5 10^5 105 ,1 <= B <= 1 0 5 10^5 105
2、加载数据:将输入的数据作为字符存储,实现大整数数据的加载
3、数据处理:使用C++的vector向量处理输入数据,并且数据低位在前( string “12344” --> vector {4,4,3,2,1} )
4、执行相关操作:通过以下方法实现加、减、乘、除


1、加法操作
/*
* param : 加法因子 A (vector<int>) , 加法因子 B (vector<int>)
* return :  加法结果 C (vector<int>)
*/
vector<int> add(vector<int> &A, vector<int>&B){
    vector<int> C;   //定义返回结果C
    int t=0;   //定义进位值
    for(int i=0;i<A.size()||i<B.size();i++){ 
    
    	/*  从低位开始进行对应位的相加,即在第i位有:(式子右边的t表示i-1位上进行加运算后的进位值)
    	*  1. t = t+A[i]+B[i] , i<A.size() and i<B.size() 第i位上A和B均有值
    	*  2. t = t+A[i] , i<A.size() and i>=B.size() 第i位上仅A有值
    	*  3. t = t+B[i] , i<B.size() and i>=A.size() 第i位上仅B有值
    	*/
        if(i<A.size()) t += A[i];   
        if(i<B.size()) t += B[i];
        
        // ( t mod 10 ), 即第i位的结果 
        C.push_back(t%10);
        
        // t>10 表示有进位,进位值为 t / 10 = t
        // t<10 表示无进位,进位值为 t / 10 = 0
        t /= 10;   
    }
    //如果在A和B的最后一位上进行加运算仍有进位(t=1),即添加至结果中
    if(t) C.push_back(1);
    return C;
}

2、减法操作
/*
* param : 被减数 A (vector<int>) , 减数 B (vector<int>)
* return :  加法结果 C (vector<int>)
*/
vector<int> sub(vector<int> &A,vector<int> &B){
    vector<int> C;  //定义返回结果C
    int t=0;   //定义借位值
    for(int i=0;i<A.size()||t;i++){
    
    	// 从低位开始进行对应位的相减 
        t = A[i] - t;  //被减数中第i位的值A[i]需要先减去第i-1位上的借位值
        if(i<B.size()) t -= B[i];  //然后当减数B第i位上有值时,需要减去B[i]
        
        /*  第i位的结果是:(t+10) mod 10, 当在第i位上进行减操作的时候:
        *  1. 若t<0,则说明需要向A[i+1]借位
        *  2. 若t>=0,则不需要借位
        */
        C.push_back((t+10)%10);  
        
        if(t<0) t = 1; //发生借位,则借位值为1
        else t = 0;  //否则为0
    }
    //去除前导0,否则会出现:333- 332 = 001 的情况
    while(C.size()>1&&C.back()==0) C.pop_back();
    return C;
}

因为当进行减法操作时会出现A-B(A<B)的情况,所以需要考虑正负,而通过如下的比较函数可以避免在sub函数中考虑正负,如下所示:

bool cmp(vector<int> &A, vector<int> &B){

	/* 当A和B的长度不一致时返回长度较大的那个
	* A : { 1, 4 , 5 , 6 , 3 , 2 } --> 236541  √  
	* B : { 3, 3 , 6 , 7 , 8 }  --> 87633
	*/
    if(A.size()!=B.size()) return A.size()>B.size();

	//当A和B的长度一致时从高位开始遍历A和B
    for(int i=A.size()-1;i>=0;i--){
    	/* 当A[i]和B[i]不相等时返回值较大的那个
    	* A : { 1, 4 , 5 , 6 , 3 , 2 } --> 236541    
		* B : { 3, 3 , 6 , 6 , 3 , 2 } --> 236633  √
		*       0  1   2   3   4   5       
		* 		       <   =   =   = 
    	*/
        if(A[i]!=B[i]) return A[i]>B[i];
    }
    return true;
}

3、乘法操作
/*
* param : 乘法因子 A (vector<int>) , 乘法因子 B (vector<int>)
* return :  乘法结果 C (vector<int>)
*/
vector<int> multi(vector<int> &A,vector<int> &B){
	/* 构造返回结果C,设置其长度为A和B的长度之和,该长度满足任意情况
	* A : { a3 , a2 , a1 }  
	* B : { b3 , b2 , b1 }
	* C = A × B = { a3·b3 , a3·b2 + a2·b3 , 
	*     a3·b1 + a2·b2 + a1·b3 , a2·b1 + a1·b2 , a1·b1 } 
	* 因为a3·b3的结果可能大于10,所以需要保证C的长度为A和B的长度和
	*/
    vector<int> C(A.size()+B.size(),0); 

    for(int i=0;i<A.size();i++){
        for(int j=0;j<B.size();j++){
        	//先将A和B的不同位上的数相乘,然后将结果添加到C的对应位上
            C[i+j] += A[i] * B[j];  //使用+=是因为第i+j位上可能存在其他值
        }
    }
    int t=0;  //定义进位值
    //遍历初始结果C,对每一位上的数据进行处理,因为其中的某位数据可能是两位数或三位数
    for(int i=0;i<C.size();i++){
        t = t + C[i]; //等式右侧的t表示第i-1位上的进位值
        C[i] = t%10;  //第i位上的值取该位上C[i]的模即可
        t/=10;   //然后通过t/10来求得进位值
    }
     //去除前导0,否则会出现:333 × 0 = 000 的情况
    while(C.size()>1&&C.back()==0) C.pop_back();
    return C;
}

4、除法操作
/*
* param : 被除数 A (vector<int>) , 除数 B (vector<int>) , 余数 r (vector<int>)
* return :  除法结果 C (vector<int>)
*/
vector<int> div(vector<int> &A, vector<int> &B, vector<int> &r)
    vector<int> C;  //定义返回结果C
    
    /*  假设 A={1,2,3,4}-->"4321", B={1,1,2}-->"211", 执行的过程如下:
    *   1. j=3  
    * 		第一步: r={2,3,4}-->"432"  
    * 		    因为 r="432" > B="211",所以 r=sub(r,B) => r="432"-"211"="221"
    * 		第二步: r={1,2,2}-->“221”  
			    因为 r="221" > B="211",所以 r=sub(r,B) => r="221"-"211"="10"
    * 		第三步: r={0,1}-->"10"
    * 			因为 r="10" < B="211",所以需要补充一位,即使j值加1
    * 		因为执行了两次sub操作,即第一位的商值为2 => C={2}
    *   2. j=4
    * 		第一步: r={1,0,1}-->"101"
    * 			因为 r="101" < B="211",所以需要补充一位,即使j值加1
    * 		因为执行了零次sub操作,即第二位的商值为0 => C={2,0}
    * 		并且为了使商值C满足数据格式的要求,即低位在前,需要使其反转 C={0,2}
    * 	3. j=5 
    * 		因为 j=5 > A.size(),所以循环结束,得出结果:
    * 			商:C={0,2} --> "20"
    * 			余数:r={1,0,1}  --> "101"
    */
    int j = B.size();   //获取B的长度值
    r.assign(A.end()-j,A.end());  //先将A{n-j..n}的值分配给余数r
    
    while(j<=A.size()){
        int k=0;  //定义商值
        
        //循环执行减操作,前提是r要大于B
        while(cmp(r,B)){ 
            r = sub(r,B);   //更新r向量的值
            k++;  //更新商值
        }
        C.push_back(k);  //添加商值
        
        //使r向量向后补充一位,使之能够继续执行循环减操作
        if(j<A.size()) r.insert(r.begin(),A[A.size()-j-1]); 
        
        //去除r向量的前导0,否则出现1101/11 => r=01/11 的情况
        if(r.size()>1&&r.back()==0) r.pop_back();  
        
        j++;  //j指针向右移一位,即表示向量r向后补充一位
    }
    reverse(C.begin(),C.end());  //反转商值向量C,使其满足数据格式要求
	
	//去除C向量的前导0,否则出现1101/11 => C="0100" 的情况
    while(C.size()>1&&C.back()==0) C.pop_back();  
    return C;
}

执行示例
int main(){
    string a,b;  //定义a和b为string字符串
    cin>>a>>b;   //输入a和b
    vector<int> A,B,r;  //定义A、B和r向量表示a、b和余数
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');  //处理字符串a得到A
    for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');  //处理字符串b得到B
    vector<int> C;  //定义返回结果C
    
    /* 1.加法示例
    *  C = add(A,B);
    */

	/* 2.减法示例
	*  if(cmp(A,B)){
    *      C = sub(A,B);
    *  }else{
    *     C = sub(B,A);
    *     printf("-");
    *  }
	*/

	/* 3.乘法示例
	*  C = multi(A,B);
	*/

	/* 4.除法示例
	*   if(cmp(A,B)){
    *      C = div(A,B,r);
    * 	}else{
    *      C.push_back(0);
    *      r.assign(A.begin(),A.end());
    * 	}
	*/
	
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值