Four operations of large integers (high precision calculation) (c language)

Posted by notionlogic on Wed, 16 Feb 2022 15:45:32 +0100

Large integer operation

For A topic of A + B, if the range of A and B is in the range of int, I believe you can write the program soon. However, if A and B are integers with 1000 digits, there is no data type to represent. At this time, you can only honestly simulate the process of addition, subtraction, multiplication and division. In fact, the principle of these things is primary school knowledge. In addition, large integers are also called high-precision integers, which means integers whose precision cannot be stored with basic data types.

1. Storage of large integers

An array is used to store each bit of an integer, and the high order of the integer is stored in the high order of the array, and the low order of the integer is stored in the low order of the array. In order to obtain the length of a large integer at any time, generally, an len of int variable type is defined to record its length, and the structure is formed with the array as follows:

//Large integer structure
struct bign {
    int d[1000];
    int len;
    bign() {    //Initialize structure
        memset(d, 0, sizeof(d));
        len = 0;
    }
};

2. Input of large integer

//Enter a large integer
bign change(char str[]) {   //Convert integer to bign
    bign a;
    a.len = strlen(str);
    for (int i = 0; i < a.len; i++) {
        a.d[i] = str[a.len - 1 - i] - '0';//Reverse order assignment
    }
    return a;
}

 3. Compare the size of two large integer variables (you need to judge their size when subtracting)

//Compare the size of two large bign variables
int cmp(bign a, bign b) {
    if (a.len > b.len) return 1;
    else if(a.len < b.len) return -1;
    else {
        for (int i = a.len - 1; i >= 0; i--) {
            if (a.d[i] > b.d[i]) return 1;    //As long as one a is big, a is big
            else if (a.d[i] < b.d[i]) return -1;    //As long as one a is small, a is small
        }
        return 0;    //Two numbers are equal
    }
}

 4. Output of large integers

void print(bign a) {    //Output bign
    for (int i = a.len - 1; i >= 0; i--) {
        printf("%d", a.d[i]);
    }
    printf("\n");
}

 5. High precision addition

Taking 147 + 65 as an example, let's review how we learned how to add two integers in primary school

① 7 + 5 = 12, take the single digit 2 as the result of this bit, and take the ten digit 1 carry

② 4 + 6 = 10, plus carry 1 is 11, take single digit 1 as the result of this bit, and take ten digit 1 carry

③ 1 + 0 = 1, plus carry 1 is 2, take the single digit 2 as the result of this bit, because the ten digit is 0, there is no carry

This can be summarized as follows: add the two numbers at this position, take the single digit as the result of this bit, and take the ten digits as the new carry. The method of high-precision addition is exactly the same as that of the second. You can see the code

//High precision addition
bign add(bign a, bign b) {
    bign c;
    int carry = 0;//carry
    for (int i = 0; i < a.len || i < b.len; i++) {
        int temp = a.d[i] + b.d[i] + carry;    //Add two corresponding carry
        c.d[c.len++] = temp % 10;    //The single digit is the result of this bit
        carry = temp / 10;    //Ten digits are new ones
    }
    if (carry != 0) {    //If 0 is assigned to the last bit, the carry result is not assigned directly
        c.d[c.len++] = carry;
    }
    return c;
}

 6. High precision subtraction

Take 145 - 67 , as an example, let's review how we learned how to subtract two integers in primary school

 

① 5 - 7 < 0 is not enough to reduce, so borrow 1 from the high 4, so 4 minus 1 becomes 3, and the result of this bit is 15 - 7 = 8

② 3 - 6 < 0 is not enough to reduce, so continue to borrow 1 from the high 1, so 1 minus 1 becomes 1, and the result of this bit becomes 13 - 6 = 7

③ Both above and below are 0, end the calculation

This can be summarized as follows: compare the subtracted and subtracted positions from the low position. If it is not enough, subtract the high position of the subtracted position by 1, add 10 to the subtracted position, and then subtract directly if it is enough. In the last step, note that there may be redundant zeros after the high position, ignore them, but also ensure that the result has at least one digit. The code implementation is as follows

