最近群里有人聊N! (N<=100) 于是发现这种代码的复用还是有点意义的,于是把自己曾经写的一个numberSystem子库公布下。


它能够实现任意精度的带小数位在任意进制下的任意加减乘除余等等。

自从写BinaryTree泛化类采用down-up原语设计后,我就一直喜欢在写内聚性很强的东西时,从元操作(原语)开始实现,之后其他所有之上的操作都能通过几个原语的组合实现。所以能够避免混乱的代码结构和浪费大量调试时间。


/**/ /*numberSystem.cpp :vgl::numberSystem*/
/**/ /*----------------------------------------------------------------------------
Simple v1.2
Developer: Zblc
vgl::numberSystem

classes:
    numberSystem                            :大数类
                                        

macros:
    BigReal(STR)                            :临时测试用大数对象

global variable:
    numberSystem VGL_G_TEMP;                :临时传递用对象
    char VGL_G_TEMP_STR[MAX_DIGIT];         :临时传递用字符串

include:
    base.h                                  :VGL基库
    string.h                                :VGL泛型字符串库 
--------------------------- --------------------------------------------------
*/





#ifndef NUMBERSYSTEM__
#define  NUMBERSYSTEM__


#include 
" base.h "
#include 
" string.h "
#define  MAX_DIGIT 500


#define  BigReal(STR)  (*(numberSystem*)( new numberSystem(STR)) )



class  numberSystem
{

private:
    
int radix;
    
int num[MAX_DIGIT];
    
int len;
    
char sign;
    
int decNum;//decreasing Digit till dot
    void init(int Radix=10);
    
void init(int *Num,int Len=0,int Radix=10,int DecNum=-1);
    
void init(char *Num,int Len=0,int Radix=10);
    
void addFrontZero(numberSystem& obj,int Num);
    
void addBackZero(numberSystem& obj,int Num);
    
void delFrontZero(numberSystem & obj);
    
void delBackZero(numberSystem& obj);
    
void balanceNumber(numberSystem& First,numberSystem& Second);
    
void cleanNumber(numberSystem& Obj);
    
    
void addStrict(numberSystem & Right,numberSystem & Result);
    
void subtractStrict(numberSystem & Right,numberSystem & Result);
    
void mulStrict(int Factor,numberSystem & Result);
    
int getMaxFactor(numberSystem& Obj,numberSystem& Multi);
    
int smallerThanAsInt(numberSystem& Copy);
    
public:
    numberSystem();
    numberSystem(
int Radix);
    numberSystem(
int *Num,int Len=0,char Sign='+',int DecNum=-1,int Radix=10);
    numberSystem(
char *Num,int Len=0,char Sign='+',int Radix=10);
    
void add(numberSystem & Right,numberSystem & Result);
    
void sub(numberSystem & Right,numberSystem & Result);
    
void mul(numberSystem & Right,numberSystem & Result);
    
void div(numberSystem & Right,numberSystem & Result);
    
void mod(numberSystem & Right,numberSystem & Result);

    
    
char getSign();
    
int getLen();
    
int* getNum();
    
char* toChars();
    adt::
string toString();
    numberSystem getInteger();
    numberSystem getDecimal();
    
    
    
int* operator ()();
    
int& operator[](int i);
    
int operator > (numberSystem& Copy);
    
int operator >= (numberSystem& Copy);
    
int operator <= (numberSystem& Copy);
    
int operator < (numberSystem& Copy);
    
int operator == (numberSystem& Copy);
    
int operator == (char* strNum);
    numberSystem 
operator +(numberSystem& Right);
    numberSystem 
operator +=(numberSystem& Right);

    numberSystem 
operator -(numberSystem& Right);
    numberSystem 
operator -=(numberSystem& Right);

    numberSystem 
operator *(numberSystem& Right);
    numberSystem 
operator *=(numberSystem& Right);

    numberSystem 
operator /(numberSystem& Right);
    numberSystem 
operator /=(numberSystem& Right);

    numberSystem 
operator %(numberSystem& Right);
    numberSystem 
operator %=(numberSystem& Right);

    numberSystem
& operator=(const numberSystem& Copy);

    
}
;


