计算机考研复试真题 大数问题之大数相加、相乘。
博客转自:https://blog.csdn.net/hacker00011000/article/details/51298294 若侵权告知立删!
1. 大数相加
1、从结尾开始每位相加
2、两个整数长度不相等(肯定有一个已经加完了,再把没有加完的加上去)
3、最高位有进位,要再进一位
4、结果字符串逆序
2. 大数相乘
- 分析
12*34=?
乘数:12
被乘数:34
1、先把乘数列出来,第i行列左起第i位数,列N次(N为乘数的位数)
第二行起每次右移一位
(1) (1) (2) (2)
2、写入被乘数,按先列后行的方式
(1,3) (1,4) (2,3) (2,4)
3、将()内的数两乘
(1,3=3) (1,4=4) (2,3=6) (2,4=8)
4、相加,注意进位
(1,3=3) (1,4=4) (2,3=6) (2,4=8) ------------------------- 3 10 8 . ------------------------- 4 0 8 --------------------- 作者:silentsharer 来源:CSDN 原文:https://blog.csdn.net/hacker00011000/article/details/51298294 版权声明:本文为博主原创文章,转载请附上博文链接!
12*34=408
再看三位数乘法
123*456=?
第一步:
(1) (1) (1) (2) (2) (2) (3) (3) (3)
第二步:
(1,4) (1,5) (1,6) (2,4) (2,5) (2,6) (3,4) (3,5) (3,6)
第三步:
(1,4= 4) (1,5= 5) (1,6= 6) (2,4= 8) (2,5=10) (2,6=12) (3,4=12) (3,5=15) (3,6=18)
第四步:
(1,4= 4) (1,5= 5) (1,6= 6) (2,4= 8) (2,5=10) (2,6=12) (3,4=12) (3,5=15) (3,6=18) ---------------------------------------------- 4 13 28 27 18 . . . . ---------------------------------------------- 5 6 0 8 8 ---------------------
123*456=56088
分析一下每一位的值是如何计算出来的,以下说的位都是从个位算起:
结果的第i位,是乘数的第i位乘以被乘数的1位,再加上乘数的第i-1位乘以被乘数的第2位,一起加到乘数的第1位乘以被乘数的第i位。
这样描述起来有点不明白,画个图就很清楚了:
123*456的第3位:从乘数的第3位(1)起到第1位(3),按从右向左的方式
逐个乘以被乘数:
1*6+2*5+3*4=28
再把进位加上就可以了。
即:计算结果的第i位(权值肯定为i,第1位也就是个位权值为0(pow(10, 0)))。等于乘数的第(i~0)位分别与被乘数的第(0~i)位相乘,因为这样每位相乘之后权值仍为i 。然后相加再加上前一位的进位,就是结果的第i位
到这里,已经可以得出一个通用的计算方法,把结果逐位计算出来。
通过上面的分析,我们知道了算法的核心思想,接下来就能把算法实现
程序代码:
#include <iostream> #include <sstream> #include <algorithm> #include <cstring> #include <string> using namespace std; //C++大数相加 string BigNumAdd(const string& strNum1, const string& strNum2) { string strSum; int len1 = strNum1.size()-1; int len2 = strNum2.size()-1; int bit = 0; //保存进位 //从结尾开始每位相加 while (len1>=0 && len2>=0) { //求每位的和(要把进位也加上) int tmpSum = strNum1[len1]-'0' + strNum2[len2]-'0' + bit; //保存进结果 strSum += tmpSum % 10 + '0'; //求进位 bit = tmpSum / 10; --len1; --len2; } //两个整数长度不相等(肯定有一个已经加完了,不需要再额外加if来判断,因为while就可以判断) while (len1 >= 0) { //和上个while循环一样 int tmpSum = strNum1[len1]-'0' + bit; strSum += tmpSum % 10 + '0'; bit = tmpSum / 10; --len1; } while (len2 >= 0) { //和上个while循环一样 int tmpSum = strNum2[len2]-'0' + bit; strSum += tmpSum % 10 + '0'; bit = tmpSum / 10; --len2; } //最高位有进位 if (bit != 0) strSum += bit + '0'; //反转 reverse(strSum.begin(), strSum.end()); return strSum; } //C++大数相乘 string BigNumMultiply(const string& strNum1, const string& strNum2) { string strMultiply; //两数相乘最大有m+n位 int bit = 0; int len1 = strNum1.size()-1; int len2 = strNum2.size()-1; //计算每一位 for (int i=0; i<len1+len2+2; ++i) { //计算结果的第i位(权值肯定为i,第1位也就是个位权值为0(pow(10, 0))) //等于乘数的第(i~0)位分别与被乘数的第(0~i)位相乘,因为这样每位相乘之后权值仍为i //然后相加再加上前一位的进位,就是结果的第i位 //然后%10得出第i位,/10得到进位 int tmp = 0; for (int j=i; j>=0; --j) { //如果下标超出字符串的范围 j为num1的下标, i-j为num2的下标,然后两数相乘 if (j>len1 || (i-j)>len2) continue; //还要注意字符串数字的最高位在字符串的最低位所以得用len减去 tmp += (strNum1[len1-j]-'0') * (strNum2[len2-(i-j)]-'0'); } //加上进位 tmp += bit; //为了防止最后一位是0,但是却加上了 if (tmp == 0 && i == len1+len2+1) break; //求余得到结果的第i位 strMultiply += tmp % 10 + '0'; //计算新的进位 bit = tmp / 10; } //判断结果的最后一个字符如果是0的话说明可以删去 //if (strMultiply[strMultiply.size()-1] == '0') // strMultiply[strMultiply.size()-1] = '\0'; //反转 reverse(strMultiply.begin(), strMultiply.end()); return strMultiply; } int main() { string str1; string str2; cin >> str1 >> str2; //相加和相乘 cout << BigNumAdd(str1, str2) << endl; cout << BigNumMultiply(str1, str2) << endl; int n; cin >> n; //阶乘 string rlt("1"); string opNum; for (int i=1; i<=n; ++i) { //ss不可以定义在for循环外 stringstream ss; ss << i; ss >> opNum; rlt = BigNumMultiply(rlt, opNum); } cout << rlt << endl; return 0; }