//High precision subtraction
bign sub(bign a, bign b) { // a - b
    bign c;
    for (int i = 0; i < a.len || i < b.len; i++) {  //Take the longer as the boundary
        if (a.d[i] < b.d[i]) {  //If not enough
            a.d[i + 1]--;   //Borrow from high position
            a.d[i] += 10;   //Current position plus 10
        }
        c.d[c.len++] = a.d[i] - b.d[i]; //The subtraction result is the current bit result
    }
    while (c.len - 1 >= 1 && c.d[c.len - 1] == 0) {
        c.len--;    //Remove the high-order 0 while retaining at least one lowest order
    }
    return c;
}

7. High precision and low precision multiplication

Let's take 147 * 35 as an example

① 7 * 35 = 245, take the single digit 5 as the bit result, and the high part 24 as the carry

② 4 * 35 = 140, add carry 24 to get 164, take a digit 4 as the bit result, and the high-order part 16 as the carry

③ 1 * 35 = 35, add the carry 16 to get 51, take the single digit 1 as the bit result, and the high-order part 5 as the carry

It can be concluded that it still starts from the low position and multiplies the corresponding position. The single bit of the multiplied result is the result of the current position, and the high part is used as a new carry (the multiplication carry may be more than one bit). The code is as follows

//High precision and low precision multiplication
bign multi(bign a, int b) {
    bign c;
    int carry = 0;  //carry
    for (int i = 0; i < a.len; i++) {
        int temp = a.d[i] * b + carry;
        c.d[c.len++] = temp % 10;   //Bits as the result of this bit
        carry = temp / 10;  //The high part is used as a new carry
    }
    while (carry != 0) {    //Unlike addition, multiplication may have more than one carry, so use while
        c.d[c.len++] = carry % 10;
        carry /= 10;
    }
    return c;
}

 8. High precision and low precision Division

Let's take 1234 / 7 as an example:

① compared with 7, 1 is not enough to divide, so the bit quotient is 0 and the remainder is 1

② The remainder 1 is combined with the new bit 2 to form 12. Compared with 12 and 7, it is enough to divide. The quotient is 1 and the remainder is 5

③ The remainder 5 is combined with the new bit 3 to form 53. Compared with 53 and 7, it is enough to divide, the quotient is 7, and the remainder is 4

④ The remainder 4 is combined with the new bit 4 to form 44. Compared with 44 and 7, it is enough to divide, the quotient is 6, and the remainder is 2

It can be concluded that: the remainder * 10 in the previous step is added to the bit of this step to obtain the temporary divisor of this step, and compare it with the divisor: if it is not enough to divide, the quotient of this bit is 0; If it is sufficient to divide, the quotient is the corresponding quotient, and the remainder is the corresponding remainder. In the last step, we should pay attention to that there may be redundant zeros in the high order, ignore them, but also ensure that the result has at least one digit

The code is as follows

//High precision and low precision Division
bign divide(bign a, int b, int& r) {
    bign c;
    c.len = a.len;  //Each digit of the divisor corresponds to each digit of the quotient, so the shilling length is equal
    for (int i = a.len - 1; i >= 0; i--) {
        r = r * 10 + a.d[i];
        if (r < b) c.d[i] = 0;  //Not enough division, this bit is 0
        else {
            c.d[i] = r / b; //merchant
            r = r % b;  //Get new remainder
        }
    }
    while (c.len - 1 >= 1 && c.d[c.len - 1] == 0) {
        c.len--;    //Remove the highest 0 while retaining the lowest
    }
    return c;
}

 9. Complete code

#define _CRT_SECURE_NO_WARINGS
#include <iostream>
#include <cstring>
using namespace std;

//Large integer structure
struct bign {
    int d[1000];
    int len;
    bign() {//Initialize structure
        memset(d, 0, sizeof(d));
        len = 0;
    }
};