#endif




#include  " numberSystem.h "

numberSystem VGL_G_TEMP;
char  VGL_G_TEMP_STR[MAX_DIGIT];
numberSystem numberSystem::
operator   + (numberSystem &  Right)
{
    add(Right,VGL_G_TEMP);
    
return VGL_G_TEMP;
}

numberSystem numberSystem::
operator   += (numberSystem &  Right)
{
    add(Right,
*this);
    
return *this;
}

numberSystem numberSystem::
operator   - (numberSystem &  Right)
{
    sub(Right,VGL_G_TEMP);
    
return VGL_G_TEMP;
}

numberSystem numberSystem::
operator   -= (numberSystem &  Right)
{
    sub(Right,
*this);
    
return *this;
}

numberSystem numberSystem::
operator   * (numberSystem &  Right)
{
    mul(Right,VGL_G_TEMP);
    
return VGL_G_TEMP;
}

numberSystem numberSystem::
operator   *= (numberSystem &  Right)
{
    mul(Right,
*this);
    
return *this;
}

numberSystem numberSystem::
operator   / (numberSystem &  Right)
{
    div(Right,VGL_G_TEMP);
    
return VGL_G_TEMP;
}

numberSystem numberSystem::
operator   /= (numberSystem &  Right)
{
    div(Right,
*this);
    
return *this;
}

numberSystem numberSystem::
operator   % (numberSystem  &  Right)
{
    mod(Right,VGL_G_TEMP);
    
return VGL_G_TEMP;
}

numberSystem numberSystem::
operator   %= (numberSystem  &  Right)
{
    mod(Right,
*this);
    
return *this;
}

void  numberSystem::init( int  Radix /**/ /*=10*/ )
{
    decNum
=-1;
    radix
=Radix;
}

void  numberSystem::init( int   * Num, int  Len /**/ /*=0*/ , int  Radix /**/ /*=10*/ , int  DecNum /**/ /*=-1*/ )
{
    decNum
=DecNum;
    radix
=Radix ;
    
if(!Len)
        
for(;Num[Len]<=-1;Len++);
    
else if(Len<0)
        TEST_THROW(
"numberSystem::init(..)")
        len
=Len;
    
for(;Len!=0;Len--)
        num[Len
-1]=Num[Len-1];
}

void  numberSystem::init( char   * Num, int  Len /**/ /*=0*/ , int  Radix /**/ /*=10*/ )
{
    decNum
=-1;
    radix
=Radix ;
    
if(!Len)
        
for(;Num[Len]!='\0';Len++);
    
else if(Len<0)
        TEST_THROW(
"numberSystem::init(..)")
        len
=Len;

    
int k=0,j=0,tag=0;
    
if(Num[0]=='+')
        sign
='+',Num++,tag=1,len--;
    
else if(Num[0]=='-')
        sign
='-',Num++,tag=1,len--;

    Len
-=tag;
    
for(;j!=Len;j++)
        
if(Num[j]!='.')
        
{
            num[k]
=Num[j]-48;
            k
++;
        }
else
        
{
            decNum
=j;
            len
--;
        }

    
if(decNum==-1)
        decNum
=len;

}

void  numberSystem::addFrontZero(numberSystem &  obj, int  Num)
{
    
for(int i=obj.len+Num-1;i!=Num-1;i--)
        obj.num[i]
=obj.num[i-Num];

    
for(int i=0;i!=Num;i++)
        obj.num[i]
=0;

    obj.decNum
+=Num;
    obj.len
+=Num;
}

void  numberSystem::addBackZero(numberSystem &  obj, int  Num)
{
    
for(int i=0;i!=Num;i++)
        obj.num[i
+obj.len]=0;
    obj.len
+=Num;

}

void  numberSystem::delFrontZero(numberSystem  &  obj)
{
    
if(obj.len==1||(obj.decNum==1))
        
return;

    
int k=0;
    
for(;(k!=obj.len)&&(obj.num[k]==0)&&(k!=obj.decNum);k++);


    
if(k==obj.decNum)
        k
--;
    
for(int i=0;i!=obj.len-k;i++)
        obj.num[i]
=obj.num[i+k];

    
if(k==obj.len)
    
{

        obj.num[
0]=0;
        
--k;
    }


    obj.len
-=k;
    
if(obj.decNum>0)
        obj.decNum
-=k;

}

