免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: yuxh
打印 上一主题 下一主题

一个十进制大数运算类,支持加减乘除模、n次乘方、n次开方等运算 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2006-08-22 10:35 |只看该作者

回复 10楼 hqxyn 的帖子

decimal.cpp
/***************************************************************************
                          decimal.cpp  -  description
                             -------------------
    begin                : Wed Jan 9 2002
    copyright            : (C) 2002 by Xian Yining
    email                : hqxyn@yahoo.com.cn
***************************************************************************/

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
#include <iostream>
#include <string>

#undef __DEBUG__
//#define __DEBUG__

#include "decimal.h"
unsigned int midDigits(const decimal& ,const decimal& ) ;

/***********
* 构造函数 *
***********/
decimal::decimal(const std::string &s,const unsigned int p,const unsigned int d) {
        decimal x(s.c_str(),p,d);
        sn=x.sn;
        val=x.val;
        exp=x.exp;
        st=x.st;
        pre=x.pre;
        dec=x.dec;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const char* ci,const unsigned int p,const unsigned int d) {
        char c[strlen(ci)+1];
        unsigned j=0;
        int i;
        strcpy(c,ci);
#ifdef __DEBUG__
std::cout<<"char*:c="<<c<<"\n";
#endif
        //消前后空格
        for ( i=strlen(c)-1;i>=0;--i ) {
                if ( c!=' ' ) break;
                c='\0';
        }
        for ( j=0;j<strlen(c); ) {
                if (c[j]!=' ') break;
                ++j;
        }
        //判符号
        if ( c[j]=='+' ) {sn=PLUS;++j;}
        else {
                if ( c[j]=='-' ) {sn=MINUS;++j;}
                else sn=PLUS;
        }
        //去前导‘0’
        while (j<strlen(c+j)) {if (c[j]!='0') break;++j;}
#ifdef __DEBUG__
std::cout<<"char*:j="<<c+j<<"\n";
#endif
        char *fp=c+j;        //尾数数组指针
#ifdef __DEBUG__
std::cout<<"char*:fp="<<fp<<"\n";
#endif
        char *ep=NULL;        //指数数组指针
        char *dp=NULL;        //小数数组指针
        st=OK;
        for ( j=0;j<strlen(fp) && fp[j]!='\0'; ) {        //取尾数整数部分
                switch(fp[j]) {
                  case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':++j;break;
                  case '.':dp=fp+j+1;fp[j]='\0';break;
                  case 'E':case 'e':ep=fp+j+1;fp[j]='\0';break;
                  default:st=NOINIT;fp[j]='\0';

                  }
        }
#ifdef __DEBUG__
std::cout<<"char*:fp2="<<fp<<"\n";
#endif
        if ( dp!=NULL ) {        //取尾数小数部分
                for (j=0;j<strlen(dp) && dp[j]!='\0'{
                        switch(dp[j]) {
                          case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':++j;break;
                          case 'E':case 'e':ep=dp+j+1;dp[j]='\0';break;
                          default:st=NOINIT;dp[j]='\0';
                          }
                }
        }
#ifdef __DEBUG__
std::cout<<"char*:fp3="<<ep<<"\n";
#endif
        if ( ep!=NULL ) {
                switch(ep[0]) {        //检查指数首字符
                  case '+':case '-':
                  case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':break;
                  default:st=NOINIT;
                }
        }
#ifdef __DEBUG__
std::cout<<"char*:fp4="<<fp<<"\n";
#endif
        if ( ep!=NULL ) {        //取指数部分
                for (j=1;j<strlen(ep){
                        switch(ep[j]) {
                          case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':++j;break;
                          default:st=NOINIT;
                          }
#ifdef __DEBUG__
std::cout<<"char*:fp5c="<<fp[j]<<"\n";
#endif

                }
        }
#ifdef __DEBUG__
std::cout<<"char*:fp5="<<fp<<"\n";
#endif
        if (fp!=NULL ) {
                val=fp;
        }
        exp=0;
        if (dp!=NULL) {
                val.append(dp);
                exp-=strlen(dp);
        }
        if (ep!=NULL) {
#ifdef __DEBUG__
std::cout<<"char*:*ep="<<atoi(ep)<<"\n";
#endif
                exp+=atoi(ep);
        }
        dec=d;
        pre=p;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const int v,const unsigned int p,const unsigned int d) {
        char c[std::numeric_limits<int>::digits10+2];
        sprintf(c,"%i",v);
#ifdef __DEBUG__
std::cout<<"int:c="<<c<<"\n";
#endif
        if (c[0]=='-') {sn=MINUS;val=c+1;}
        else {sn=PLUS;val=c;}
        pre=p;
        dec=d;
        exp=0;
        st=OK;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const unsigned int v,const unsigned int p,const unsigned int d) {
        char c[std::numeric_limits<unsigned int>::digits10+2];
        sprintf(c,"%u",v);
#ifdef __DEBUG__
std::cout<<"Uint:c="<<c<<"\n";
#endif
        sn=PLUS;
        val=c;
        pre=p;
        dec=d;
        exp=0;
        st=OK;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const long v,const unsigned int p,const unsigned int d) {
        char c[std::numeric_limits<long>::digits10+2];
        sprintf(c,"%li",v);
#ifdef __DEBUG__
std::cout<<"long:c="<<c<<"\n";
#endif
        if (c[0]=='-') {sn=MINUS;val=c+1;}
        else {sn=PLUS;val=c;}
        pre=p;
        dec=d;
        exp=0;
        st=OK;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const long long v,const unsigned int p,const unsigned int d) {
        char c[std::numeric_limits<long long>::digits10+2];
        sprintf(c,"%lli",v);
#ifdef __DEBUG__
std::cout<<"long long:c="<<c<<"\n";
#endif
        if (c[0]=='-') {sn=MINUS;val=c+1;}
        else {sn=PLUS;val=c;}
        pre=p;
        dec=d;
        exp=0;
        st=OK;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const unsigned long v,const unsigned int p,const unsigned int d) {
        char c[std::numeric_limits<unsigned int>::digits10+2];
        sprintf(c,"%lu",v);
#ifdef __DEBUG__
std::cout<<"Ulong:c="<<c<<"\n";
#endif
        val=c;
        sn=PLUS;
        pre=p;
        dec=d;
        exp=0;
        st=OK;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}

decimal::decimal(const unsigned long long v,const unsigned int p,const unsigned int d) {
        char c[std::numeric_limits<unsigned long long>::digits10+2];
        sprintf(c,"%llu",v);
#ifdef __DEBUG__
std::cout<<"UUlong:c="<<c<<"\n";
#endif
        val=c;
        sn=PLUS;
        pre=p;
        dec=d;
        exp=0;
        st=OK;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const double v,const unsigned int p,const unsigned int d) {
        char c[std::numeric_limits<double>::digits10+std::numeric_limits<int>::digits10+1];

        char t[10],s[15]="%.";
       
        sprintf(t,"%u",std::numeric_limits<double>::digits10);
        strcat(s,t);
        strcat(s,"E";
       
        sprintf(c,s,v);
#ifdef __DEBUG__
std::cout<<"double:c="<<c<<"\n";
#endif
        char *tE=strchr(c,'E');
        if ( tE!=NULL ) {        //取指数
                exp=atoi(tE+1);
                *tE='\0';
        }
        else exp=0;
       
//        for (unsigned u=strlen(c)-1;u>0 && c=='0';c='\0',u--) {}
       
        char *tD=strchr(c,'.');
       
        if ( tD!=NULL ) {        //将尾数变为整数,并相应调整指数
                char *px=tD;
                for (;*(px+1)!='\0';*px = *(px+1),--exp,++px) {}
                *px='\0';
        }

        if (c[0]=='-') {sn=MINUS;val=c+1;}
        else {sn=PLUS;val=c;}
        pre=p;
        dec=d;
        st=OK;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const long double v,const unsigned int p,const unsigned int d) {
        char c[std::numeric_limits<long double>::digits10+std::numeric_limits<int>::digits10+1];

        char t[10],s[15]="%.";
       
        sprintf(t,"%u",std::numeric_limits<long double>::digits10);
        strcat(s,t);
        strcat(s,"LE";
       
        sprintf(c,s,v);
#ifdef __DEBUG__
std::cout<<"long double:c="<<c<<"\n";
#endif
        char *tE=strchr(c,'E');
        if ( tE!=NULL ) {        //取指数
                exp=atoi(tE+1);
                *tE='\0';
        }
        else exp=0;
       
//        for (unsigned u=strlen(c)-1;u>0 && c=='0';c='\0',u--) {}
       
        char *tD=strchr(c,'.');
       
        if ( tD!=NULL ) {        //将尾数变为整数,并相应调整指数
                char *px=tD;
                for (;*(px+1)!='\0';*px = *(px+1),--exp,++px) {}
                *px='\0';
        }
       
        if (c[0]=='-') {sn=MINUS;val=c+1;}
        else {sn=PLUS;val=c;}
        pre=p;
        dec=d;
        st=OK;
        this->decReg();
        if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
/************
* 赋值操作符 *
************/
decimal& decimal:perator=(const decimal& d) {
        //精度定义(pre)和保留小数位数(dec)在变量定义时确定,?新值时不变。
#ifdef __DEBUG__
std::cout<<"in decimal[=]:"<<*this<<";;"<<d<<"\n";
#endif
        sn=d.sn;
        val=d.val;
        exp=d.exp;
        if (val.size()>pre) {st=OVERDIGITS;/*throw*/ ;}
        else st=d.st;
        return *this;
}
/**************
*  算术运算符  *
**************/
decimal& decimal:perator +=(const decimal& d2) {
        if (sn==d2.sn) {
                valAdd(val,exp,d2.val,d2.exp);
        }
        else {
                if (valCmp(val,exp,d2.val,d2.exp)<0) {
                        std::string t=d2.val;
                        int et=d2.exp;
                        valSub(t,et,val,exp);val=t;exp=et;sn=d2.sn;
                }
                else valSub(val,exp,d2.val,d2.exp);
        }
        return this->decReg();
}
decimal& decimal:perator -=(const decimal& d2) {
        if (sn==d2.sn) {
                if (valCmp(val,exp,d2.val,d2.exp)<0) {
                        std::string t=d2.val;
                        int et=d2.exp;
                        valSub(t,et,val,exp);val=t;exp=et;
                        sn=(d2.sn==PLUS)?MINUSLUS;
                }
                else valSub(val,exp,d2.val,d2.exp);
        }
        else {
                valAdd(val,exp,d2.val,d2.exp);
        }
        return this->decReg();
}
decimal& decimal:perator *=(const decimal& d2) {
        sn=(sn==d2.sn)?PLUS:MINUS;
        exp+=d2.exp;
        valMult(val,d2.val);
        return this->decReg();
}
decimal& decimal:perator /=(const decimal& d2) {
        if (d2.zero()) {st=UPFLOW;return *this;}
        sn=(sn==d2.sn)?PLUS:MINUS;
        int te1,te2;
        te1=exp+val.size();te2=d2.exp+d2.val.size();
        te1-=te2;
        valDiv(val,d2.val,pre+1);
        exp=-val.size()+1+te1;
        return this->decReg();
}
decimal operator +(const decimal& d1,const decimal& d2) {
        decimal d(0,midDigits(d1,d2),(d1.getDec()>=d2.getDec())?d1.getDec():d2.getDec());
        d=d1;
#ifdef __DEBUG__
        std::cout<<"[+]:d="<<d<<"d.pre="<<d.getPre()<<"\n";
#endif
        return d+=d2;
}
decimal operator -(const decimal& d1,const decimal& d2) {
        decimal d(0,midDigits(d1,d2),(d1.getDec()>=d2.getDec())?d1.getDec():d2.getDec());
        d=d1;
#ifdef __DEBUG__
        std::cout<<"[-]:d="<<d<<"d.pre="<<d.getPre()<<"\n";
#endif
        return d-=d2;
}
decimal operator *(const decimal& d1,const decimal& d2) {
        decimal d(0,d1.getPre()+d2.getPre(),d1.getDec()+d2.getDec());
        d=d1;
#ifdef __DEBUG__
        std::cout<<"
  • :d="<<d<<"d.pre="<<d.getPre()<<"\n";
    #endif
            return d*=d2;
    }
    decimal operator /(const decimal& d1,const decimal& d2) {
            decimal d(0,d1.getPre()+d2.getPre(),d1.getDec()+d2.getDec());
            d=d1;
    #ifdef __DEBUG__
            std::cout<<"[/]:d="<<d<<"d.pre="<<d.getPre()<<"\n";
    #endif
            return d/=d2;
    }
    /**********************
    *    比较运算符       *
    *********************/

    bool decimal::le(const decimal& d2) const {
            if (sn==decimal:LUS && d2.sn==decimal::MINUS) return false;
            if (sn==decimal::MINUS && d2.sn==decimal:LUS) return true;
            int r=decimal::valCmp(val,exp,d2.val,d2.exp);
            if (sn==decimal:LUS && r<0) return true;
            if (sn==decimal::MINUS && r>0) return true;
            return false;
    }
    bool decimal::eq(const decimal& d2) const {
            if ((sn==decimal::MINUS && d2.sn==decimal:LUS) || (sn==decimal:LUS && d2.sn==decimal::MINUS)) return false;
            int r=decimal::valCmp(val,exp,d2.val,d2.exp);
            if (r==0) return true;
            return false;
    }
    bool decimal::gt(const decimal& d2) const {
            if (this->sn==decimal::MINUS && d2.sn==decimal:LUS) return false;
            if (this->sn==decimal:LUS && d2.sn==decimal::MINUS) return true;
            int r=decimal::valCmp(val,exp,d2.val,d2.exp);
            if (this->sn==decimal:LUS && r>0) return true;
            if (this->sn==decimal::MINUS && r<0) return true;
            return false;
    }

    bool operator <(const decimal& d1,const decimal& d2) {
            return d1.le(d2);
    }
    bool operator ==(const decimal& d1,const decimal& d2) {
            return d1.eq(d2);
    }
    bool operator  >(const decimal& d1,const decimal& d2) {
            return d1.gt(d2);
    }
    bool operator <=(const decimal& d1,const decimal& d2) {
            return !(d1>d2);
    }
    bool operator >=(const decimal& d1,const decimal& d2) {
            return !(d1<d2);
    }
    bool operator !=(const decimal& d1,const decimal& d2) {
            return !(d1==d2);
    }

    /*****************
    *   输入输出流   *
    ****************/
    std:stream &operator <<(std:stream &os,const decimal& d) {
    #ifdef __DEBUG__
            os<<"ok="<<d.ok();
            os<<",sign="<<((d.getSn()==decimal:LUS)?'+'d.getSn()==decimal::MINUS)?'-':'?'));
            os<<",val="<<d.getVal();
            os<<",exp="<<d.getExp();
            os<<",pre="<<d.getPre();
            os<<",dec="<<d.getDec();
            os<<"\n";
    #endif
            os<<d.toString(0,d.getDec());
            return os;
    }
    /*
    std::istream& operator >>(std::istream& is,decimal& d) {
            std::string s;
            std::cin>>s;
            decimal dx(s.c_str());
            d=dx;
            return is;
    }
    */
    /**************
    *  杂函数     *
    **************/
    std::string decimal::toEString(const unsigned len) const {
            std::string s="";
            s.append((sn==decimal::MINUS)?"-"sn==decimal::PLUS)?" ":"?");
            s.append(val);
            s.append("E";
            char c[50];
            sprintf(c,"%i",exp);
            s.append(c);
            if (len != 0 && len<s.size()) s.assign(len,'*');
            return s;
    }
    std::string decimal::toShortStr() const{
            std::string s=toString();
            if (s.find('.')==std::string::npos) return s;
            int c=0;
            for (uint u=s.length()-1;u>0;--u){
                    if (s=='0') ++c;
                    else break;
            }
            if (s[s.length()-1-c]=='.') ++c;
            s=s.substr(0,s.length()-c);
            return s;
    }

    std::string decimal::toString() const{
            return toString(0,getDec());
    }
    std::string decimal::toString(const unsigned int len,const int de) const {
            std::string s="";
            if ( ! this->ok() ) return s.append((len==0)?1:len,'*');        //数字无效
            s.append((sn==decimal::MINUS)?"-"sn==decimal::PLUS)?" ":"?");
            if (exp>=0) {        //整数
                    s.append(val).append(exp,'0').append(1,'.').append(de,'0');
            }
            else {
                    if (-exp>=val.size()) {        //纯小数
                            s.append("0.".append(-exp-val.size(),'0').append(val);
                    }
                    else {
                            s.append(val.substr(0,val.size()+exp));
                            s.append(1,'.');
                            std::string x=val.substr(val.size()+exp);
                            s.append(x);        //带小数
                            s.append((de>x.size())?de-x.size():0,'0');
                    }
            }
            if (len != 0 && len<s.size()) s.assign(len,'*');
            return s;
    }
    decimal& decimal::round() {
            return round(dec);
    }
    decimal& decimal::round(int r) {
            if (r<-exp) {        //末位属于舍入位
                    std::string x="5";
                    int e=-(r+1);
                    valAdd(val,exp,x,e);
                    int i=-exp-r;
                    if ((val.size()-i)<=0) val="0";
                    else val=val.substr(0,val.size()-i);
                    exp+=i;
            }
            return this->decReg();
    }

    decimal round(const decimal& d,const int dec) {
            decimal dx(0,d.getPre(),dec);
            dx=d;
            dx.round(dec);
            return dx;
    }

    /****************
    *   内部子程序   *
    ****************/

    void decimal::valDiv(std::string& s1,const std::string& s2,const unsigned len) {
            std::string s(len,'0');        //商
            int ed=s2.size()-s1.size();        //商的小数位数
            std::string t1=s1,t2=s2;
            int et1;        //被除数对位指数,把两数首位对齐
            et1=ed;
            unsigned int i;        //商数循环
            int c;        //借位
            for (i=0;i<len;++i,++et1) {
                    int j=1;
                    for (j=1;j<=10;++j) {
                            if (valCmp(t1,et1,s2,0)<0) {
                            --j;
                            break;
                            }
                            c=valSub(t1,et1,s2,0) ;
                    }
                    s=char(j+4;
            }
            s1=s;
    }
    char decimal::valMult(std::string& s1,const std::string& s2) {
            std::string s="0";
            int es=0;
            for (unsigned int i=0;i<s2.size();++i) {        //乘数从末尾向前循环
                    char c1,c2=s2[s2.size()-1-i],m='0';
                    int j;
                    std::string pn(s1.size()+1,'0');
                    for (j=s1.size()-1;j>=0;--j) {        //被乘数乘以当前乘数位
                            c1=s1[j];
                            m=digitMult(c1,c2,m);
                            pn[j+1]=c1;
                    }
                    es=-i;
                    pn[0]=m;
                    valAdd(s,es,pn,0);
            }
            if (s[0]!='0') s1=s;
            else s1=s.substr(1);
            return '0';
    }
    int decimal::valSub(std::string& s1,int &e1,const std::string& s2,const int e2) {
            //计算差的位数
            //std::cout<<"s1="<<s1<<",e1="<<e1<<",s2"<<s2<<",e2="<<e2<<"\n";
            int li1,ld1,li2,ld2,li,ld;
            li1= s1.size()+e1;
            if ( e1>=0 ) {
                    li1=s1.size()+e1;
                    ld1=0;
            }
            else {
                    if (li1<0) li1=0;
                    ld1=-e1;
            }
            li2=s2.size()+e2;
            if ( e2>=0 ) {
                    ld2=0;
            }
            else {
                    if (li2<0) li2=0;
                    ld2=-e2;
            }
            li=(li1>=li2)?li1:li2;        //整数位数
            ld=(ld1>=ld2)?ld1:ld2;        //小数位数
            std::string s(li+ld,'0');
            int qb1,        //第一串首位权数
                qe1,        //第一串末位权数
                qb2,        //第二串首位权数
                qe2;        //第二串末位权数
            qe1=li-e1-1;qb1=qe1-s1.size()+1;
            qe2=li-e2-1;qb2=qe2-s2.size()+1;
            char c1,c2;
            int m=0,j;
            for (j=li+ld-1;j>=0;--j) {
                    c1=(j>=qb1 && j<=qe1)?s1[j-qb1]:'0';
                    c2=(j>=qb2 && j<=qe2)?s2[j-qb2]:'0';
                    m=digitSub(c1,c2,m);
                    s[j]=c1;
            }
            s[0]=c1;
            s1=s;e1=-ld;
            return m;
    }
    void decimal::valAdd(std::string& s1,int &e1,const std::string& s2,const int e2) {
            //计算和的位数
            int li1,ld1,li2,ld2,li,ld;
            li1= s1.size()+e1;
            if ( e1>=0 ) {
                    li1=s1.size()+e1;
                    ld1=0;
            }
            else {
                    if (li1<0) li1=0;
                    ld1=-e1;
            }
            li2=s2.size()+e2;
            if ( e2>=0 ) {
                    ld2=0;
            }
            else {
                    if (li2<0) li2=0;
                    ld2=-e2;
            }
            li=(li1>=li2)?li1:li2;        //整数位数
            ld=(ld1>=ld2)?ld1:ld2;        //小数位数
            std::string s(li+ld+1,'0');
            int qb1,        //第一串首位权数
                qe1,        //第一串末位权数
                qb2,        //第二串首位权数
                qe2;        //第二串末位权数
            qe1=li-e1;qb1=qe1-s1.size()+1;
            qe2=li-e2;qb2=qe2-s2.size()+1;
            char c1,c2;
            int m=0,j;
            for (j=li+ld;j>0;--j) {
                    c1=(j>=qb1 && j<=qe1)?s1[j-qb1]:'0';
                    c2=(j>=qb2 && j<=qe2)?s2[j-qb2]:'0';
                    m=digitAdd(c1,c2,m);
                    s[j]=c1;
            }
            if (m>0) {s[0]='1';s1=s;}
            else s1=s.substr(1);
            e1=-ld;
    }
    int decimal::digitAdd(char& c1,const char c2,const int car) {
            int i=c1+c2-48+car;
            int c=0;
            if (i>57) {i-=10;c=1;}
            c1=char(i);return c;
    }
    int decimal::digitSub(char& c1,const char c2,const int b) {
            int c=(c1>=c2+b)?0:1;
            int i=c1+(c*10)-c2+48-b;
            c1=char(i);
            return c;
    }
    char decimal::digitMult(char& c1,const char c2,const char m) {
            int i=(c1-4*(c2-4+(m-4;
            c1=i%10+48;
            return char(i/10+4;
    }
    int decimal::valCmp(const std::string& s1,const int e1,const std::string& s2,const int e2) const {
            unsigned int h1,h2;        //第一有效位的位置
            //去掉前导0
            for (h1=0;h1<s1.size() && (s1[h1]=='0');++h1) {}
            for (h2=0;h2<s2.size() && (s2[h2]=='0');++h2) {}
            if ( (h1<s1.size()) && ((s1.size()-h1+e1)>(s2.size()-h2+e2)) ) return 1;
            if ( ((s1.size()-h1+e1)<(s2.size()-h2+e2)) && (h1<s1.size()) ) return -1;
            int i,j;
            for (i=s1.size()-h1,j=s2.size()-h2;i>0 && j>0;--i,--j,++h1,++h2) {

                    if (s1[h1]<s2[h2]) return -1;
                    if (s1[h1]>s2[h2]) return 1;
            }
            if (i>j) {
                    for (;i>0 && s1[h1]=='0';--i,++h1) {}
                    return (i==0)?0:1;
            }
            if (i<j) {
                    for (;j>0 && s2[h2]=='0';--j,++h2) {}
                    return (j==0)?0:-1;
            }
            return 0;
    }

    decimal& decimal::decReg() {
            //消去前0和尾0,调整指数exp
            unsigned int b,e;
            for (b=0;b<val.size()-1 && val=='0';++b){}
            for (e=val.size()-1;e>b && val[e]=='0';--e,++exp){}
            if (b!=0 || e!=val.size()-1) val=val.substr(b,e-b+1);
            if (val.size()==1 && val[0]=='0') {exp=0;sn=PLUS;}        //值为“零”,指数应为0,符号认定为正
            return *this;
    }
    unsigned int midDigits(const decimal& d1,const decimal& d2) {
            //计算和或差中间变量的位数
            int li1,ld1,li2,ld2,li,ld;
            li1= d1.getVal().size()+d1.getExp();
            if ( d1.getExp()>=0 ) {
                    li1=d1.getVal().size()+d1.getExp();
                    ld1=0;
            }
            else {
                    if (li1<0) li1=0;
                    ld1=-d1.getExp();
            }
            li2=d2.getVal().size()+d2.getExp();
            if ( d2.getExp()>=0 ) {
                    ld2=0;
            }
            else {
                    if (li2<0) li2=0;
                    ld2=-d2.getExp();
            }
            li=(li1>=li2)?li1:li2;        //整数位数
            ld=(ld1>=ld2)?ld1:ld2;        //小数位数
            return li+ld+1;
    }

    [ 本帖最后由 hqxyn 于 2006-8-22 19:55 编辑 ]
  • 论坛徽章:
    1
    2015年辞旧岁徽章
日期:2015-03-03 16:54:15
    12 [报告]
    发表于 2006-08-22 10:36 |只看该作者
    原帖由 mirnshi 于 2006-8-21 15:02 发表
    接口为10进制, 内部的进制采用unsigned long或unsigned short,是不是更能借助逻辑运算,提高效率?

    我也这样想。
    考虑到 unsigned int 在 32 位机上可以表示超过 10 亿的整数,因此倘若采用万进制来进行内部表示的话,效率应该会高很多。
    至于加减法,可以直接用亿进制来进一步提高速度。

    论坛徽章:
    0
    13 [报告]
    发表于 2006-08-22 10:56 |只看该作者

    回复 12楼 flw 的帖子

    开始我也曾用long long型作内部表示,但出于以下考虑,还是放弃了
    1)要能表示”任意“大小的十进浮点数。
    2)算术运算不能带来误差(用二进制数表示十进制小数总会有舍入误差)。
    当然用字符型处理数值效率确实低,但这样作的最直接用途是处理货币类应用,并不是科学计算,也就将就了。

    论坛徽章:
    1
    荣誉会员
日期:2011-11-23 16:44:17
    14 [报告]
    发表于 2006-08-22 12:30 |只看该作者
    我写这个类的目的是想实现判断一个数是否是素数, 其中第一步就是判断这个数是否某个数的整数次幂
    所以我关心的是运算的效率,而不是把它扩展成浮点数形式等更适用的情况
    由于在推导一些公式时就是用10进制来考虑的,所以写的代码里也是用10进制数表示的,其实,对代码作一些相应的改动,是很方便换成16进制或别的基进制,(也可以扩展成浮点数的形式,但对我的应用来说,意义不大).

    [ 本帖最后由 yuxh 于 2006-8-22 12:38 编辑 ]

    dec.JPG (48.31 KB, 下载次数: 57)

    基本运算的说明

    基本运算的说明

    论坛徽章:
    1
    荣誉会员
日期:2011-11-23 16:44:17
    15 [报告]
    发表于 2006-08-22 13:04 |只看该作者
    贴一段测试代码给大家玩玩
    1. #include "decnum.h"

    2. int main()
    3. {
    4.     decnum x, y, r;
    5.     char *line = NULL;
    6.     size_t  n = 0;
    7.     int read;

    8.     cout << "input x:" << endl;
    9.     if((read = (int)getline(&line, &n, stdin)) != -1) {
    10.         x = decnum(line, read-1);
    11.     }
    12.     else
    13.         exit(-1);

    14.     cout << "input y:" << endl;
    15.     if((read = (int)getline(&line, &n, stdin)) != -1) {
    16.         y = decnum(line, read-1);
    17.     }
    18.     else
    19.         exit(-1);

    20.     cout << "x = " << x << endl;
    21.     cout << "y = " << y << endl;
    22.     cout << "x * y =" << x * y << endl;
    23.     cout << "x / y =" << x / y << endl;
    24.     cout << "x % y =" << x % y << endl;
    25.     cout << "div(x, y) =" << div(x , y, r) << endl;
    26.     cout << "mod(x, y) =" << r << endl;
    27.     cout << "y ^ 2 =" << pow(y, 2) << endl;
    28.     cout << "x ^ 1/2 =" << root(x, 2) << endl;
    29.     cout << "x is pow = " << x.ispow() << endl;

    30.     return 0;
    31. }
    复制代码

    input x:
    12934891238741902347120934871230948712390487123904871239047812390847123094871230948712309487123904871230947123980471203948712309487120394712398471239048713256129834712903847120394781239084712930487231094712394087123094123481203333333333333333333333333333333333333333333888888888888888888888888888888888888888888888888222222222222222222222222222222222222221094387123908471293048721903487123908412903471290384712398471239847213984712938471209384172093847129834712093847123904123471290384712398471209348712093847120938471297340129341
    input y:
    87123904781239084712309487123094871230948712390487123
    x = 12934891238741902347120934871230948712390487123904871239047812390847123094871230948712309487123904871230947123980471203948712309487120394712398471239048713256129834712903847120394781239084712930487231094712394087123094123481203333333333333333333333333333333333333333333888888888888888888888888888888888888888888888888222222222222222222222222222222222222221094387123908471293048721903487123908412903471290384712398471239847213984712938471209384172093847129834712093847123904123471290384712398471209348712093847120938471297340129341
    y = 87123904781239084712309487123094871230948712390487123
    x * y =1126938232639833173075933852454844491172426928514059866807740841770815249456423275828974308682129087476539239375374114934208988211619943619716558347499808789403504191997992053251495407207133672212198009872845450749525122406765537233683189166639249361344448037097903846536903047332910602617949715068386039572749284661323652396812507276858460341917936752512602597008627491342253724797935606421392773895578442187710885039658694980497445673861077574294718176507864939038642062979105391800654254681231524754223749316701123751673470225808955075291647887679573776980478625133783450814975943
    x / y =148465467327484275048232812439334306695533671227089122007816650126394502951501427671718661140385906942393209068225081817296775831986299773922335101921640962699307587052445014486841122328740344708845214812651256032481988250472736002705523700302442398432754627409724200156670159012028113430398315975429449502269548763370786332836604219524721316400456079938591537603272259855595623013801608933716962712146970686555106278637839124034044858476557783789374654839217122223912234300207
    x % y =79300951666803804539185154310166594060311523590394880
    div(x, y) =148465467327484275048232812439334306695533671227089122007816650126394502951501427671718661140385906942393209068225081817296775831986299773922335101921640962699307587052445014486841122328740344708845214812651256032481988250472736002705523700302442398432754627409724200156670159012028113430398315975429449502269548763370786332836604219524721316400456079938591537603272259855595623013801608933716962712146970686555106278637839124034044858476557783789374654839217122223912234300207
    mod(x, y) =79300951666803804539185154310166594060311523590394880
    y ^ 2 =7590574784330414645380746230930586484532745231159928445672223588351361500455337820516206371351345228817129
    x ^ 1/2 =3596510981318130543477927424759527967760623382196876121688918127992258229306117726707700713885454867164034990294666943466289844107281148419105171980209085534883218753821511324570335831894205011649807156193955342866243572062280023407886590191390520013437462254313721
    x is pow = 0

    论坛徽章:
    0
    16 [报告]
    发表于 2006-08-22 13:09 |只看该作者
    yuxh 弄了一个伟大的工程呀

    论坛徽章:
    1
    荣誉会员
日期:2011-11-23 16:44:17
    17 [报告]
    发表于 2006-08-22 13:12 |只看该作者
    原帖由 思一克 于 2006-8-22 13:09 发表
    yuxh 弄了一个伟大的工程呀


    只是玩玩,呵呵~万里长征才走了第一步哇~

    论坛徽章:
    0
    18 [报告]
    发表于 2006-08-22 15:16 |只看该作者
    搞科学计算最好不用C/C++,传统的用Fortran,现代流行的用Matlab,后者矩阵运算功能超级强大

    论坛徽章:
    0
    19 [报告]
    发表于 2006-08-22 15:29 |只看该作者
    顶起

    论坛徽章:
    0
    20 [报告]
    发表于 2006-08-22 15:46 |只看该作者
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP