高精度-基础
公用函数部分
//没什么,就是一个结构体
struct BigNum{
int len;
int d[10000];
}a,b;
//比较两个大数的大小,用于减法与除法中
//返回值为a1是否大于a2
bool cmp(BigNum a1,BigNum a2){
if(a1.len!=a2.len) return a1.len>a2.len;
for(int i = a1.len-1;i>=0;i--){
if(a1.d[i]!=a2.d[i]) return a1.d[i]>a2.d[i];
}
return true;
}
//读入
void input(){
string n1,n2;
cin>>n1>>n2;
int l1 = n1.length();
int l2 = n2.length();
for(int i = 0;i<l1;i++){
a.d[l1-i-1] = n1[i] - '0';
}
a.len = l1;
for(int i = 0;i<l2;i++){
b.d[l2-i-1] = n2[i] - '0';
}
b.len = l2;
//最高位下标为len-1
}
void output(){
for(int i = a.len-1;i>=0;i--){
cout<<a.d[i];
}
}
高精度加法
void jia(){
if(a.len<b.len) swap(a,b);
for(int i = 0;i<a.len;i++){
a.d[i] = a.d[i] + b.d[i];
}
for(int i = 0;i<a.len;i++){
if(a.d[i]>=10){
a.d[i] -= 10;
a.d[i+1] += 1;
}
}
if(a.d[a.len]!=0) a.d[a.len]++;
}
高精度减法
void jian(){
bool zhengshu = cmp(a,b);
if(!zhengshu) swap(a,b);
//大数减小数再加上负号
for(int i = 0;i<a.len;i++){
a.d[i] = a.d[i] - b.d[i];
}
for(int i = 0;i<a.len;i++){
if(a.d[i]<0){
a.d[i] += 10;
a.d[i+1] -= 1;
}
}
if(a.d[a.len-1]==0) a.d[a.len-1]--;
if(!zhengshu) a.d[a.len-1] = -a.d[a.len-1];
}
高精度乘法
int mod(int a1,int n){
while(a1>=n){
a1 -= n;
}
return a1;
}
void cheng(){
//按照人类习惯,大数在上,小数在下
//拿小数各位去乘大数各位,结果存在 下标和
//即 第2位 乘 第3位 结果存在 第5位 内
//位数最多增加 小数位数 个
//位数最少增加 0 个
/*
9 9 9
* 9 9
---------
8 9 9 1
8 9 9 1
---------
9 8 9 0 1
*/
BigNum t;
//大数在上,小数在下
if(a.len<b.len) swap(a,b);
//乘
for(int i = 0;i<b.len;i++){
for(int j = 0;j<a.len;j++){
//因为两个大数都要重复使用所以需要另开辟一个BigNum t
//各位相乘结果存在 下标和 内
t.d[i+j] = t.d[i+j] + b.d[i] * a.d[j];
}
}
//进位
for(int i = 0;i<a.len+b.len;i++){
if(t.d[i] >= 10){
t.d[i+1] = t.d[i+1] + (t.d[i] - mod(t.d[i],10))/10;
t.d[i] = mod(t.d[i],10);
}
}
//判断位数增加数
int jinwei = 0;
for(int i = a.len;i<=a.len+b.len;i++){
if(t.d[i]!=0) jinwei++;
}
//转移
for(int i = 0;i<a.len+jinwei;i++){
a.d[i] = t.d[i];
}
//改变位数
a.len += jinwei;
}
高精度除法
我有一个很好的思路可惜这里写不下
真的会用到高精度除法吗
- 大概思路
- 会用到高精度减法(用来取余数以及整除)
- 会用到高精度比较函数
- 从被除数首位开始除,不断在后面添加被除数下一位,直到被除数大于除数
- 商从最高位开始记录,需要倒序存在数组里
- 倒序输出
在大佬!LZB!的指导下弄明白了(大概)高精度除法
-
在除数后面补0(即逆序的右移操作)至位数相同
-
连续进行高精减法,用cnt来计数,减至a<b时,cnt即为“补0个数”位上的值
-
用第2步的结果(即上一步余数)做被除数,除数去掉一个0(即逆序左移一位)重复第2步
-
示例:
假设计算 \(32517/54\) 时
①将除数 \(54\) 的位数补至小于被除数的最大数,即 \(54000\),所以千位为\(0\)
②高精减算出 \(32517/5400=6......117\),所以结果的百位为 \(6\)
③以 \(117\)为被除数,\(54\)不补 \(0\),即 \(117/54=2......9\)所以个位为 \(2\)
所以整除结果为 \(602\),余数为 \(9\)
void youyiwei(BigNum &a,int n) {
for(int i = a.len + n-1; i>=n; i--) {
a.d[i] = a.d[i-n];
}
for(int i = 0; i<n; i++) {
a.d[i] = 0;
}
a.len+=n;
}
void zuoyiwei(BigNum &a,int n) {
for(int i = 0; i<a.len-n; i++) {
a.d[i] = a.d[i+n];
}
for(int i = a.len-n; i<=a.len; i++) {
a.d[i] = 0;
}
a.len-=n;
}
void chu() {
BigNum r;
if(!cmp(a,b)) {
cout<<"0";
return;
}
int xiangchaweishu = a.len-b.len;
int s = xiangchaweishu;
youyiwei(b,xiangchaweishu);
while(xiangchaweishu>=0) {
int cnt = 0;
while(cmp(a,b)) {
cnt++;
jian();
}
r.d[xiangchaweishu] = cnt;
zuoyiwei(b,1);
xiangchaweishu -= 1;
}
for(int i = s;i>=0;i--){
if(r.d[i]!=0){
r.len = i+1;
break;
}
}
for(int i = r.len-1; i>=0; i--) {
cout<<r.d[i];
}
cout<<endl;
}
另外,高精乘与高精除似乎在位数较大时会出现高位缺失、结果有误等问题(但是调不明白了TAT)
完整代码