[C + +] vector and high-precision calculation

Posted by erikwebb on Wed, 27 Oct 2021 16:39:31 +0200

vector

Luogu original topic https://www.luogu.com.cn/problem/P1009
This topic requires high-precision factorial writing, but I haven't learned it yet. I picked up all kinds of materials and online classes from the Internet and found that before learning high precision, I need to know the container vector.

What is a vector

vector is a sequential container that encapsulates dynamic size arrays and belongs to C++STL. You can simply think. vector is a dynamic array that can store any type.

Using vector

To use vector, you need to add at the beginning of the file
#include< vector >
using namespace std;

Original link: https://blog.csdn.net/qq_38654981/article/details/81907134
https://blog.csdn.net/w_linux/article/details/71600574
Initialization of vector:

  1. Vector < type > identifier / / vector a
  2. Vector < type > identifier (maximum capacity) / / vector (10)
  3. Vector < type > identifier (maximum capacity, initial all values) / / vector (10,1)
  4. int b[7]={1,2,3,4,5,9,8}; vector a(b,b+7); // Get initial value from array
  5. vector< vector< int> >v; Two dimensional vector / / the outermost < > here must have a space. Otherwise, it cannot pass under the older compiler
  6. vector a(b); // Use B vector to create a vector, and assign global replicability

vector function set
https://blog.csdn.net/w_linux/article/details/71600574

High precision calculation

After learning vector, start learning high-precision calculation

In fact, high-precision computing is to store big data in a string for manual operation and re storage. The principle is roughly the same and the algorithm is different.

High precision addition

#include <iostream>
//< vector > comes with a size function to find the length 
#include <vector> 
using namespace std;
//Array length + 10 prevents boundary problems 
const int N=1e6+10;
//Write a method that returns the vector type 
//The address character is taken here because the reference type is faster 
//C=A+B
vector<int> add(vector<int> &A,vector<int> &B){
	vector<int> C;
	int t =0;//This is a carry and is used to store data at the same time 
	for (int i=0;i<A.size()||i<B.size();i++){
		 if(i<A.size()) t+=A[i];
		 if(i<B.size()) t+=B[i];
		 //The current bit can only store single digits of data t 
		 C.push_back(t%10);
		 //Let t divide by 10 
		 t/=10;
	}
	//If t is still several at this time, enter 1 
	if(t) C.push_back(1);
	return C;
}
int main(){
	//The number is too long to read with string 
	string a,b;
	vector<int>A,B;
	cin>>a>>b; //a="123456"
	for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
	//Store in reverse order / / characters become integers minus' 0 ' 
	for(int i=b.size()-1;i>=0;i--)B.push_back(b[i]-'0');
	auto C = add(A,B);
	//Reverse order output 
	for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
	return 0; 
}

High precision subtraction

High precision subtraction and addition are mainly input and output in the main function. There is no difference. Therefore, for convenience, only function template fragments are put in.

vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size(); i ++ )
    {   //t is used to store data
        t = A[i] - t; //Maybe there's a borrow space in front
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);//t+10 because t-B[i] may be negative
        //If T < 0, record and borrow 1 from the high order. When t = a [i] - t = 1, the high order number decreases by 1
        if (t < 0) t = 1;
        else t = 0;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();//Judge whether the highest bit is 0
    return C;
}

High precision multiplied by low precision

High precision multiplication is different from the usual multiplication formula. Usually, we do multiplication, such as 123 * 12, which is 123 * 2 + 123 * 10.
And high-precision multiplication, such as 123 * 12
3 * 12 = 36, carry 3, and the last bit is 6.
2 * 12 + 3 = 27, the penultimate bit of carry 2 is 7.
1 * 12 + 2 = 14, carry 1, and the penultimate digit is 4.
0 * 12 + 1 = 1, the first digit is 1.
Combined to 1476.

The code implementation is as follows:

#include <iostream>
//< vector > comes with a size function to find the length
#include <vector>
using namespace std;
//Array length + 10 prevents boundary problems
const int N=1e6+10;
//Write a method that returns the vector type
//The address character is taken here because the reference type is faster
vector<int> mul(vector<int> &A,int b)
{
    vector<int> C;
    if (b==0){ //Because it is a string type, 00000 will be output at * 0 without if judgment
        C.push_back(0);
        return C;
    }
    int t =0;
    for (int i =0;i<A.size();i++){
        t+=A[i]*b;  //t=t+A[i]*b the first t = represents the data, and T + of T + represents the carry of the previous operation
        C.push_back(t%10);  //Single digits of t
        t=t/10;    //Carry of t
    }
    if (t) C.push_back(t);  //Add carry
    return C;
}
int main(){
    //a the number is too long, read it with string, b can read it directly
    string a;
    int b;
    //Save a to vector
    vector<int> A;
    cin>>a>>b;
    //Deposit from low position
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    auto C = mul(A,b);
    //Output from the end of the vector
    for(int i =C.size()-1;i>=0;i--) printf("%d",C[i]);
    return 0;
}

The mul function can be simplified as follows:

vector<int> mul(vector<int> &A,int b)
{
    vector<int> C;
    if (b==0){ //Similarly, 0 data needs special judgment
        C.push_back(0);
        return C;
    }
    int t =0;
    for (int i =0;i<A.size()||t;i++){  //Add a "||t" condition judgment, either i does not complete the cycle, or T is not 0
        if (i<A.size()) t+=A[i]*b;  //Because conditions are added above, the following multiple judgments determine whether i is within the range of A
        C.push_back(t%10);  //Single digits of t
        t=t/10;    //Carry of t
    }
    return C;
}

High precision except low precision

Train of thought:
138/12
Starting from the highest bit, 1 / 12 = 0... 1, 1 falls to the next bit
The remainder of the above formula * 10 + the second digit: (1 * 10 + 3) / 12 = 1... 1, 1 to the next digit
Similarly: (1 * 10 + 8) / 12 = 1... 6
Get the answer 011, remove the highest bit 0, and the answer is 11... 6

Division returns the remainder in addition to the quotient:
The code implementation is as follows:

#include <iostream>
//< vector > comes with a size function to find the length
#include <vector>
#Include < algorithm > / / this header file contains the function reverse
using namespace std;
//Array length + 10 prevents boundary problems
const int N=1e6+10;
//Write a method that returns the vector type
//The address character is taken here because the reference type is faster
vector<int> div(vector<int> &A,int b,int &r)//r is the remainder. The address character is used to directly change the value of r
{
    vector<int> C;
    r=0;
    for(int i=A.size()-1;i>=0;i--){   //Division needs to start with the high-order number, so for is a positive loop
        r=r*10+A[i];
        C.push_back(r/b);
        r=(r%b);
    }
    reverse(C.begin(),C.end());  //Because the final result of C is in positive order and the output of C is in reverse order, it should be reversed
    while (C.size()>1&& C.back()==0) C.pop_back(); //Remove the leading 0 sentence and put it after reverse!
    return C;
}
int main(){
    //a the number is too long, read it with string, b can read it directly
    string a;
    int b,r;
    //Save a to vector
    vector<int> A;
    cin>>a>>b;
    //Deposit from low position
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    auto C = div(A,b,r);
    //Output from the end of the vector
    for(int i =C.size()-1;i>=0;i--) printf("%d",C[i]);
    cout<<endl<<r<<endl;
    return 0;
}

In fact, the input and output parts of high-precision calculation are not much different, mainly in the function template

In particular, high-precision division requires setting the remainder in the function.

Topics: C++ Back-end