High precision algorithm (children can understand = =)

Posted by SerpentSword on Mon, 21 Feb 2022 06:11:41 +0100

High precision algorithm

Here comes the question time (0v0!):

Question (1):

What is a high-precision algorithm? Why do we need high-precision algorithms? What can high-precision algorithms be used for?

Question (2):

How to store a large number?

Question (3):

How can you add them up? subtract? Multiply? What about division? ---- > Simulate primary school mathematics!

General knowledge points coming (ovo!):

Knowledge points (1):

For question (1):

In C + +, when you use super huge numbers that cannot be handled by int, long long, or even unsigned long long, you will feel extremely painful and even desperate. Then we have only one method at this time - high-precision algorithm.

High precision algorithm: it belongs to the mathematical calculation method for processing large numbers. It is an analog addition, subtraction, multiplication, division and other operations of large data with computer. For a very large number that cannot be normally stored in the computer, the number is disassembled and stored bit by bit in an array. An array is used to represent a number, so this number is called a high-precision number.

c language knowledge review:

Knowledge points (2):

Use the vector array in c++ stl library (here we only do a simple use of vector, specific underlying principles and container related knowledge, and interested students can learn by themselves)

use vector To store large numbers because vector The usage of array is basically no different from that of array, and it is more intelligent and smart! He is not as stupid as an array(~ ̄(OO) ̄)ブ,The size of the array needs to be set in advance. It can open a new space to provide new data when it needs to be used at any time. Moreover, it has more methods to facilitate our calculation!

Here comes vector Smart:

Vector in C + + is an array that can be changed in size. When you can't know the size of the array you need when solving problems, you can use vector to achieve the purpose of maximum space saving. You need to include the vector header file when using.

The syntax for defining a one-dimensional dynamic array is
vector<int> a;  //int is the element data type of the dynamic array, which can be string, double, etc
[1,2]
The syntax for defining a two-dimensional dynamic array is
vector<int*> a; //The 3D data type is int * *, and so on.

The basic operations of vector in C + + include:

Here is a simple example:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
    vector<int> a;
    vector<int> b;

for (int i = 0; i < 10; i++)    //Add 0 ~ 9 to array a in turn
    a.push_back(i);

a.swap(b);      //Swap array a elements with array b elements
cout << a.size() << " " << b.size() << endl;    //0 10 should be output at this time

for (vector<int>::iterator it = b.begin(); it != b.end(); it++)//Traverse the array elements from the first element
    cout << *it << " ";     //Output 0 ~ 9 in sequence
cout << endl;

b.erase(b.begin() + 1);     //Delete the element at position 1, i.e. element 1
cout << b.size() << endl;   //Since an element is deleted, the output should be 8 at this time

for (vector<int>::reverse_iterator rit = b.rbegin(); rit != b.rend(); ++rit)//Reverse output array element
    cout << *rit << " ";    //Should output 9 8 7 6 5 4 3 2 0
cout << endl;

b.resize(9);    //Set the array space to 9, which is equivalent to one more position than before
b.push_back(20);//Add element 20 at the end

for (vector<int>::iterator it = b.begin(); it != b.end(); it++)
    cout << *it << " ";  //Should output 0 2 3 4 5 6 7 8 9 20

return 0;

}

Here comes the thought process (= v =!):

Addition:

Key analysis:

  1. A large number is stored upside down in the array. This is because once carry occurs, we need to open up a new space and fill in the number obtained by carry. If the largest bit of a number is the first bit of the array, we need to move the whole array backward to make room for new space after carry occurs, We can simply put the most effective carry to solve this problem
  2. The essence of addition: A[i] (the ith bit of array A) + B[i] (the ith bit of array B) + T (carry)

Subtraction:

Key analysis:

  1. The difference between string comparison and string number comparison:

    character string:

    For example, the comparison between (James and Jan) depends on the ascll value. The first two characters of the two strings are the same, and the ascll code value of the third character n is greater than m, so Jan > James

    String number:

    1235 and 12345 are compared. In people's impression, 12345 must be larger, but the string 1235 in the computer is larger than 12345 because of the size of the ASCL code of the fourth character. Therefore, when comparing the size of digital string, we can't simply use the function a.compare(b). We need to write a function manually!

    Numeric string size judgment function:

    bool cmp(string a,string b){
    	if(a.size()!=b.size())return a.size()>b.size();
    	for(int i=0;i<a.size();i++){
    		if(a[i]!=b[i])return a[i]>b[i];
    	}
    	return true;
    }
    
  2. A-B size analysis

    A-B>=0—>A-B

    A-B<0—>-(B-A)

  3. Substance:

    t=A[i]-B[i]-t;

    If t > = 0, C [i] = t; t=0;

    If T < 0, C [i] = t + 10; t=1;

  4. Leading zero problem:

    Sometimes leading zeros appear during subtraction

    Then use

    while(C.size()>1&&C.back()==0)C.pop_back();
    

Multiplication: (large positive integer * small positive integer)

