Four operations of large number and high precision

Posted by Renlok on Thu, 13 Feb 2020 15:36:55 +0100

Four operations of large numbers

High precision calculation means that the number involved in the operation is far beyond the range of standard data types, such as multiplication of two 1000 digits, which occurs frequently in algorithm competitions. In c or c + +, the maximum data type is only 64 bits. If a larger number needs to be processed, it can only be simulated by an array. Each bit of the large number can be stored in an array, and then carry and borrow bits can be processed by bits.
I searched some data on the Internet and found that what I wrote was too tedious and difficult to understand. I wrote four operations for large numbers (division is not written for the time being, but it will be updated tomorrow). The code is as follows.
First define a structure

typedef struct aaa{
	int num[MAXN];			//The high and low bits store your numbers in reverse 
	int len;				//Number of digits 
	aaa(){memset(num,0,sizeof(num));len=-1;}		//Constructor 
}bignum;

Note that there is a num [] array in the structure, and the high and low order of the stored numbers are opposite, for example, 1234. In the array, it is actually num[0]=4,num[1]=3,num[2]=2,num[3]=1, which is helpful for the subsequent operation, because the addition and subtraction methods start from the low order. len represents the number of digits in the number.

A function that converts a string to a large number

bignum change_bignum(char *s){
	bignum tmp;
	int length=strlen(s);
	for(int i=0;i<strlen(s);i++)
		tmp.num[length-1-i]=s[i]-48;		//High position in front, low position in front, convenient for operation 
	tmp.len=length;
	return tmp;
}

The parameter of this function is a character pointer. In the main function, as long as the value is assigned in the character array, you can call the change ﹣ bignum() function, and then return a bignum type structure. Again, the high and low order of large numbers are the opposite.

Print large functions

void show(bignum a){		//Print digit 
	for(int i=a.len-1;i>=0;i--)
		printf("%d",a.num[i]);	
	printf("\n");
}