void  numberSystem::delBackZero(numberSystem &  obj)
{
    
int i=obj.len-1;
    
for(;;i--)
    
{
        
if(obj.num[i]==0&&i>obj.decNum-1)
            obj.len
--;
        
else
            
return;
    }

}

void  numberSystem::balanceNumber(numberSystem &  First,numberSystem &  Second)
{
    
if(First.decNum>Second.decNum)
    
{
        addFrontZero(Second,First.decNum
-Second.decNum);
    }

    
else if(First.decNum<Second.decNum)
    
{
        addFrontZero(First,Second.decNum
-First.decNum);
    }



    
if(First.len-First.decNum>Second.len-Second.decNum)
    
{
        addBackZero(Second,(First.len
-First.decNum)-(Second.len-Second.decNum));
    }

    
else if(First.len-First.decNum<Second.len-Second.decNum)
    
{

        addBackZero(First,(Second.len
-Second.decNum)-(First.len-First.decNum));
    }

}

void  numberSystem::cleanNumber(numberSystem &  Obj)
{
    delFrontZero(Obj);
    delBackZero(Obj);
}


void  numberSystem::addStrict(numberSystem  &  Right,numberSystem  &  Result)
{
    
if(radix!=Right.radix)
        TEST_THROW(
"numberSystem:operands differed in radix");

    numberSystem First
=*this,Second=Right;
    
int i,carry=0;

    balanceNumber(First,Second);

    i
=First.len;
    Result.init(radix);
    Result.decNum
=First.decNum+1;
    Result.len
=i+1;

    
for(;i!=0;i--)
    
{
        Result.num[i]
=(carry+First[i-1]+Second[i-1])%radix;
        carry
=(carry+First[i-1]+Second[i-1])/radix;
    }


    Result[i]
=carry;
    cleanNumber(Result);

}

void  numberSystem::subtractStrict(numberSystem  &  Right,numberSystem  &  Result)
{
    
if(radix!=Right.radix)
        TEST_THROW(
"numberSystem:operands differed in radix");

    numberSystem First
=*this,Second=Right;

    
int i,carry=0;

    balanceNumber(First,Second);

    
if(First.smallerThanAsInt(Second))
    
{
        atom::swap(First,Second);
        Result.sign
='-';
    }
else
    
{
        Result.sign
='+';
    }


    i
=First.len-1;
    Result.init(radix);
    Result.decNum
=First.decNum;
    Result.len
=i+1;

    
for(;i!=-1;i--)
        
if(First[i]+carry>=Second[i])
        
{
            Result.num[i]
=First[i]-Second[i]+carry;
            carry
=0;
        }
else
        
{
            Result.num[i]
=radix-Second[i]+First[i]+carry;
            carry
=-1;
        }

    cleanNumber(Result);

}

void  numberSystem::mulStrict( int  Factor,numberSystem  &  Result)
{
    Result.init(radix);
    
int carry=0,i=len-1,j=len;
    
for(;i!=-1;i--,j--)
    
{
        Result.num[j]
=(num[i]*Factor+carry)%radix;

        carry
=(num[i]*Factor+carry)/radix;
    }

    Result.num[j]
=carry;
    Result.len
=len+1;
    Result.decNum
=Result.len;
    delFrontZero(Result);    
}



int  numberSystem::getMaxFactor(numberSystem &  Obj,numberSystem &  Multi)
/**/ /* Obj>=Multi*MAX(Result) */
{
    
if(Obj.radix!=Multi.radix)
        TEST_THROW(
"numberSystem: in getMaxFactor radixes differ ");
    numberSystem _temp(Obj.radix);
    
for(int i=9;i!=-1;i--)
    
{
        Multi.mulStrict(i,_temp);

        
if(!Obj.smallerThanAsInt(_temp))
        
{
            
return i;
        }

    }

    
return 0;
}


