高精度害死人

£可爱£侵袭症+ 提交于 2020-01-11 16:23:08

高精度加减乘除板子,整理一下成为函数。

思路

都是字符串读入,倒序存储。数组\(a_0\)表示\(a\)的位数。

加法

每一位相加,判断是否需要进位。循环结束后判断最高位是否需要进位,最终调整一下位数。

减法

每一位相减,不够减的向前一位借位 (感觉我在学习小学一年级知识??)最后需要调整位数,去掉前导0.

乘法

这里和普通的竖式乘法不同。高精乘高精思路为,答案的第i+j-1位,等于两乘数分别的第 i 位和第 j 位相乘。最后需要处理进位和位数的问题。

除法

如上图,是地球人用纸和笔做的除法。但是很显然,计算机走试商的方法太麻烦,那就只能把除数移到被除数的最高位(空余的用0补上),再相减,直到剩下的数小于除数(同时记录商),然后进行下一位的计算。

代码

加法

#include<iostream>
#include"cmath"
#include<cstdio>
#include<algorithm>
using namespace std;
string in;
int a[999],b[999],ans[999];
int strlen(string x){
    int tot = 0;
    while(x[tot++] != '\0');
    return tot-1;
}
void _P(int x[],int y[]){
    ans[0] = max(x[0],y[0]);
    for(int i = 1;i <= ans[0]; i++){
        ans[i] += x[i] + y[i];
        ans[i+1] += ans[i]/10;
        ans[i] %= 10;
    }
    if(ans[ans[0] + 1]) ans[0] ++;
} 
int main(){
    cin >> in;
    a[0] = strlen(in);
    for(int i = 1;i <= a[0]; i++){
        a[i] = in[a[0] - i] - '0';
    }
    cin >> in;
    b[0] = strlen(in);
    for(int i = 1;i <= b[0]; i++){
        b[i] = in[b[0] - i] - '0';
    }
    _P(a,b);
    for(int i = ans[0];i >= 1; i--){
        cout << ans[i];
    }
    cout <<endl;
}

减法

注意正负号的检验。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
string in;
int a[10100],b[10100];
int c[10100];
int strlen(string x){
    int tot = 0;
    while(x[tot++] != '\0');
    tot--;
    return tot;
}
void jian(int x[],int y[]){
    c[0] = x[0];
    for(int i = 1;i <= x[0]; i++){ 
        c[i] += x[i]-y[i];
        if(c[i] < 0){
            c[i] += 10;
            c[i+1]--;
        }
    }
    while(c[0] > 1 && c[c[0]] == 0) c[0]--;
}
bool cmp(int x[],int y[]){
    if(x[0] > y[0]) return 1;
    if(x[0] < y[0]) return 0;
    for(int i = y[0];i >= 1; i--){
        if(x[i] > y[i]) return 1;
        if(x[i] < y[i]) return 0;
    }
    return 1;
}
int main(){
    cin >> in;
    a[0] = strlen(in);
    for(int i = 1;i <= a[0]; i++){
        a[i] = in[a[0] - i] - '0';
    }
    cin >> in;
    b[0] = strlen(in);
    for(int i = 1;i <= b[0]; i++){
        b[i] = in[b[0] - i] - '0';
    }
    if(!cmp(a,b)){
        for(int i = 0;i <= max(a[0],b[0]); i++){
            swap(a[i],b[i]);
        }
        cout << '-';
    }
    jian(a,b);
    for(int i = c[0];i >= 1; i--)
        cout << c[i] ;
    cout << endl; 
    return 0;
}

乘法

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
string in;
int a[999],b[999],ans[999];
int strlen(string x){
    int tot = 0;
    while(x[tot++] != '\0');
    return tot-1;
}
void _X(int x[],int y[]){
    ans[0] = x[0] + y[0]-1;
    for(int i = 1;i <= x[0]; i++){
        for(int j = 1;j <= y[0]; j++){
            ans[j+i-1] += x[i] * y[j];
            ans[i+j] += ans[j+i-1] / 10;
            ans[i+j-1] %= 10; 
        }
    }
    if(ans[ans[0]+1] != 0) ans[0]++;
    while(ans[0] > 1 && ans[ans[0]] == 0) ans[0]--;
} 
int main(){
    cin >> in;
    a[0] = strlen(in);
    for(int i = 1;i <= a[0]; i++){
        a[i] = in[a[0] - i] - '0';
    }
    cin >> in;
    b[0] = strlen(in);
    for(int i = 1;i <= b[0]; i++){
        b[i] = in[b[0] - i] - '0';
    }
    _X(a,b);
    for(int i = ans[0];i >= 1; i--){
        cout << ans[i];
    }
    cout <<endl;
    return 0;
} 

除法

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
string in;
int a[10100],b[10100];
int c[10100];
int d[10100],r[10100];
int strlen(string x){
    int tot = 0;
    while(x[tot++] != '\0');
    tot--;
    return tot;
}

void jian(int x[],int y[]){
    memset(c,0,sizeof c);
    c[0] = x[0];
    for(int i = 1;i <= x[0]; i++){ 
        c[i] += x[i]-y[i];
        if(c[i] < 0){
            c[i] += 10;
            c[i+1]--;
        }
    }
    while(c[0] > 1 && c[c[0]] == 0) c[0]--;
}