//Enter a large integer
bign change(char str[]) {   //Convert integer to bign
    bign a;
    a.len = strlen(str);
    for (int i = 0; i < a.len; i++) {
        a.d[i] = str[a.len - 1 - i] - '0';//Reverse order assignment
    }
    return a;
}
//Compare the size of two large bign variables
int cmp(bign a, bign b) {
    if (a.len > b.len) return 1;
    else if(a.len < b.len) return -1;
    else {
        for (int i = a.len - 1; i >= 0; i--) {
            if (a.d[i] > b.d[i]) return 1;//As long as one a is big, a is big
            else if (a.d[i] < b.d[i]) return -1;//As long as one a is small, a is small
        }
        return 0;//Two numbers are equal
    }
}

void print(bign a) {    //Output bign
    for (int i = a.len - 1; i >= 0; i--) {
        printf("%d", a.d[i]);
    }
    printf("\n");
}

//High precision addition
bign add(bign a, bign b) {
    bign c;
    int carry = 0;//carry
    for (int i = 0; i < a.len || i < b.len; i++) {
        int temp = a.d[i] + b.d[i] + carry;//Add two corresponding carry
        c.d[c.len++] = temp % 10;//The single digit is the result of this bit
        carry = temp / 10;//Ten digits are new ones
    }
    if (carry != 0) {//If the last carry is not 0, it is directly assigned to the highest bit of the result
        c.d[c.len++] = carry;
    }
    return c;
}

//High precision subtraction
bign sub(bign a, bign b) { // a - b
    bign c;
    for (int i = 0; i < a.len || i < b.len; i++) {  //Take the longer as the boundary
        if (a.d[i] < b.d[i]) {  //If not enough
            a.d[i + 1]--;   //Borrow from high position
            a.d[i] += 10;   //Current position plus 10
        }
        c.d[c.len++] = a.d[i] - b.d[i]; //The subtraction result is the current bit result
    }
    while (c.len - 1 >= 1 && c.d[c.len - 1] == 0) {
        c.len--;    //Remove the high-order 0 while retaining at least one lowest order
    }
    return c;
}

//High precision and low precision multiplication
bign multi(bign a, int b) {
    bign c;
    int carry = 0;  //carry
    for (int i = 0; i < a.len; i++) {
        int temp = a.d[i] * b + carry;
        c.d[c.len++] = temp % 10;   //Bits as the result of this bit
        carry = temp / 10;  //The high part is used as a new carry
    }
    while (carry != 0) {    //Unlike addition, multiplication may have more than one carry, so use while
        c.d[c.len++] = carry % 10;
        carry /= 10;
    }
    return c;
}

//High precision and low precision Division
bign divide(bign a, int b, int& r) {
    bign c;
    c.len = a.len;  //Each digit of the divisor corresponds to each digit of the quotient, so the shilling length is equal
    for (int i = a.len - 1; i >= 0; i--) {
        r = r * 10 + a.d[i];
        if (r < b) c.d[i] = 0;  //Not enough division, this bit is 0
        else {
            c.d[i] = r / b; //merchant
            r = r % b;  //Get new remainder
        }
    }
    while (c.len - 1 >= 1 && c.d[c.len - 1] == 0) {
        c.len--;    //Remove the highest 0 while retaining the lowest
    }
    return c;
}

int main()
{
    char str1[1000], str2[1000];
    scanf("%s%s", str1, str2);
    bign a = change(str1);
	bign b = change(str2);
	printf("High precision addition:"); 
    print(add(a, b));	
    
    printf("High precision subtraction:");
    if(cmp(a, b) == -1) {	 
		printf("-");
		print(sub(b, a));
	}
    else print(sub(a, b));
		
	bign x = change(str1);
	int y;
	scanf("%s%d", str1, &y);
	printf("Multiplication of high precision and low precision:");
	print(multi(x, y));
	
	printf("High precision and low precision Division:");
	int r;
	print(divide(x, y, r));
	printf("remainder:%d", r);
}

 

 

 

Topics: C C++