大数模板

原文为吉林大学ACM模板。

但是乘除我自己测试了几个样例好像有点问题于是自己在许多地方都改了改。

其思想依然是数组储存数位,然而每一位是万进制。这样存的数范围大了很多,但是输出输入比较麻烦。

实现了加减乘除比较和取余。除法采用二分的方法查找结果。

期中取余在除法函数里已经实现了。

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int base = 10000;//万进制所以是10000
const int width = 4;        //最大是9999四位数
const int N = 1000;        //最大数字是10000的1000次方
class dashu{
public:
    int ln;
    int v[N];
    dashu(int r = 0){
        int i;
        for(i=0;r>0;r/=base){
            v[i++]=r%base;
        }
        ln=i;
    }
    friend bool operator < (const dashu& a,const dashu& b);
    friend bool operator <= (const dashu& a,const dashu& b);
    friend dashu operator+ (const dashu& a,const dashu& b);
    friend dashu operator- (const dashu& a,const dashu& b);
    friend dashu operator* (const dashu& a,const dashu& b);
    friend dashu operator/ (const dashu& a,const dashu& b);
    friend void write(const dashu& v);
    friend int digit(const dashu& a);
    friend bool read(const dashu& b,char buf[]);
    dashu& operator = (const dashu& r){
        memcpy(this,&r,(r.ln+1)*sizeof(int));
        return *this;
    }
};

bool operator < (const dashu& a,const dashu& b){
    int i;
    if(a.ln!=b.ln) return a.ln<b.ln;
    for(i=a.ln-1;i>=0&&a.v[i]==b.v[i];i--);
    return i<0?0:a.v[i]<b.v[i];
}
bool operator <= (const dashu& a,const dashu& b)
{
    return !(b<a);
}
dashu operator+ (const dashu& a,const dashu& b){
    dashu res;
    int i,cy=0;
    for(i=0;i<a.ln||i<b.ln;i++){
        if(i<a.ln) cy+=a.v[i];
        if(i<b.ln) cy+=b.v[i];
        res.v[i]=cy%base;
        cy/=base;
    }
    if(cy){
        res.ln=i+1;
        res.v[res.ln-1]=cy;
    }
    else
        res.ln=i;
    return res;
}
dashu operator -(const dashu &a,const dashu& b){
    dashu res;int i,cy=0;
    for(res.ln=a.ln,i=0;i<res.ln;i++){
        res.v[i]=a.v[i]-cy;
        if(i<b.ln) res.v[i]-=b.v[i];
        if(res.v[i]<0){cy=1;res.v[i]+=base;}
        else cy=0;
    }
    while(res.ln>0 && res.v[res.ln-1]==0) res.ln--;
    return res;
}
dashu operator * (const dashu& a,const dashu& b){
    dashu res;res.ln=0;
    if(0==b.ln) { res.v[0]=0;return res;}
    int i,j,cy;
    for(i=0;i<a.ln;i++){
        for(j=cy=0;j<b.ln||cy>0;j++,cy/=base){
            if(j<b.ln) cy+=a.v[i]*b.v[j];
            if(i+j<res.ln) cy+=res.v[i+j];
            if(i+j>=res.ln) res.v[res.ln++]=cy%base;
            else res.v[i+j]=cy%base;
        }
    }
    return res;
}
dashu operator /(const dashu& a,const dashu& b){
    dashu mod,tem,res;
    int i,lf,rg,mid;
    mod.v[0]=mod.ln=0;
    for(i=a.ln-1;i>=0;i--){
        mod=mod*base+a.v[i];
        for(lf = 0,rg=base-1;lf<rg;){
            mid=(lf+rg+1)/2;
            if(b*mid<=mod) lf=mid;
            else rg=mid-1;
        }
        res.v[i]=lf;
        mod=mod-b*dashu(lf);
    }
    res.ln=a.ln;
    int t=0;
    while(res.ln>0&&res.v[res.ln-1]==0)
        res.ln--;
    for(int i=0;i<res.ln;i++)
        res.v[i]=res.v[i+t];
    return res;
    //return mod;
}
int digit(dashu &a){
    if(a.ln==0) return 0;
    int l=(a.ln-1)*4;
    for(int t=a.v[a.ln-1]; t ;l++,t/=10);
    return l;
}
bool read(dashu& b,char buf[]){//将字符串数组变为大数
    cin>>buf;
    int ln=strlen(buf);
    memset(&b,0,sizeof(dashu));
    b.ln=ln/4+1;
    int t=0;
    for(int i=ln-1;i>=0;i=i-4){
        int n=0;
        int j=i-3;
        if(j<0){
            j=0;
        }
        while(j<=i){
            n=n*10+(buf[j++]-'0');
        }
        b.v[t++]=n;
    }
    return 1;
}
void write(const dashu& v){ //输出大数
    int i;
    printf("%d",v.ln==0?0:v.v[v.ln-1]);
    for(i=v.ln-2;i>=0;i--)
        printf("%04d",v.v[i]);
    cout<<endl;
}
int main()
{
    dashu a,b,c;
    a.ln=1;
    a.v[0]=1;
    b.ln=2;
    b.v[0]=1111;
    b.v[1]=1;
    c=a+b;
    write(a);
    write(b);
    write(c);
    return 0;
}
至于开根号,理论上来说用牛顿递推法,但是由于是整数不太适合。手动开方的话,手动开根号的基本方法:
(1)将被开方数从右向左每隔2位用撇号分开;
(2)从左边第一段求得算数平方根的第一位数字;
(3)从第一段减去这个第一位数字的平方,再把被开方数的第二段写下来,作为第一个余数;
(4)把所得的第一位数字乘以20,去除第一个余数,所得的商的整数部分作为试商(如果这个整数部分大于或等于10,就改用9左试商,如果第一个余数小于第一位数字乘以20的积,则得试商0);
(5)把第一位数字的20倍加上试商的和,乘以这个试商,如果所得的积大于余数时,就要把试商减1再试,直到积小于或等于余数为止,这个试商就是算数平方根的第二位数字; (6)用同样方法继续求算数平方根的其他各位数字。

照此写出的函数如下,正确性存疑。

void Sqrt(char *str){
    double i,r,n;
    int j,l,siz,num,x[1000];
    siz=strlen(str);
    if(siz==1 && str[0]=='0')
    {
        cout<<0<<endl;
        return ;
    }
    if(siz%2==1)
    {
        n=str[0]-'0';
        l=-1;
    }
    else
    {
        n=(str[0]-'0')*10+str[1]-'0';
        l=0;
    }
    r=num=0;
    while(1){
        i=0;
        while(i*(i+20*r)<=n) i+=1;
        i-=1;
        n-=i*(i+20*r);
        r=r*10+i;
        x[num]=(int )i;
        num++;
        l+=2;
        if(l>=siz) break;
        n=n*100+(double)(str[l]-'0')*10+(double)(str[l+1]-48);
    }
    for(j=0;j<num;j++)
        cout<<x[j];
    cout<<endl;
}
对于大数开方详见 http://blog.csdn.net/hondely/article/details/693989

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值