之前一直没有做过有关高精度的题,今天做蓝桥杯真题的时候才知道有这种题型(看来埋头硬学不太行),不过幸好发现得早,还有时间补救。
高精度加法
有些题目该出的数据会很大,致使连最大的unsigned long long(264-1)都存不下,c++中有种名为字符串的东西,它的长度可比unsigned long long 长的多,我们可以考虑用它来存储数字;不过string只能存储字符串,所以我们要采取一定的措施,用一定的放法来模拟加法。
在日常生活中,我们计算加法时都是用竖式,所以我们考虑模拟竖式的计算,但是,c++中字符串的遍历方式是从左到右的,为方便计算,我们还得把字符串给翻转一下,我们可以使用reverse函数来实现字符串的翻转,也可以手写函数,手写函数的代码如下:
void reve(string &x)
{long long len = x.size()for(int i = 1;i<=len;i++){char t = x[i];x[i] = x[len - 1 - i];x[len - 1 - i] = t;}
}
加法的模拟如下:
string high(string a,string b)
{string res;long long maxl = max(a.size(),b.size());//找出字符串的最长长度int up = 0;//up为进位for(int i = 0;i< maxl;i++){int n1 = (i<a.size() ? a[i] - '0' : 0);int n2 = (i<b.size() ? b[i] - '0' : 0);//避免越界,如果超出了小的字符串的范围,小的字符串的数字就始终为0int sum = n1 + n2 + up;//计算每位的和up = sum / 10;//计算进位res.push_back('0' + (sum % 10));//把数字存起来,当然是倒序 }if(up > 0) res.push_back('0' + up); //如果up有剩余,那么还需要进一位return res;
}
完整代码如下:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;void reve(string &x)
{int len = x.size();for(int i = 0;i<len / 2;i++){swap(x[i], x[len-i-1]);}
}string high(string &a,string &b)
{int up = 0,maxl = max(a.size(),b.size());string res;for(int i = 0;i<maxl;i++){int n1 = (i < a.size()) ? (a[i]-'0') : 0;int n2 = (i < b.size()) ? (b[i]-'0') : 0;int sum = n1 + n2 + up;up = sum / 10;char t = '0' + sum;res.push_back('0'+(sum%10));}if(up > 0) res.push_back('0' + up);return res;
}void solve()
{string a,b;cin >> a >> b;reve(a),reve(b);string ans = high(a,b);reve(ans);cout << ans <<"\n";
}int main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int _ = 1;while(_--)solve();return 0;
}
高精度乘法
具体情况和高精度加法差不多,也是需要模拟竖式计算。
首先,依然是需要将字符串翻转过来,可以用reverse函数也可以手写函数,手写函数的方法和加法一样,这里就不在赘述了。
接下来是乘法模拟,为了模拟乘法竖式计算,我们采用与加法计算不同的方法(因为个位数乘完后还需要相加),我们用一个数组来存储结果;用双层循环来枚举其中一个乘数的每一位来与另一个乘数相乘并加在product[i+j]上,这样是为了模拟竖式计算的错位,第一位相乘时,错0位,第二位相乘时,错1位……
由于我们的数字是倒序存储的所以product数组中的数组也是倒序的,与加法不同,我们的数组长度是固定的,难免会出现多于的0,这时我们就应该删去它们,
完成上述操作后,将数字转化为字符串即可。
乘法模拟函数
string high(string a,string b)
{string res;//定义结果vector<int> product(a.size()+b.size(),0);//用来存储每位相乘所得的数字for(int i = 0;i<a.size();i++){for(int j = 0;j<b.size();j++){product[i+j] += (a[i]-'0') * (b[j]-'0');//计算相乘的结果product[i+j+1] += product[i+j]/10;// 处理进位 product[i+j] %= 10;//计算当前位应留下的数}}//假设为12*123,那么第一层循环就是从12中拆除每一位与另一个数相乘,双层循环也可以解决多位数相乘是产生的错位情况 while(product.size() > 1 && product.back() == 0) product.pop_back();//将product数组的大小设为a.size()+b.size()可能会剩下不必要的0,比如10*10 = 100,最后一位就会多出不必要的0,由于数字是倒序存储的,所以不必担心去除数字原有的0 for(int i = product.size()-1; i >= 0; i--) res.push_back(product[i] + '0');//将数字转化为字符串(倒序)return res;//返回结果
}
完整代码如下:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;void reve(string &x)
{for(int i = 0;i<x.size()/2;i++){swap(x[i],x[x.size()-1-i]);}
}string high(string a,string b)
{string res;vector<int> product(a.size()+b.size(),0);for(int i = 0;i<a.size();i++){for(int j = 0;j<b.size();j++){product[i+j] += (a[i]-'0') * (b[j]-'0');product[i+j+1] += product[i+j]/10; product[i+j] %= 10;}}while(product.size() > 1 && product.back() == 0) product.pop_back();for(int i = product.size()-1; i >= 0; i--) res.push_back(product[i] + '0');return res;
}void solve()
{string a,b;cin >> a >> b;reve(a);reve(b);string res = high(a,b);cout << res <<"\n";
}int main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int _ = 1;while(_--)solve();return 0;
}
算法学习,任重而道远啊。