前面我写了一篇高精度加法的博客,但那个代码其实是有长度限制的,两个加数最多100位,再高一点就要修改宏定义,很不方便。所以我用c++又写了一遍加法,和乘法。上一篇->博客
这次用的是c++的string。使用很方便,但是写起来有点难理解。
高精加
还是分三步:①倒序输入,对齐个位;②相加,进位;③输出(由于string可以字符串相加,所以不需要倒序输出)。 原理跟上一篇的数组写法差不多。唯一有一点不同就是这次需要判断长短,人后给短的字符串补0,保证俩字符串长度相等,就不多赘述了。
上代码
string add(string str1, string str2, int len)
{
string ans;
int ret = 0;
for (int i = 0; i < len; i++)
{
if (ret == 1)
ret = 1 + str1[len - 1 - i] - '0' + str2[len - 1 - i] - '0';
else
ret = str1[len - 1 - i] - '0' + str2[len - 1 - i] - '0';
int tmp = ret / 10;
ret = ret % 10;
ans = char(ret + '0') + ans;
ret = 0;
if (tmp != 0)//判断是否需要进位
ret++;
}
if (ret == 1)
ans = char(1 + '0') + ans;//把int的1转换成字符的1,并加在字符串的前面
return ans;
}
细节处理好了还是没有什么问题的。
高精乘
这个要考虑的情况就比较多了:
(建议先看代码,再看注解)
①还是方便相乘,我们倒序输入,但是为了节(tou)省(lan),我直接写成了(str1[len1-1-i]-'0')*(str2[len2-1-i]-'0');
②进位,不在只有加1的情况,所以我们要把ret的存起来。然后直接相加
也就是ret+(str1[len1-1-i]-'0')*(str2[len2-1-i]-'0');代码跟上面差不多;
③两数相加,这里我调用了高精加的函数,原因在于:
④还有一些特殊情况:比如101*32,101中间的0其实是可以跳过计算的;还有0*32,直接输出0就可以了。
最后说一下乘法的整体思路:模拟竖式乘法,用两组循环对字符串当中的数两两相乘。并将第二次循环得到的字符串保留,调用高精加相加得到最终结果(数据范围可以满足10^2000)
上代码
string mul(string str1, string str2, int len1,int len2)
{
if (str1 == "0" || str2 == "0")//判断因数是否有0
return "0";
string too;
string ans;
ans += "0";
int ret = 0;//用于进位
int key = 0;//存储临时变量
int count = 0;//用于计算too补0的个数,例如第一次不需要补0,第二次补一个......
for (int i = 0; i < len1; i++)
{
step1:
for (int j = 0; j < len2; j++)
{
if (str1[len1 - 1 - i] == '0')
{
count++;
i++;
goto step1;//跳过数字中间有0(例如101)的情况
}
if (ret != 0)//需要进位
{
key = ret + (str1[len1 - 1 - i] - '0') * (str2[len2 - 1 - j] - '0');
ret = 0;
}
else
key = (str1[len1 - 1 - i] - '0') * (str2[len2 - 1 - j] - '0');
ret = key / 10;//判断是否需要进位
key = key % 10;
too = char(key + '0') + too;
}
if (ret != 0)
too = char(ret + '0') + too;
for (int i = 0; i < count; i++)
too = too + "0";
if (count == 0 || ans == "0")
ans = too;
else
{
int n = too.length() - ans.length();
while (n)
{
ans = "0" + ans;//在ans前补0,保证俩字符串长度相等
n--;
}
ans = add(ans, too, too.length());
}
count++;
ret = 0;
too = too.erase(0, too.length());//清空too,方便下一次计算。
}
return ans;
}
有点繁琐,个人能力有限大家不要介意哈~
我的方法绝对不是最简单的,但是大家可以通过看懂我的代码写出更精简的方案来,我自己也是从这次做题中学到了不少c++的知识,我坚信有一天当我熟练的写高精的时候我的代码一定非常优秀。下面附上我的全部代码,希望与诸君共勉
全部代码
#include<string>
#include<iostream>
using namespace std;
string add(string str1, string str2, int len)
{
string ans;
int ret = 0;
for (int i = 0; i < len; i++)
{
if (ret == 1)
ret = 1 + str1[len - 1 - i] - '0' + str2[len - 1 - i] - '0';
else
ret = str1[len - 1 - i] - '0' + str2[len - 1 - i] - '0';
int tmp = ret / 10;
ret = ret % 10;
ans = char(ret + '0') + ans;
ret = 0;
if (tmp != 0)//判断是否需要进位
ret++;
}
if (ret == 1)
ans = char(1 + '0') + ans;//把int的1转换成字符的1,并加在字符串的前面
return ans;
}
string mul(string str1, string str2, int len1,int len2)
{
if (str1 == "0" || str2 == "0")//判断因数是否有0
return "0";
string too;
string ans;
ans += "0";
int ret = 0;//用于进位
int key = 0;//存储临时变量
int count = 0;//用于计算too补0的个数,例如第一次不需要补0,第二次补一个......
for (int i = 0; i < len1; i++)
{
step1:
for (int j = 0; j < len2; j++)
{
if (str1[len1 - 1 - i] == '0')
{
count++;
i++;
goto step1;//跳过数字中间有0(例如101)的情况
}
if (ret != 0)//需要进位
{
key = ret + (str1[len1 - 1 - i] - '0') * (str2[len2 - 1 - j] - '0');
ret = 0;
}
else
key = (str1[len1 - 1 - i] - '0') * (str2[len2 - 1 - j] - '0');
ret = key / 10;//判断是否需要进位
key = key % 10;
too = char(key + '0') + too;
}
if (ret != 0)
too = char(ret + '0') + too;
for (int i = 0; i < count; i++)
too = too + "0";
if (count == 0 || ans == "0")
ans = too;
else
{
int n = too.length() - ans.length();
while (n)
{
ans = "0" + ans;//在ans前补0,保证俩字符串长度相等
n--;
}
ans = add(ans, too, too.length());
}
count++;
ret = 0;
too = too.erase(0, too.length());//清空too,方便下一次计算。
}
return ans;
}
int main()
{
string str1, str2;
cin >> str1 >> str2;
int len1 = (int)str1.length();
int len2 = (int)str2.length();
string ans = mul(str1, str2, len1, len2);
if (len1 > len2)
{
for (int i = 0; i < len1 - len2; i++)
str2 = "0" + str2;
}
else if (len1 < len2)
{
for (int i = 0; i < len2 - len1; i++)
str1 = "0" + str1;
}
int len = len1 > len2 ? len1 : len2;
string anst = add(str1, str2, len);
cout << ans<<endl<<anst;//先输出的是乘法
return 0;
}