高精度

C++常用数据类型范围

#include<bits/stdc++.h>
using namespace std;
int main(){
    //数据类型范围定义在limits.h中
    printf("int\n字节数:%d\n最大值:%d\n最小值:%d\n",sizeof(int),INT_MAX,INT_MIN);
    printf("unsigned\n字节数:%d\n最大值:%u\n最小值:%u\n",sizeof(unsigned),UINT_MAX,0);
    printf("long long\n字节数:%lld\n最大值:%lld\n最小值:%lld\n",sizeof(long long ),LLONG_MAX,LLONG_MAX);
    printf("unsigned long long\n字节数:%d\n最大值:%llu\n最小值:%llu\n",sizeof(unsigned long long),ULLONG_MAX,0);
    //float.h
    printf("float\n字节数:%d\n最大值:%f\n最小值:%f\n正最小:%e\n",sizeof(float),FLT_MAX,-FLT_MAX,FLT_MIN);
    printf("double\n字节数:%d\n最大值:%e\n最小值:%e\n正最小:%e\n",sizeof(double),DBL_MAX,-DBL_MAX,DBL_MIN);
    printf("long double\n字节数:%d\n最大值:%Le\n最小值:%Le\n正最小:%e\n",sizeof(long double),LDBL_MAX,-LDBL_MAX,LDBL_MIN);
    //long double 完全输出用%Lf
    int x=0xfffffff;
    float y=0xfffffff;
    //由于float尾数为(有效位)为23,而int为31所以相同的数字float会有误差,即float牺牲精度换取范围
    printf("x:%d\ny:%f\n",x,y);
    return 0;
}

运行结果

那么当我们需要存储或计算的数据过大时,就需要使用高精度了。

高精度(四位压缩)

对于数字100456789
存储的时候是这个样子

参考代码

#include<bits/stdc++.h>
// 高精度
// 四位压缩大法
using namespace std;
const int mlen=1e3,mod=1e4;
struct BD{
    int p[mlen],len;
    bool cha;//符号位 0为正,1为负
    BD(){
        memset(p,0,sizeof(p));
        len=0;//存储时从第零位开始存储,方便乘法运算
        cha=0;
    }
    BD(string &s){//字符串转高精
        memset(p,0,sizeof(p));
        len=0;
        int beg=0;
        if(s[0]=='-')cha=1,beg=1;
        else cha=0;
        for(int i=s.size()-1;i>=beg;i-=4){
            int sum=0,base=1;
            for(int j=0;j<4&&i-j>=beg;++j){
                sum+=(s[i-j]-'0')*base;
                base*=10;
            }
            p[len++]=sum;
        }
    }
    void print(){//打印高精度的函数
        if(cha)putchar('-');
        if(len==0){putchar('0');return ;}
        printf("%d",p[len-1]);//第一个四位数不需要前导零,单独打印
        for(int i=len-2;i>=0;--i){
            if(p[i]==0){
                printf("0000");
                continue;
            }
            for(int j=10;j*p[i]<mod;j*=10)printf("0");
            printf("%d",p[i]);
        }
    }
    BD operator+(const BD&a);//高精加高精
    BD operator*(int a);//高精乘单精
    BD operator*(const BD&a);//高精乘高精
    bool operator<(const BD&a);//高精比大小
    BD operator-(const BD&a);//高精减高精
};
//高精加高精
//符号位相同调这个
BD BD::operator+(const BD&a){
    BD c;
    c.len=max(len,a.len);
    c.cha=a.cha;
    int f=0;
    for(int i=0;i<c.len;++i){
        c.p[i]=p[i]+a.p[i]+f;
        f=c.p[i]/mod;
        c.p[i]%=mod;
    }
    if(f)c.p[c.len++]=f;
    return c;
}
//高精乘单精
BD BD::operator*(int a){
    BD c;
    if(a<0){
        a=-a;
        c.cha=cha^1;
    }
    else c.cha=cha;
    if(a==0)return c;
    c.len=len;
    int f=0;
    for(int i=0;i<len;++i){
        c.p[i]=p[i]*a+f;
        f=c.p[i]/mod;
        c.p[i]%=mod;
    }
    while(f){
        c.p[c.len++]=f%mod;
        f/=mod;
    }
    return c;
}
//高精比大小
bool BD::operator<(const BD&a){
    if(len<a.len)return true;
    else if(a.len<len)return false;
    for(int i=len-1;i>=0;--i){
        if(p[i]<a.p[i])return true;
        else if(a.p[i]<p[i])return false;
    }
    return false;
}
//高精减高精
int flag;//帮助判断符号位
BD BD::operator-(const BD&a){//调用前先比较大小
    BD c;
    c.cha=cha^flag;
    c.len=len;
    int f=0;//标记是否借位
    for(int i=0;i<len;++i){
        if(p[i]+f<a.p[i]){
            c.p[i]=p[i]+mod+f-a.p[i];
            f=-1;
        }
        else {
            f=0;
            c.p[i]=p[i]-a.p[i];
        }
    }
    while(c.len>0&&c.p[c.len-1]==0){
        c.len--;
    }
    return c;
}
//高精乘高精
//n位数乘n位数最多得到2n位数
BD BD::operator*(const BD&a){
    BD c;
    c.cha=cha^a.cha;
    for(int i=0;i<len;++i){
        for(int j=0;j<a.len;++j){
            c.p[i+j]+=p[i]*a.p[j];
            c.p[i+j+1]+=c.p[i+j]/mod;
            c.p[i+j]%=mod;//即刻进位,防止超出int范围
        }
    }
    //删除前导零
    c.len=a.len+len;
    while(c.len>0&&c.p[c.len-1]==0)c.len--;
    return c;
}
int main(){
    string s1;
    string s2;
    cin>>s1>>s2;
    BD a(s1),b(s2);
    printf("s1+s2=");
    if(a.cha==b.cha)(a+b).print();
    else{
        if(a<b)flag=0,(b-a).print();
        else flag=0,(a-b).print();
    }
    putchar('\n');
    printf("s1-s2=");
    if(a.cha!=b.cha){
       (b+a).print();
    }
    else{//此时符号位相同,用flag判断是否要改变符号即可
        if(a<b)flag=1,(b-a).print();
        else flag=0,(a-b).print();
    }
    putchar('\n');
    printf("s1*s2=");
    (a*b).print();
    putchar('\n');
    return 0;
}

思路不难,但是有很多细节要注意,符号,乘法偏移量,前导零\(\cdots\)
运行结果

posted @ 2022-03-20 20:50  何太狼  阅读(246)  评论(0编辑  收藏  举报