numberSystem::numberSystem():radix(
10 ),len( 0 ),sign( ' + ' )
{
}

numberSystem::numberSystem(
int  Radix):radix(Radix),len( 0 ),sign( ' + ' )
{
}

numberSystem::numberSystem(
int   * Num, int  Len /**/ /*=0*/ , char  Sign /**/ /*='+'*/ , int  DecNum /**/ /*=-1*/ , int  Radix /**/ /*=10*/ )
:radix(Radix),sign(Sign)
{
    init(Num,Len,Radix,DecNum);
}

numberSystem::numberSystem(
char   * Num, int  Len /**/ /*=0*/ , char  Sign /**/ /*='+'*/ , int  Radix /**/ /*=10*/ )
:radix(Radix),sign(Sign)
{
    init(Num,Len,Radix);
}

void  numberSystem::add(numberSystem  &  Right,numberSystem  &  Result)
{
    
if(sign=='+')
    
{
        
if(Right.sign=='+')
        
{
            addStrict(Right,Result);

        }
else
        
{
            subtractStrict(Right,Result);
        }

    }
else if(sign=='-')
    
{
        
if(Right.sign=='+')
        
{
            Right.subtractStrict(
*this,Result);

        }
else
        
{
            addStrict(Right,Result);
            Result.sign
='-';
        }

    }


}

void  numberSystem::sub(numberSystem  &  Right,numberSystem  &  Result)
{
    
if(sign=='+')
    
{
        
if(Right.sign=='+')
        
{
            subtractStrict(Right,Result);
        }
else
        
{
            addStrict(Right,Result);
        }

    }
else if(sign=='-')
    
{
        
if(Right.sign=='+')
        
{
            addStrict(Right,Result);
            Result.sign
='-';
        }
else
        
{
            Right.subtractStrict(
*this,Result);
        }

    }


}

void  numberSystem::mul(numberSystem  &  Right,numberSystem  &  Result)
{
    numberSystem First
=*this,Second=Right;
    Result.init(
"0");
    numberSystem _temp(
"0"),_temp2("0");
    
int Decimal=First.len+Second.len-First.decNum-Second.decNum;


    
int dig=0;
    
for(int i=Second.len-1;i!=-1;i--,dig++){
        First.mulStrict(Second.num[i],_temp);

        
for(int j=0;j!=dig;j++)
        
{
            _temp.num[_temp.len
++]=0;
            _temp.decNum
++;
        }

        _temp.add(_temp2,_temp2);

    }

    Result
=_temp2;
    Result.decNum
=Result.len-Decimal;
    cleanNumber(Result);
    
if(sign==Right.sign)
    
{
        Result.sign
='+';
    }
else
    
{
        Result.sign
='-';
    }


}

