Objective
We know that in mathematics, the size of the number is not the upper limit, but in the computer, due to the limit of word length, the computer can represent a limited range, when we calculate the smaller number, such as: 1234+5678, such a number does not exceed the scope of the computer's representation, so it can be computed. But when we do a lot of data processing in the actual application, it is found that the number of participating operations often exceeds the representation of the basic data type of the computer, for example, if, in astronomy, a planet is 1 million light-years away, then we will simplify it to a kilometer, or a meter, We will find that this is a very large number. The computer will not be able to calculate it directly.
Perhaps we think that the actual application of the large number is only hundreds of digits, in fact, in some areas, even millions of-bit data can be calculated, which is difficult to imagine. If there is no computer, then the computational efficiency is conceivable.
Because the basic numeric data type provided by the programming language has a limited range of numerical values and can not meet the large-scale high precision numerical computation, it is necessary to use other methods to realize the high precision numerical calculation, so the large number operation is produced. This project realizes the addition and subtraction operation of large number operation.
I. Questions raised
Implement a large integer calculator in C language. Initial requirements support the addition and subtraction operations of large integers, such as 8888888888888+1112=8888888890000 or 1000000000000-999999999999=1.
In C, integer variables can store the widest data of 0xFFFF FFFF, the corresponding unsigned number is 4294967295, that is, can not save more than 10-bit integers. Note that here "10 digits" refers to 10 digits in mathematics, not 10 bits in computer science. Floating-point type double although you can store integers with more digits, the constant literal width is limited by the compiler and, on the other hand, the integer precision is handled in a floating-point manner. For example:
Double A = 1377083362513770833626.0, b=1585054852315850548524.0;
printf ("res =%.0f\n", a+b);
Output is res = 2962138214829621510144
, and the correct value should be 2962138214829621382150.
Since the basic data type cannot represent large integers, you can only design the storage mode to implement the representation and operation of large integers. Typically, the large integer entered is a string. Therefore, the common idea is to convert large integer strings into arrays, and then to simulate large integer operations with an array. In particular, the sequence of numeric characters in a string is first stored in a larger integer array whose elements represent one or several bits of an integer (such as the Universal), and then the array elements are manipulated to simulate integer operations based on the operational rules, and finally the array elements are sequentially exported.
The array method is easy to operate and easy to implement, and the disadvantage is that the space utilization and execution efficiency are not high. You can also directly manipulate large integer strings and reverse them from the end of a string. This is the way this article is implemented.
Two. Code implementation
First, a few macro definitions and operational structures are given:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Add_thres ( sizeof ("4294967295")-2)//Two 9-bit integer addition does not overflow
#define Mul_thres (sizeof ("65535")-2) //Two 4-bit integer multiplication does not overflow
# Define Oth_thres (sizeof ("4294967295")-1)//Two 10-bit integer subtraction or division does not overflow the
typedef struct{
char *leftval;
char *rightval;
char operator;
} Math_oper;
Based on the above definition, the following will be followed by the implementation of the Operation code.
The addition operation focuses on the carry problem in the additive process:
void addition (char *leftval, Char *rightval, char *resbuf, unsigned int resbuflen) {unsigned int leftlen = Strl
En (Leftval);
unsigned int rightlen = strlen (rightval); unsigned char Isleftlonger = (leftlen>=rightlen)?
1:0; unsigned int longlen = Isleftlonger?
Leftlen:rightlen; if (Resbuflen < Longlen) {//possible carry + string Terminator fprintf (stderr, "not enough spaces for result (cur:%u)
!\n ", Resbuflen);
Return } char *longaddend = Isleftlonger?
Leftval:rightval; Char *shortaddend = Isleftlonger?
Rightval:leftval; unsigned int difflen = Isleftlonger?
(Leftlen-rightlen): (Rightlen-leftlen); A carry might is generated from adding the most significant digit if ((Leftlen = Rightlen) && (leftval[0]-' 0 ' +
rightval[0]-' 0 ' >= 9)) Resbuf + + + 1;
unsigned int carry = 0;
int i = longLen-1;
for (; I >= 0; i--) {unsigned int leftaddend = longaddend[i]-' 0 '; unsigned int rightaddend = (i<difflen)? 0:shortaddend[i-difflen]-' 0 ';
unsigned int digitsum = leftaddend + rightaddend + carry;
Resbuf[i] = digitsum% 10 + ' 0 '; carry = (Digitsum >= 10)?
1:0;
} if (carry = = 1) {resbuf = 1;
Resbuf[0] = ' 1 ';
else if (leftval[0]-' 0 ' +rightval[0]-' 0 ' = 9) {resbuf = 1; Resbuf[0] = '; Fail to generate a carry}}
Note that the processing of line 33rd to 36th, when the highest bit is not expected to produce the carry, the original 0 resbuf[0] was placed as a space character, otherwise it will not output the results of the operation. Of course, you can also move the resbuf whole forward one element.
Subtraction is relatively complex, and the order of operations needs to be adjusted based on Bing and meiosis. If the meiosis is less than the meiosis ("11-111" or "110-111"), then the swap is followed by the normal subtraction after meiosis, and the result needs to be prefixed with a minus sign. In addition, attention should also be paid to borrow issues.
void Subtraction (char *leftval, Char *rightval, char *resbuf, unsigned int resbuflen) {int cmpval = strcmp (le
Ftval, Rightval);
if (!cmpval) {resbuf[0] = ' 0 ';
Return
} unsigned int leftlen = strlen (leftval);
unsigned int rightlen = strlen (rightval);
unsigned char isleftlonger = 0; if ((Leftlen > Rightlen) | |
100-10 (Leftlen = = Rightlen && cmpval > 0))//100-101 Isleftlonger = 1; unsigned int longlen = Isleftlonger?
Leftlen:rightlen; if (Resbuflen <= longlen) {//string Terminator fprintf (stderr, "not enough spaces for result (cur:%u)!\n", Resbuflen)
;
Return } char *minuend = Isleftlonger?
Leftval:rightval; Char *subtrahend = Isleftlonger?
Rightval:leftval; unsigned int difflen = Isleftlonger?
(Leftlen-rightlen): (Rightlen-leftlen);
A borrow would be generated from subtracting the most significant digit if (!isleftlonger) {resbuf[0] = '-';
Resbuf + 1; } unsigned int borrow= 0;
int i = longLen-1; for (; I >= 0; i--) {unsigned int expansubtrahend = (i<difflen)?
' 0 ': Subtrahend[i-difflen];
int digitdif = minuend[i]-Expansubtrahend-borrow; Borrow = (Digitdif < 0)?
1:0;
Resbuf[i] = digitdif + borrow*10 + ' 0 ';
printf ("[%d]dif=%d=%c-%c-%d->%c\n", I, Digitdif, Minuend[i], expansubtrahend, Borrow, resbuf[i]);
}//strip leading ' 0 ' characters int isrc = 0, idst = 0, isstripped = 0;
while (Resbuf[isrc]!= ' i ') {if (isstripped) {RESBUF[IDST] = resbuf[isrc]; isrc++;
idst++;
else if (resbuf[isrc]!= ' 0 ') {RESBUF[IDST] = resbuf[isrc]; isrc++;
idst++;
isstripped = 1;
else isrc++;
} RESBUF[IDST] = '; }
for addition ()
and subtraction ()
functions, design test cases as follows:
#include <assert.h> #define ASSERT_ADD (_ADD1, _ADD2, _sum) do{\ char resbuf[100] = {0}; \ addition (_ADD1, _ADD2, Resbuf, sizeof (RESBUF)); ASSERT (!STRCMP (resbuf, _sum)); \}while (0) #define ASSERT_SUB (_minu, _subt, _dif) do{\ char resbuf[100] = {0}; \ subtraction (_minu, _subt, Resbuf, si Zeof (RESBUF)); ASSERT (!STRCMP (resbuf, _dif));
\}while (0) void verifyoperation (void) {Assert_add ("22", "1686486458", "1686486480");
Assert_add ("8888888888888", "1112", "8888888890000");
Assert_add ("1234567890123", "1", "1234567890124");
Assert_add ("1234567890123", "3333333333333", "4567901223456");
Assert_add ("1234567890123", "9000000000000", "10234567890123");
Assert_add ("1234567890123", "8867901223000", "10102469113123");
Assert_add ("1234567890123", "8000000000000", "9234567890123");
Assert_add ("1377083362513770833626", "1585054852315850548524", "2962138214829621382150");
Assert_sub ("10012345678890", "1", "10012345678889"); Assert_sub ("1", "10012345678890"),"-10012345678889");
Assert_sub ("10012345678890", "10012345678891", "-1");
Assert_sub ("10012345678890", "10012345686945", "-8055");
Assert_sub ("1000000000000", "999999999999", "1"); }
The
takes into account that the computational efficiency of the language built-in should be higher, so as to choose the built-in operations when overflow is not possible. The calcoperation ()
function uses this idea:
void Calcoperation (Math_oper *mathoper, char *resbuf, unsigned int resbuflen) {unsigned int leftlen = strlen (mathoper-
>leftval);
unsigned int rightlen = strlen (mathoper->rightval);
Switch (mathoper->operator) {case ' + ': if (leftlen <= add_thres && rightlen <= add_thres)
snprintf (Resbuf, Resbuflen, "%d", atoi (mathoper->leftval) + atoi (mathoper->rightval));
else addition (Mathoper->leftval, Mathoper->rightval, Resbuf, Resbuflen);
Break
Case '-': if (leftlen <= oth_thres && rightlen <= oth_thres) snprintf (Resbuf, Resbuflen, "%d",
Atoi (Mathoper->leftval)-atoi (Mathoper->rightval));
else subtraction (Mathoper->leftval, Mathoper->rightval, Resbuf, Resbuflen);
Break
Case ' * ': if (leftlen <= mul_thres && rightlen <= mul_thres) snprintf (Resbuf, Resbuflen, "%d", Atoi (Mathoper->leftVal) * Atoi (mathoper->rightval)); else break;
multiplication:product = multiplier * Multiplicand break;
Case '/': if (leftlen <= oth_thres && rightlen <= oth_thres) snprintf (Resbuf, Resbuflen, "%d",
Atoi (Mathoper->leftval)/atoi (mathoper->rightval)); else break;
Division:quotient = Dividend/divisor break;
Default:break;
} return; }
Note that the multiplication and division operations for large integers have not yet been implemented, so the corresponding code branches are returned directly.
Finally, complete the entry function:
int main (void) {
verifyoperation ();
Char leftval[100] = {0}, rightval[100] = {0}, operator= ' + ';
Char resbuf[1000] = {0};
As for you, basically any key can quit:
printf ("Enter Math expression (press Q to quit):");
while (scanf ("%[0-9]%[+-*/]%[0-9]", Leftval, &operator, rightval) = = 3) {Math_oper Mathoper
= {leftval, Rightva l, operator};
memset (resbuf, 0, sizeof (RESBUF));
Calcoperation (&mathoper, Resbuf, sizeof (RESBUF));
printf ("%s%c%s =%s\n", Leftval, Operator, Rightval, resbuf);
printf ("Enter Math expression (press Q to quit):");
}
return 0;
}
In the preceding code, scanf()
a function's formatted string style resembles a regular expression. It details see the article "Sscanf string formatting usage."
Three. Effect verification
Save the previous section code as a BigIntOper.c
file. The test results are as follows:
[Wangxiaoyuan_@localhost ~]$ Gcc-wall-o bigintoper bigintoper.c
[wangxiaoyuan_@localhost ~]$./BigIntOper
Enter Math expression (press Q to quit): 100+901
+ 901 = 1001
Enter math expression (press Q to quit): 100-9
100-9 =
expression Enter math (press Q to quit): 1234567890123 + 8867901223000
1234567890123 + 8867901223000 = 10102469113123
Enter Math expression (press Q to quit): 1377083362513770833626-1585054852315850548524
1377083362513770833626-1585054852315850548524 = -207971489802079714898
Enter Math expression (press Q to quit): Q
Through internal test Cases and external manual verification, the results of the operation are accurate.
Summarize
The above is the C language to achieve large integer addition and subtraction operation of the entire content, we have learned it? I hope the content of this article for everyone to learn C language can help.