Key analysis:

  1. Substance:

    t+=A[i]*b;

    C .push _ back(t%10);

    t/=10;

  2. Carry problem

    When the multiplication is completed, if the last t > 0 is found, it means that the highest bit of our multiplier is multiplied by our multiplier to get a number greater than 10. At this time, we continue to carry

    By:

    while(t){
    	C.push_back(t%10);
    	t/=10;
    }
    
  3. Leading 0 (0 * 123456)

    Same formula

    while(C.size()>1&&C.back()==0)C.pop_back();
    

Division:

Key analysis:

  1. Substance:

    ​ t=t*10+A[i];

    ​ C .push_back(t/b);

    ​ t=t%b;

  2. Note that division is calculated from high to low

    for(int i=A.size()-1;i>=0;i--);
    

    After the operation, reverse the array and remember to add #include < algorithm > header file

    reverse(C.begin(),C.end());
    
  3. Note handling leading 0

    while(C.size()>1&&C.back()==0)C.pop_back();
    

Code template coming (o!):

Addition template:

#include<iostream>
#include<vector>
using namespace std;
vector<int> add(vector<int> &A,vector<int> &B){//Use reference to directly call the original address and modify the original array without opening up new space and saving time
	if(A.size()<B.size())return add(B,A); //Because the length of the two numbers is large or small, the premise of our algorithm design is to consider according to the number, so just reverse it!
	vector<int> C;//Answer array
	int t=0;//Carry flag
	for(int i=0;i<A.size();i++){//At this time, array A must be larger than array B. The for loop is designed according to the large array
		t+=A[i];//Equivalent to t+A
		if(i<B.size())t+=B[i];//If B has not been added, it is equivalent to t (carry) + a (number A) + (number B)
		C.push_back(t%10);//The remainder obtained through t%10 is the number stored in the current position
		t/=10;//t/=10 get the number of digits
	}
	if(t) C.push_back(t);//After all, if t= 0 indicates that there is still carry in the maximum position. At this time, a new bit will be created for the carry result
	return C;
}
int main(){
	string a,b;//Because a, b can be huge! So use string to save!
	vector<int> A,B;//This is equivalent to an array. Each bit of the string represents each bit of the array. We choose vector to store the string
	cin>>a>>b;
	for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');//Store each bit in a string in reverse order in a
	for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');//Same as the above sentence
	vector<int> C=add(A,B);//Call addition function
	for(int i=C.size()-1;i>=0;i--)cout<<C[i];
	return 0;
}

Subtraction template:

#include<iostream>
#include<vector>
using namespace std;
bool cmp(string a,string b){
	if(a.size()!=b.size()) return a.size()>b.size();
	
	for(int i=0;i<a.size();i++){
		if(a[i]!=b[i])return a[i]>b[i];
	}
	return true;
	
}
 vector<int> sub(vector<int> &A,vector<int> &B){
	int t=0;
	vector<int> C;
	
	for(int i=0;i<A.size();i++){
		t=A[i]-t;
		if(i<B.size())t-=B[i];
		if(t>=0){
			C.push_back(t);
			t=0;
		}else{
			C.push_back(t+10);
			t=1;
		}
	}
	while(C.size()>1&&C.back()==0)C.pop_back();
	return C;
	
}
int main(){
	string a,b;
	cin>>a>>b;
	vector<int> A,B;
	for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
	for(int i=b.size()-1;i>=0;i--)B.push_back(b[i]-'0');
	
	if(cmp(a,b)){
	vector<int> C=sub(A,B);
	for(int i=C.size()-1;i>=0;i--)cout<<C[i];
	}else{
	vector<int> C=sub(B,A);
	cout<<"-";
	for(int i=C.size()-1;i>=0;i--)cout<<C[i];
	}
}

Multiplication template:

#include<iostream>
#include<vector>
using namespace std;
 vector<int> mul(vector<int> &A,int b){
	int t=0;
	vector<int> C;
	for(int i=0;i<A.size();i++){
		t+=A[i]*b;
		C.push_back(t%10);
		t/=10;
	}
	while(t){
		C.push_back(t%10);
		t/=10;
	}
	return C;
}
int main(){
	string a;
	int b;
	cin>>a>>b;
	vector<int> A;
	for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
	vector<int> C=mul(A,b);
	for(int i=C.size()-1;i>=0;i--)cout<<C[i];
	return 0;
}

Division template:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//r=r*10+A[i]
vector<int> div(vector<int> &A,int b,int &r){
	vector<int> C;
	for(int i=A.size()-1;i>=0;i--){
		r=r*10+A[i];
		C.push_back(r/b);
		r%=b;
	}
	reverse(C.begin(),C.end());
	while(C.size()>1&&C.back()==0)C.pop_back();
	return C;
}
int main(){
	string a;
	int b;
	cin>>a>>b;
	vector<int> A;
	int r=0;
	for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
	vector<int> C=div(A,b,r);
	for(int i=C.size()-1;i>=0;i--)cout<<C[i];
	cout<<endl<<r;
	return 0;
}

Topics: C++ Algorithm