void  numberSystem::div(numberSystem  &  Right,numberSystem  &  Result)
{
    
if(sign==Right.sign) Result.sign='+';
    
else Result.sign='-';
    
if(Right=="0")
        TEST_THROW(
"numberSystem: in div divisor is zero ");
    
if((*this)=="0"){
        Result
=(*this);
        
return ;
    }

    numberSystem First
=*this,Second=Right,_temp(radix),_temp2("10");
    
int i=0,j=0,k=max(len-decNum,Right.len-Right.decNum);
    Result.init(
"");

    
for(int t=0;t!=k;t++){
        First.mul(_temp2,First);
        Second.mul(_temp2,Second);
    }

    
for(;Result.len!=MAX_DIGIT;){
        
for(int s=0;_temp.smallerThanAsInt(Second);s++){
            _temp.num[_temp.len
++]=First.num[i++];
            
if(s>0){
                Result.num[Result.len
++]=0;
                
if(i-1<=First.len)
                    Result.decNum
++;
            }
            
            
if(i>=First.len) First.num[i]=0;
            _temp.decNum
=_temp.len;
            cleanNumber(_temp);
            
if(_temp=="0"break;
        }

        i
<=First.len?Result.decNum++:1;
        Result.num[Result.len
++]=getMaxFactor(_temp,Second);
        Second.mulStrict(Result.num[Result.len
-1],_temp2);
        _temp.sub(_temp2,_temp);
        
if((_temp=="0")&&(i>=First.len))
            
break;
    }

    cleanNumber(Result);

}


int *  numberSystem:: operator  ()()
{
    
return num;
}

int *  numberSystem::getNum()
{
    
return num;
}

int &  numberSystem:: operator []( int  i)
{
    
return num[i];
}


int  numberSystem::getLen()
{
    
return len;
}

char  numberSystem::getSign()
{
    
return sign;
}

numberSystem
&  numberSystem:: operator = ( const  numberSystem &  Copy)
{
    sign
=Copy.sign;
    len
=Copy.len;
    radix
=Copy.radix;
    decNum
=Copy.decNum;

    
for(int i=0;i!=Copy.len;i++)
        num[i]
=Copy.num[i];

    
return *this;
}

int  numberSystem:: operator   >  (numberSystem &  Copy)
{
    
if(radix!=Copy.radix)
        TEST_THROW(
"numberSystem: in operator <  radixes differ ");

    
if(*this==Copy)
        
return 0;
    
return (*this-Copy).sign=='+'?1:0;
}

int  numberSystem:: operator   >=  (numberSystem &  Copy)
{
    
return !(*this<Copy);
}

int  numberSystem:: operator   <=  (numberSystem &  Copy)
{
    
return !(*this>Copy);
}

int  numberSystem:: operator   <  (numberSystem &  Copy)
{
    
if(radix!=Copy.radix)
        TEST_THROW(
"numberSystem: in operator <  radixes differ ");

    
if(*this==Copy)
        
return 0;
    
return (*this-Copy).sign=='+'?0:1;
}

int  numberSystem::smallerThanAsInt(numberSystem &  Copy)
{
    
if(len<Copy.len)
        
return 1;
    
else if(len>Copy.len)
        
return 0;

    
for(int i=0;i!=len;i++)
        
if(num[i]<Copy.num[i])
            
return 1;
        
else if(num[i]>Copy.num[i])
            
return 0;

    
return 0;
}

int  numberSystem:: operator   ==  (numberSystem &  Copy)
{
    
if(radix!=Copy.radix)
        TEST_THROW(
"numberSystem: in operator ==  radixes differ ");

    
if(len!=Copy.len)
        
return 0;

    
if(sign!=Copy.sign)
        
return 0;

    
for(int i=0;i!=len;i++)
        
if(num[i]!=Copy.num[i])    
            
return 0;

    
return 1;
}

int  numberSystem:: operator   ==  ( char *  strNum)
{
    VGL_G_TEMP.init(strNum);
    
return VGL_G_TEMP==*this;
}


char *  numberSystem::toChars()
{
    adt::
string _temp=toString();
    
for(int i=0;i!=_temp.len;i++)
        VGL_G_TEMP_STR[i]
=_temp[i];
    
return VGL_G_TEMP_STR;

}

adt::
string  numberSystem::toString()
{
    adt::
string _temp;
    
if(sign=='-')
        _temp
<<'-';
    
for(int i=0;i!=len;i++)
        
if(decNum!=i)
            _temp
<<(char)(num[i]+48);
        
else
            _temp
<<'.'<<(char)(num[i]+48);
    _temp
<<(char)0;
    
return _temp;
}



numberSystem numberSystem::getInteger()
{
    VGL_G_TEMP
=*this;
    VGL_G_TEMP.len
=VGL_G_TEMP.decNum;
    VGL_G_TEMP.sign
='+';
    
return VGL_G_TEMP;
}

numberSystem numberSystem::getDecimal()
{
    
return *this-getInteger();
}


void  numberSystem::mod(numberSystem  &  Right,numberSystem  &  Result)
{
    
if(this->len!=this->decNum||Right.len!=Right.decNum)
        TEST_THROW(
"numberSystem: in function mod  ,the legal number appears");
    numberSystem First
=*this,Second=Right;
    First.sign
='+';
    Second.sign
='+';
    Result
=First-(((First)/Second).getInteger())*Second;
    Result.sign
=(this->sign==Right.sign)?'+':'-';
}



关于case 就不发了,想执行的可以留言,因为还涉及到公共基础子库的引入.