Note that even after the operation is completed, it can only be output through the array, because even the long long is not so large. (subtraction, division may get a small number, but it's special)
When the preparation is finished, you can do the calculation.
Addition operation

bignum add(bignum a,bignum b){
	bignum tmp;
	int carry=0;			//Carry information 
	int length=max(a.len,b.len); 	//Maximum number of digits of two numbers 
	for(int i=0;i<length;i++){
		tmp.num[i]=(a.num[i]+b.num[i]+carry)%10;	//Store the number after operation 
		carry=(a.num[i]+b.num[i]+carry)/10;			//Update carry information 
	}
	if(carry){			//If there is carry after the last operation 
		tmp.num[length]=carry;	//The highest digit is the carry digit 
		tmp.len=length+1;		//New digits plus 1 
	}
	else
		tmp.len=length;			//Number of new digits 
		
	return tmp;
}

The idea is to add from the low order. If it is greater than 10, carry information will be stored with carry, and then the result of adding mod10 will exist in the corresponding position. If the result of addition is greater than 10, carry can directly assign 1. Why? Because two numbers less than 10 are added, the maximum is 18, and only one digit can be added. But it is better to divide 10 by the result of addition, because in the later multiplication operation, carry information may be 2, 3, 4 For example, 7 * 7, 4. The last if, else to assign a length to a new large number, generally speaking, is the one with the most median of two addends, but after adding two numbers with the same number of digits, carry information may be generated in the highest position, so you need to add the length of the large number by one bit, such as 77 + 66.

Subtraction operation

bignum Minus(bignum a,bignum b){			//a is bigger than b. 
	bignum tmp;
	for(int i=0;i<a.len;i++){
		if(a.num[i]<b.num[i]){
			int borrow=1;			//Borrow information 
			while(a.num[i+borrow]==0)		//The high order is 0 until you find a number to borrow 
				borrow++;
			a.num[i+borrow]--;		//Number of borrowed digits minus 1 
			a.num[i]+=10;			//Borrow digit plus 10 
			for(int j=i+1;j<i+borrow;j++){		//Change the high order of those 0's
				a.num[j]=9;	 
			}
		}
		tmp.num[i]=a.num[i]-b.num[i];
	}
	
	for(int i=a.len-1;i>=0;i--)		//Find the number whose first highest digit is not 0 as the highest digit of the new number 
		if(tmp.num[i]!=0){
			tmp.len=i+1;			//Number of new digits 
			break;
		}
	return tmp;
}

Subtraction is more complicated than addition (for example, division is more difficult than multiplication. The blogger hasn't written it out yet, and it will be updated tomorrow)
Addition has carry, subtraction has borrow, addition starts from the lowest, subtraction also starts from the lowest. If the low value of the subtracted digit is smaller than the low value of the subtracted digit, it needs to borrow 1 from the high position. If the high position is 0, it needs to borrow from the next higher position until the high position is non-zero. Then add 10 to the position number of the borrow position and subtract 1 from the digit value of the borrowed position. In the middle of the process, all the bits of 0 become 9 (better than 1001-9). When the borrow position is good, it can be calculated. After the operation is completed, traverse from high to low to find the first non-zero bit, so that the number of new digits can be determined.

Multiplication operation

The multiplication of large numbers is the same as that of primary schools. The column vertical calculation is as shown in the figure above.

bignum multiply(bignum a,bignum b){			//Column calculation 
	bignum tmp;
	int carry=0;
	for(int i=0;i<b.len;i++){		//Every one of b 
		for(int j=0;j<a.len;j++){		//Everyone of a 
			tmp.num[i+j]+=(b.num[i]*a.num[j]+carry)%10;		//Multiplication as shift addition 
			carry=(b.num[i]*a.num[j]+carry)/10;
			if(tmp.num[i+j]>=10){		//Vertical accumulation may also produce carry 
				tmp.num[i+j]-=10;		//Here, the result of each operation is added directly to the number on the corresponding digit 
				carry++;				//Generating carry directly gives the next bit of this vertical calculation without affecting the final result 
			}
		}
	}
	if(carry){		//Similarly, if the carry is generated by the highest order operation of two numbers, the number of digits of the new number will be increased by 1 
		tmp.num[a.len-1+b.len]=carry;
		tmp.len=a.len+b.len;	
	}
	else
		tmp.len=a.len-1+b.len;	//Otherwise, think about 1000 * 100 and 300 * 400 
	
	return tmp;
}


The first row of numbers is assumed to be a, the second row is b, and each bit of b is multiplied by each bit of a, so there are two layers of loops. Note that the weights of each digit of a and b are different, for example, the second digit of a, 2, and the first digit of b, 4. The result of multiplication should be saved in ten digits. The result of multiplication of the i-th digit of a and the j-th digit of b should be saved in the i+j-th digit of the new number (note here that num[0] is a digit number. To generalize, num[i] is an i+1 digit number). You can find several numbers to verify it. Note also that there are two carry information here, one is the carry obtained by multiplying each bit of a and b, and the other is the carry generated by adding the intermediate results of two multiplication (pink in the figure). After explanation, the above code is easy to understand.

The complete code is as follows (large divisor is not available for now, it will be updated tomorrow)

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1000;
typedef struct aaa{
	int num[MAXN];			//The high and low bits store your numbers in reverse 
	int len;				//Number of digits 
	aaa(){memset(num,0,sizeof(num));len=-1;}		//Constructor 
}bignum;

bignum change_bignum(char *s){
	bignum tmp;
	int length=strlen(s);
	for(int i=0;i<strlen(s);i++)
		tmp.num[length-1-i]=s[i]-48;		//High position in front, low position in front, convenient for operation 
	tmp.len=length;
	return tmp;
}
bignum add(bignum a,bignum b){
	bignum tmp;
	int carry=0;			//Carry information 
	int length=max(a.len,b.len); 	//Maximum number of digits of two numbers 
	for(int i=0;i<length;i++){
		tmp.num[i]=(a.num[i]+b.num[i]+carry)%10;	//Store the number after operation 
		carry=(a.num[i]+b.num[i]+carry)/10;			//Update carry information 
	}
	if(carry){			//If there is carry after the last operation 
		tmp.num[length]=carry;	//The highest digit is the carry digit 
		tmp.len=length+1;		//New digits plus 1 
	}
	else
		tmp.len=length;			//Number of new digits 
		
	return tmp;
}
bignum Minus(bignum a,bignum b){			//a is bigger than b. 
	bignum tmp;
	for(int i=0;i<a.len;i++){
		if(a.num[i]<b.num[i]){
			int borrow=1;			//Borrow information 
			while(a.num[i+borrow]==0)		//The high order is 0 until you find a number to borrow 
				borrow++;
			a.num[i+borrow]--;		//Number of borrowed digits minus 1 
			a.num[i]+=10;			//Borrow digit plus 10 
			for(int j=i+1;j<i+borrow;j++){		//Change the high order of those 0's
				a.num[j]=9;					//For example, the tens of 101-99 101 become 9 
			}
		}
		tmp.num[i]=a.num[i]-b.num[i];
	}
	
	for(int i=a.len-1;i>=0;i--)		//Find the number whose first highest digit is not 0 as the highest digit of the new number 
		if(tmp.num[i]!=0){
			tmp.len=i+1;			//Number of new digits 
			break;
		}
	return tmp;
}
void show(bignum a){		//Print digit 
	for(int i=a.len-1;i>=0;i--)
		printf("%d",a.num[i]);	
	printf("\n");
}
bignum multiply(bignum a,bignum b){			//Column calculation 
	bignum tmp;
	int carry=0;
	for(int i=0;i<b.len;i++){		//Every one of b 
		for(int j=0;j<a.len;j++){		//Everyone of a 
			tmp.num[i+j]+=(b.num[i]*a.num[j]+carry)%10;		//Multiplication as shift addition 
			carry=(b.num[i]*a.num[j]+carry)/10;
			if(tmp.num[i+j]>=10){		//Vertical accumulation may also produce carry 
				tmp.num[i+j]-=10;		//Here, the result of each operation is added directly to the number on the corresponding digit 
				carry++;				//Generating carry directly gives the next bit of this vertical calculation without affecting the final result 
			}
		}
	}
	if(carry){		//Similarly, if the carry is generated by the highest order operation of two numbers, the number of digits of the new number will be increased by 1 
		tmp.num[a.len-1+b.len]=carry;
		tmp.len=a.len+b.len;	
	}
	else
		tmp.len=a.len-1+b.len;	//Otherwise, think about 1000 * 100 and 300 * 400 
	
	return tmp;
}

int main(){
	bignum a,b,result;
	char s[MAXN];
	scanf("%s",s);
	a=change_bignum(s);
	scanf("%s",s);
	b=change_bignum(s);
	
	result=add(a,b);
	show(result);
	
	result=multiply(a,b);
	show(result);
	
	result=Minus(a,b);
	show(result);
	
	return 0;
}
Published 6 original articles, praised 0, visited 49
Private letter follow

Topics: less