int cmp(int x[],int y[]){
    if(x[0] > y[0]) return 1;
    if(x[0] < y[0]) return 0;
    for(int i = y[0];i >= 1; i--){
        if(x[i] > y[i]) return 1;
        if(x[i] < y[i]) return 0;
    }
    return 2;
}
//商d,余数r
void chu(int x[],int y[]){
    memset(d,0,sizeof d);
    memset(r,0,sizeof r);
    int tmp[10100] = {};
    for(int i = 0;i <= x[0]; i++){
        r[i] = x[i];
    }
    d[0] = x[0];
    for(int i = x[0] - y[0] + 1;i >= 1; i--){
        memset(tmp,0,sizeof tmp);
        int cnt = 1;
        for(int j = i;j <= i + y[0] - 1; j++){
            tmp[j] = y[cnt++];//移位操作
        }
        for(int j = i-1; j >= 1; j--) tmp[j] = 0;
        tmp[0] = i-1 + y[0];
        while(cmp(r,tmp)){//比较除数和剩下的被除数
            d[i]++;
            jian(r,tmp);
            memset(r,0,sizeof r);
            for(int i = 0;i <= max(r[0],c[0]); i++) r[i] = c[i];
        }
    }
    while(d[0] > 1 && d[d[0]] == 0) d[0]--;
    while(r[0] > 1 && c[c[0]] == 0) r[0]--;
}
int main(){
    cin >> in;
    a[0] = strlen(in);
    for(int i = 1;i <= a[0]; i++){
        a[i] = in[a[0] - i] - '0';
    }
    cin >> in;
    b[0] = strlen(in);
    for(int i = 1;i <= b[0]; i++)
        b[i] = in[b[0]-i] - '0'; 
    
    chu(a,b);
    
    for(int i = d[0];i >= 1; i--) cout << d[i];
    cout << endl;
    for(int i = r[0];i >= 1; i--) cout << r[i];
    cout << endl;
    return 0;
}

例题

回文数

传送至洛谷 一本通

特殊的一点就是这里提到的是n进制,所以需要稍微进行一下优化(还好不是乘法除法)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[10086],b[10086];
int c[10086];
int n;string in;
int ans;
int strlen(string x){
    int tot = 0;
    while(x[tot++] != '\0');
    return tot-1;
}
void pluss(int x[],int y[],int k){//k进制
    memset(c,0,sizeof c);
    c[0] = max(x[0],y[0]);
    for(int i = 1;i <= max(x[0],y[0]); i++){
        c[i] += x[i] + y[i];
        if(c[i] >= k){
            c[i+1] += 1;
            c[i] %= k;//实际就是把10都改成了k
        }
    }
    if(c[c[0] + 1])
        c[0]++;
}
bool is_hw(int x[]){
    for(int i = 1;i <= x[0]; i++){
        if(x[i] != x[x[0] - i + 1]) return 0;
    }
    return 1;
}
int main(){
    cin >> n;
    cin >> in;
    a[0] = strlen(in);
    for(int i = 1;i <= a[0]; i++){
        if(in[a[0] - i] >= '0' && in[a[0] - i] <= '9')
            a[i] = in[a[0] - i] - '0';
        else
            a[i] = 10 + in[a[0]-i] -'A';
    }
    for(int i = 0;i <= a[0];i++) c[i] = a[i];
    while(!is_hw(c)){
        ans++;
        b[0] = c[0];
        a[0] = c[0];
        for(int i = 1;i <= c[0]; i++){
            b[i] = c[i];
            a[i] = c[c[0] + 1 -i];//倒序
        }
        pluss(a,b,n);
        if(ans >= 30){
            cout << "Impossible" << endl;
            return 0;
        }
    }
    cout << ans << endl;
    return 0;
}

阶乘之和

洛谷 一本通
这个真的是我也不知道为什么有点麻烦,之前是打表做的,今天重新写了一下。
整体如果出问题还是在高精的核心算法上。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[10000],b,anss[10000];
int n;
int ans[10000],now[10000];

void _x(int x,int y[]){
    memset(ans,0,sizeof ans);
    int x0 = 0,k = x;
    while(k){k /= 10; x0++;}
    ans[0] = x0 + y[0] -1;
    for(int i = 1;i <= max(y[0],x0); i++){
        ans[i] += x * y[i];
        k = i;
        while(ans[k] >= 10){
            ans[k+1] += ans[k] / 10;
            ans[k] %= 10;
            k++;
        }
        ans[0] = max(k,ans[0]);
    }
    while(ans[0] > 1 && ans[ans[0]] == 0) ans[0]--;
}

void _p(int x[],int y[]){
    memset(anss,0,sizeof anss);
    anss[0] = max(a[0],y[0]);
    for(int i = 1;i <= max(x[0],y[0]); i++){
        anss[i] += x[i] + y[i];
        if(anss[i] >= 10){
            anss[i+1] += anss[i] / 10;
            anss[i] %= 10; 
        }
    } 
    if(anss[anss[0]+1]){anss[0]++;}
    for(int i = 0;i <= anss[0]; i++)
        now[i] = anss[i];
} 
int main(){
    scanf("%d",&n);
    for(int i = 1;i <= n; i++){
        a[0] = a[1] = 1;
        for(int j = 1;j <= i; j++){
            _x(j,a);
            for(int i = 0;i <= a[0]; i++) a[i] = ans[i];
        }
        _p(ans,now);
    }
    for(int i = now[0];i >= 1; i--){
        cout << now[i];
    }
    cout << endl;
    return 0;
}

结尾

其实高精是个上哪里都不会考到的东西,但是这个确实有助于提高代码能力啥的。所以以后还是多写写吧。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!