练习题——大数加法
大数指位数超长的数,以至于使用int(32,64)等C++语言内置数据类型已经不足以涵盖。
这里实现1000位的大数加法。
思路为将数保存成字符数组/字符串形式,按位模拟手工计算时的加法,
主要步骤为:
1)获取原数和加数的位数
2)如果位数相同不做处理,位数不同,则需要将小的数前补0对齐到大的数
(如 101 + 99,需要将99前补0对齐到101,
变成101+ 099)
3)从后至前,从左至右,按位相加处理进位
4)若最左边发生了进位,则视为溢出的情况,此时需要将结果整体右移一位,在左边补‘1’
代码实现:
测试代码:
//数组最大长度 const int MAX_LENGTH = 1000; //原数数组 char *primitiveStr = new char[MAX_LENGTH + 1]{}; //加数数组 char *addStr = new char[MAX_LENGTH + 1]{}; //结果数组 char *resultStr = new char[MAX_LENGTH + 1]{}; //原数长度 int primitiveLength = 0; //加数长度 int addLength = 0; //输入原数和加数 std::cin >> primitiveStr; std::cin >> addStr; //获取原数和加数数位 getLength(primitiveStr, addStr, &primitiveLength, &addLength); //按照数位差对齐 align(primitiveStr, addStr, primitiveLength, addLength); //按位相加并处理进位和左溢出 add(primitiveStr, addStr, primitiveLength, addLength, resultStr); //输出计算结果 std::cout << primitiveStr << " + " << addStr << " = " << resultStr << std::endl; //清除堆内存 delete primitiveStr[]; delete addStr[]; delete resultStr[]; primitiveStr = nullptr; addStr = nullptr; resultStr = nullptr;
获取原数和加数的数位的函数:
void getLength(char *pStr,char *aStr,int *pLength,int *aLength) { bool isNotEnd = true; int i = 0; while (isNotEnd) { //0也即'\0' if (pStr[i]!=0) { (*pLength)++; } if (aStr[i]!=0) { (*aLength)++; } if (pStr[i]==0&&aStr[i]==0) { isNotEnd = false; } i++; } }
对齐数位用到的函数:
void align(char *pStr,char *aStr,int pLength,int aLength) { int offset = pLength - aLength; //有位差且没逆序,将addStr对齐到primitiveStr if (offset>0) { //从末位开始,例如将101+99对齐到101+099 for (int i = pLength,j = 0; i > offset; i--,j++) { *(aStr + i) = *(aStr + aLength - j); } //补‘0’操作 for (int i = 0; i < offset;i++) { *(aStr + i) = '0'; } } //有位差且逆序,将primitiveStr对齐到addStr if (offset<0) { for (int i = aLength, j = 0; i > -offset;i--,j++) { *(pStr + i) = *(pStr + pLength - j); } for (int i = 0; i < -offset;i++) { *(pStr + i) = '0'; } } }
按位相加,并处理进位以及左溢出
void add(char* pStr,char* aStr,int pLength,int aLength,char* rStr) { int rLength = pLength > aLength ? pLength : aLength; //进位 int carry = 0; for (int i = rLength; i >= 0; i--) { //字符转数字 int primitiveNum = (int)(*(pStr+i) - '0'); int addNum = (int)(*(aStr+i) - '0'); int resultNum = primitiveNum + addNum + carry; //转字符存入结果数组 if (resultNum >= 10) { //有进位 carry = 1; *(rStr+i) = char((resultNum % 10) + '0'); } else { //无进位 carry = 0; *(rStr + i) = char(resultNum + '0'); } } //检查到上溢 if (carry==1) { //整体右移 for (int i = rLength; i > 0; i--) { *(rStr+i) = *(rStr+i - 1); } //左边补1 *(rStr+0) = '1'; } //用'\0'截断 *(rStr + rLength + 1) = '\0'; }