1.代码思路
在我们做加法时,一定是先把他们的最后一位对齐,然后从最后一位数开始相加,如果相加的结果大于9,那么就在前一位加好的基础上再加1
2.代码详解
2.1 完整代码
#include <iostream>
#include <cstring>
using namespace std;
int addzero(char one[], char two[], int lenone, int lentwo);
int main() {
int a = 0, num = 0, addone = 0, max = 0, min = 0, b = 0;
static char one[1001];
static char two[1001];
gets(one);
gets(two);
int lenone = strlen(one);
int lentwo = strlen(two);
addzero(one, two, lenone, lentwo);
lenone=strlen(one);
lentwo=strlen(two);
int f[lentwo];
int k=lentwo-1;
for (int i = lenone - 1; i >= 0; i--) {
num = int(one[i]) - 48 + int(two[i]) - 48 + a;
if (num > 9) {
num = num - 10;
a = 1;
}
else {
a = 0;
}
f[k]=num;
k--;
if (i==1 && a==1){
b=0;
}
if (i==1 && a==0){
b=1;
}
}
k=lentwo;
for (int i=b;i<k;i++){
cout << f[i];
}
return 0;
}
int addzero(char one[], char two[], int lenone, int lentwo) {
char b=0;
int zero=0;
if (lenone==lentwo){
for (int i=1;i <= lenone;i++) {
b=one[lenone-i];
one[lenone-i+1] = b;
}
one[0] = '0';
for (int i=1;i <= lentwo;i++) {
b=two[lentwo-i];
two[lentwo-i+1] = b;
}
two[0] = '0';
b=0;
}
if (lenone>lentwo){
for (int i=1;i <= lenone;i++){
b=one[lenone-i];
one[lenone-i+1] = b;
}
one[0] = '0';
for (int i=1;i <= lentwo;i++){
b=two[lentwo-i];
two[lentwo-i+(lenone-lentwo)+1] = b;
zero=lenone-lentwo;
}
for (int i=zero;i>=0;i--){
two[i]='0';
}
b=0,zero=0;
}
if (lentwo>lenone){
for (int i=1;i <= lentwo;i++){
b=two[lentwo-i];
two[lentwo-i+1] = b;
}
two[0] = '0';
for (int i=1;i <= lenone;i++){
b=one[lenone-i];
one[lenone-i+(lentwo-lenone)+1] = b;
zero=lentwo-lenone;
}
for (int i=zero;i>=0;i--){
one[i]='0';
}
b=0,zero=0;
}
return 0;
}
2.2 addzero函数
先来解释一下b和zero这两个变量的含义:b用于将数组整体向后移动时记录数组数字的变量,同时方便像新手解释
zero用于记录要往这个数组中添加多少个0
,,
if (lenone==lentwo){
for (int i=1;i <= lenone;i++) {
b=one[lenone-i];
one[lenone-i+1] = b;
}
one[0] = '0';
for (int i=1;i <= lentwo;i++) {
b=two[lentwo-i];
two[lentwo-i+1] = b;
}
two[0] = '0';
b=0;
}
当两个加数长度相等时,我们要在这两个加数的前面个加上一个'0'
我们用b来记录我们要移动的那一位,然后将b赋值给原本b的后面一位。
下面我来模拟一下(两个加数长度相同时):
one = [143]
two = [714]
lenone = 3
lentwo = 3
第一次循环:
b = one[lenone - i] = one[3 - 1] = one[2] = 3
one = [1433]
第二次循环:
b = one[lenone - i] = one[3 - 2] = one[1] = 4
one = [1443]
第三次循环:
b = one[lenone - i] = one[3 - 3] = one[0] = 1
one = [1143]
循环结束
one[0] = '0'
one = [0143]
这样第一个加数添加'0'的步骤就完成了,第二个加数同理
if (lenone>lentwo){
for (int i=1;i <= lenone;i++){
b=one[lenone-i];
one[lenone-i+1] = b;
}
one[0] = '0';
for (int i=1;i <= lentwo;i++){
b=two[lentwo-i];
two[lentwo-i+(lenone-lentwo)+1] = b;
zero=lenone-lentwo;
}
for (int i=zero;i>=0;i--){
two[i]='0';
}
b=0,zero=0;
}
当第一个加数的长度大于第二个加数的长度时,第一个加数还是像刚才一样在最前面加上一个'0',就不过多解释了。
我们来看第二个加数,我们还是把要向后移的那一位赋值给b,至于向后多少位,我们并不能知道确切的数字,但为了保持加完'0'之后两个加数的长度相同,所以除了向后移一位,还要再向后移两个加数长度差位,移动完成后,zero储存的值是两个加数的长度差。这样说可能不太容易理解,我来给大家示范一下:
第一个加数的移动就不过多演示了,我们来看第二个加数
one = [5262]
two = [153]
lenone = 4
lentwo = 3
第一次循环:
b = two[lentwo - i] = two[3 - 1] = two[2] = 3
lentwo - i + (lenone - lentwo) + 1 = 3 - 1 + 1 + 1 = 4
153 3
第二次循环:
b = two[lentwo - i] = two[3 - 2] = two[1] = 5
lentwo - i + (lenone - lentwo) + 1 = 3 - 2 + 1 + 1 = 3
15353
第三次循环:
b = two[lentwo - i] = two[3 - 3] = two[0] = 1
lentwo - i + (lenone - lentwo) + 1 = 3 - 3 + 1 + 1 = 2
15153
循环结束
zero = lenone - lentwo = 4 - 3 = 1
下一个循环:
第一次循环:
two[i](two[1]) = '0'
10153
第二次循环:
two[i](two[0]) = '0'
00153
循环结束
假设one数组我们也添加好'0'了,现在两个数组变成了这样:
one = [05262]
two = [00153]
if (lentwo>lenone){
for (int i=1;i <= lentwo;i++){
b=two[lentwo-i];
two[lentwo-i+1] = b;
}
two[0] = '0';
for (int i=1;i <= lenone;i++){
b=one[lenone-i];
one[lenone-i+(lentwo-lenone)+1] = b;
zero=lentwo-lenone;
}
for (int i=zero;i>=0;i--){
one[i]='0';
}
b=0,zero=0;
}
同理,这一段代码与上一段极为相似,只是把所有的'one'替换成了'two','two'替换成了'one'
2.3 main函数
int main() {
int a = 0, num = 0, addone = 0, max = 0, min = 0, b = 0;
static char one[1001];
static char two[1001];
gets(one);
gets(two);
int lenone = strlen(one);
int lentwo = strlen(two);
addzero(one, two, lenone, lentwo);
lenone=strlen(one);
lentwo=strlen(two);
int f[lentwo];
int k=lentwo-1;
for (int i = lenone - 1; i >= 0; i--) {
num = int(one[i]) - 48 + int(two[i]) - 48 + a;
if (num > 9) {
num = num - 10;
a = 1;
}
else {
a = 0;
}
f[k]=num;
k--;
if (i==1 && a==1){
b=0;
}
if (i==1 && a==0){
b=1;
}
}
k=lentwo;
for (int i=b;i<k;i++){
cout << f[i];
}
return 0;
}
这些变量在后续使用的时候会做讲解。static的作用是让它在两个函数中均可使用。
lenone和lentwo储存的是这两个数组的长度,然后调用addzero函数进行预处理。f数组储存最后的计算结果。
下面我们来看main函数中最主要的循环:
for (int i = lenone - 1; i >= 0; i--) {
num = int(one[i]) - 48 + int(two[i]) - 48 + a;
if (num > 9) {
num = num - 10;
a = 1;
}
else {
a = 0;
}
f[k]=num;
k--;
if (i==1 && a==1){
b=0;
}
if (i==1 && a==0){
b=1;
}
}
(注意:此时我们已经完成预处理,现在两个加数的长度相等)
首先,你应该知道,在进行加法运算时是从最后一位开始计算,所以这个循环的循环变量的初识值为加数最后一位的下标数(即lenone - 1),我们必须要计算到这两个加数的最后一位,所以当i = -1的时候就退出循环,每一次计算完成以后就要计算前一位,所以i递减(即i--)
先问大家一个问题:int('0')和int 0有什么区别?
'0'是一个字符,可以理解成整数:48,每一个字符都会有它们对应的整数,称为ACSII码(淡黄色背景为控制字符,白色背景为可显示字符):
二进制 | 十进制 | 十六进制 | 字符/缩写 | 解释 |
---|---|---|---|---|
00000000 | 0 | 00 | NUL (NULL) | 空字符 |
00000001 | 1 | 01 | SOH (Start Of Headling) | 标题开始 |
00000010 | 2 | 02 | STX (Start Of Text) | 正文开始 |
00000011 | 3 | 03 | ETX (End Of Text) | 正文结束 |
00000100 | 4 | 04 | EOT (End Of Transmission) | 传输结束 |
00000101 | 5 | 05 | ENQ (Enquiry) | 请求 |
00000110 | 6 | 06 | ACK (Acknowledge) | 回应/响应/收到通知 |
00000111 | 7 | 07 | BEL (Bell) | 响铃 |
00001000 | 8 | 08 | BS (Backspace) | 退格 |
00001001 | 9 | 09 | HT (Horizontal Tab) | 水平制表符 |
00001010 | 10 | 0A | LF/NL(Line Feed/New Line) | 换行键 |
00001011 | 11 | 0B | VT (Vertical Tab) | 垂直制表符 |
00001100 | 12 | 0C | FF/NP (Form Feed/New Page) | 换页键 |
00001101 | 13 | 0D | CR (Carriage Return) | 回车键 |
00001110 | 14 | 0E | SO (Shift Out) | 不用切换 |
00001111 | 15 | 0F | SI (Shift In) | 启用切换 |
00010000 | 16 | 10 | DLE (Data Link Escape) | 数据链路转义 |
00010001 | 17 | 11 | DC1/XON (Device Control 1/Transmission On) | 设备控制1/传输开始 |
00010010 | 18 | 12 | DC2 (Device Control 2) | 设备控制2 |
00010011 | 19 | 13 | DC3/XOFF (Device Control 3/Transmission Off) | 设备控制3/传输中断 |
00010100 | 20 | 14 | DC4 (Device Control 4) | 设备控制4 |
00010101 | 21 | 15 | NAK (Negative Acknowledge) | 无响应/非正常响应/拒绝接收 |
00010110 | 22 | 16 | SYN (Synchronous Idle) | 同步空闲 |
00010111 | 23 | 17 | ETB (End of Transmission Block) | 传输块结束/块传输终止 |
00011000 | 24 | 18 | CAN (Cancel) | 取消 |
00011001 | 25 | 19 | EM (End of Medium) | 已到介质末端/介质存储已满/介质中断 |
00011010 | 26 | 1A | SUB (Substitute) | 替补/替换 |
00011011 | 27 | 1B | ESC (Escape) | 逃离/取消 |
00011100 | 28 | 1C | FS (File Separator) | 文件分割符 |
00011101 | 29 | 1D | GS (Group Separator) | 组分隔符/分组符 |
00011110 | 30 | 1E | RS (Record Separator) | 记录分离符 |
00011111 | 31 | 1F | US (Unit Separator) | 单元分隔符 |
00100000 | 32 | 20 | (Space) | 空格 |
00100001 | 33 | 21 | ! | |
00100010 | 34 | 22 | " | |
00100011 | 35 | 23 | # | |
00100100 | 36 | 24 | $ | |
00100101 | 37 | 25 | % | |
00100110 | 38 | 26 | & | |
00100111 | 39 | 27 | ' | |
00101000 | 40 | 28 | ( | |
00101001 | 41 | 29 | ) | |
00101010 | 42 | 2A | * | |
00101011 | 43 | 2B | + | |
00101100 | 44 | 2C | , | |
00101101 | 45 | 2D | - | |
00101110 | 46 | 2E | . | |
00101111 | 47 | 2F | / | |
00110000 | 48 | 30 | 0 | |
00110001 | 49 | 31 | 1 | |
00110010 | 50 | 32 | 2 | |
00110011 | 51 | 33 | 3 | |
00110100 | 52 | 34 | 4 | |
00110101 | 53 | 35 | 5 | |
00110110 | 54 | 36 | 6 | |
00110111 | 55 | 37 | 7 | |
00111000 | 56 | 38 | 8 | |
00111001 | 57 | 39 | 9 | |
00111010 | 58 | 3A | : | |
00111011 | 59 | 3B | ; | |
00111100 | 60 | 3C | < | |
00111101 | 61 | 3D | = | |
00111110 | 62 | 3E | > | |
00111111 | 63 | 3F | ? | |
01000000 | 64 | 40 | @ | |
01000001 | 65 | 41 | A | |
01000010 | 66 | 42 | B | |
01000011 | 67 | 43 | C | |
01000100 | 68 | 44 | D | |
01000101 | 69 | 45 | E | |
01000110 | 70 | 46 | F | |
01000111 | 71 | 47 | G | |
01001000 | 72 | 48 | H | |
01001001 | 73 | 49 | I | |
01001010 | 74 | 4A | J | |
01001011 | 75 | 4B | K | |
01001100 | 76 | 4C | L | |
01001101 | 77 | 4D | M | |
01001110 | 78 | 4E | N | |
01001111 | 79 | 4F | O | |
01010000 | 80 | 50 | P | |
01010001 | 81 | 51 | Q | |
01010010 | 82 | 52 | R | |
01010011 | 83 | 53 | S | |
01010100 | 84 | 54 | T | |
01010101 | 85 | 55 | U | |
01010110 | 86 | 56 | V | |
01010111 | 87 | 57 | W | |
01011000 | 88 | 58 | X | |
01011001 | 89 | 59 | Y | |
01011010 | 90 | 5A | Z | |
01011011 | 91 | 5B | [ | |
01011100 | 92 | 5C | \ | |
01011101 | 93 | 5D | ] | |
01011110 | 94 | 5E | ^ | |
01011111 | 95 | 5F | _ | |
01100000 | 96 | 60 | ` | |
01100001 | 97 | 61 | a | |
01100010 | 98 | 62 | b | |
01100011 | 99 | 63 | c | |
01100100 | 100 | 64 | d | |
01100101 | 101 | 65 | e | |
01100110 | 102 | 66 | f | |
01100111 | 103 | 67 | g | |
01101000 | 104 | 68 | h | |
01101001 | 105 | 69 | i | |
01101010 | 106 | 6A | j | |
01101011 | 107 | 6B | k | |
01101100 | 108 | 6C | l | |
01101101 | 109 | 6D | m | |
01101110 | 110 | 6E | n | |
01101111 | 111 | 6F | o | |
01110000 | 112 | 70 | p | |
01110001 | 113 | 71 | q | |
01110010 | 114 | 72 | r | |
01110011 | 115 | 73 | s | |
01110100 | 116 | 74 | t | |
01110101 | 117 | 75 | u | |
01110110 | 118 | 76 | v | |
01110111 | 119 | 77 | w | |
01111000 | 120 | 78 | x | |
01111001 | 121 | 79 | y | |
01111010 | 122 | 7A | z | |
01111011 | 123 | 7B | { | |
01111100 | 124 | 7C | | | |
01111101 | 125 | 7D | } | |
01111110 | 126 | 7E | ~ | |
01111111 | 127 | 7F | DEL (Delete) | 删除 |
继续回到循环,用两个加数的最后一位进行相加,得到的结果赋值给num。但是这里有一个地方要注意,我们创建的数组是字符类型,把字符转换成数字就是它的ASCII码,但0的ASCII码不是0,是48,所以在获取最后一位的时候要减去48(也可以写成-'0'):
num = int(one[i]) - 48 + int(two[lentwo - j]) - 48 + a;
之后判断num是不是大于9,因为如果大于9,就需要进位。如果需要进位,那么让num-10,也就是只保留个位,并让a=1,这里a的作用是判断是否要进位,所以如果仔细看到话,在给num赋值时,最后加上了a;如果不需要进位,那么a=0,num不变。
既然算完了,那么就要把结果储存起来,在预处理之后,k=lentwo-1,也就是f数组最后一位的下标数,把我们计算的结果填在f数组的最后,k递减。b的作用会在输出时介绍。
k=lentwo;
for (int i=b;i<k;i++){
cout << f[i];
}
现在f数组储存的结果就是代码计算的结果了,我们先把lenone或lentwo赋值给k,因为在循环中k被递减,最后为0,所以需要重新赋值。下面要一个循环来输出。b的作用是在循环的最后一遍检测它是不是0。如果不是0(也就是第二位要进位,预留出的0被改成了1),那么b=0,从f数组的第一位开始输出;如果是0(也就是第二位没有进位,预留出的0没有进行改动),那么b=1,从f数组的第一位开始输出,因为第一位是0,会影响美观。
至此,C++大整数加法的代码就分享完了,后续还会分享其他大整数运算的代码,敬请期待。