优化c ++代码以添加两个数字作为字符串

时间:2014-02-27 08:01:15

标签: c++ optimization biginteger

我一直在研究一个函数,该函数读取两个具有数字的字符串并打印两个总和。例如,如果我通过我的函数传递“100”和“99”,它将打印“199”。我这样做是为了处理100位数字的数字。许多使用运算符重载和类的实现确实在线存在以处理这样的大整数,但我不希望那么多级别的复杂代码。我只想写基本的+, - ,/,*和%操作。我已经写下了以下代码以供添加。但我觉得我应该进一步优化它。有关优化以下代码以及如何以优化方式应用乘法,除法和%运算符的任何提示?

char* Add(char *s1,char *s2)
    {
        char *A,*B;
        int L1=strlen(s1),L2=strlen(s2),La,Lb,i;
        if(L1>=L2)
        {
            A=s1; La=L1;
            B=s2; Lb=L2;
        }
        else
        {
            A=s2; La=L2;
            B=s1; Lb=L1;
        }
        int L=La+2;
        char s[L];
        s[L-1]='\0';
        s[0]='0'; int temp=0;
        for(i=0;i<Lb;i++)
        {
            int x=((int)(A[La-1-i]-'0')+(int)(B[Lb-1-i]-'0'));
            s[L-2-i]=(char)((x+temp)%10+'0');
            temp=x/10;
        }
        for(i=La-Lb-1;i>=0;i--)
        {
            int x=(int)(A[i]-'0');
            s[L-La+i-1]=(char)((x+temp)%10+'0');
            temp=x/10;
        }
        s[0]=(char)(temp+'0');
        char *sum = s[0]!='0' ? &s[0] : &s[1];
        return sum;
   }

问题:

在主函数中我写了类似

的东西
char *c=(char*)Add("99","10"); 
c=(char*)Add(c,"10");
std::cout<<c;

它打印垃圾值。

在main函数中,我写了类似的东西:

char *c=(char*) Add("999999999999999999999999999","10000");
std::cout<<c;

虽然在函数本身中打印“sum”可以得到正确的输出,但我得到的是垃圾值。

关于我的计划的一些观点:

  1. A是两个字符串s1和s2中的较长者,B是两个中较短的一个字符串。
  2. La是A的长度,Lb是B的长度。
  3. s是存储最终结果的字符串,长度为L =(La + 1)+1,因为输出最多比A长1位。
  4. 对于s [1]的第一个字符的总和,如果结果是比A长一个字符,则结果与A和s [0]一样长。 例: 如果A = 100 B = 99,则s = 0199,因此总和指向s [1]。 如果A = 99 B = 99,则s = 198,因此总和指向s [0]。

4 个答案:

答案 0 :(得分:1)

根据您发布的内容,我猜测问题是在堆栈上分配了sum。因此,它仅保证在其封闭范围的生命周期内有效(即,您的Add函数)。您应该在堆上分配一个新的字符缓冲区并返回它。例如,

char* s = new char[L];

编辑:正如其他人指出的那样,您可以考虑使用字符串而不是字符数组。他们有点友善了。

也就是说,如果您不想使用字符串,给定您的代码,上述解决方案可能会泄漏内存(如果s以'0'开头,则为第一个字符)。相反,您可以使用原始代码,按如下方式修改结尾。

    char* sum;
    if (s[0] == '0')
    {
        sum = new char[strlen(s)];
        strcpy(sum,s+1);
    }
    else
    {
        sum = new char[strlen(s) + 1];
        strcpy(sum,s);
    }

同样,最大的问题似乎是ssum是您的函数的本地问题。这意味着在执行函数之后,运行时可以自由地重用它们的内存。使用new允许你做的是将内存分配给“堆”,在释放相关内存之前,运行时不会覆盖它。 Here是一个快速教程,解释了基本概念。


编辑2:正如下面指出的评论者所说,一个错误的错误可能导致溢出。我编辑了上面的代码来摆脱这个问题。但是,这是一个很好的例子,说明为什么最好先使用std::string

答案 1 :(得分:1)

我同意评论“使用std::string” - 总的来说,开销只不过是使用malloc(L)new char[L]进行人工分配,而且它的好处是允许你“发射并忘记”复杂的表达式,例如:

std::string a = "102";
std::string b = "192312";
std::string c = Add(a, Add(b, Add(a, Add(b, a)))); 

显然,我假设你会想要进行泛型数学,而不仅仅是添加,在这种情况下,上面的内容更有意义,例如: c = Add(a, Mul(a, b))c = a + a * b;

如果使用手动分配执行上述复杂调用,则必须存储所有中间值,然后在不再需要时释放它们,例如:

这样:

std::string c = Add(a, Add(b, Add(a, Add(b, a)))); 

变为:

char *tmp1 = Add(b, a); 
char *tmp2 = Add(a, tmp1); 
delete [] tmp1;   // Assuming we use `new`, otherwise `free tmp1` if using `malloc`. 
char *tmp3 = Add(b, tmp2);
delete [] tmp2;
char *c = Add(a, tmp3); 
... do stuff with c
delete [] c; 

std::string也跟踪实际长度,这意味着strlen不再“昂贵” - std::string::length()是一个非常简单的函数,复杂度为O(1) - 其中strlen()是O(n) - 也就是说,它所花费的时间与字符串的长度成正比。

答案 2 :(得分:0)

为了提出改进建议(问题的另一半),我建议停止做那么多不必要的计算。比如说。

for(i=0;i<Lb;i++)
{
    int x=((int)(A[La-1-i]-'0')+(int)(B[Lb-1-i]-'0'));
    s[L-2-i]=(char)((x+temp)%10+'0');
    temp=x/10;
}

最好写成:

int ib,ia,is;
for (
    int ib = Lb-1, int ia = La-1, int is = L-1; 
    ib >= 0; 
    ib--, ia--, is--
) {
    int x=((int)(A[ib]-'0')+(int)(B[ib]-'0'));
    s[is]=(char)((x+temp)%10+'0');
    temp=x/10;
}

每次通过循环时都会保存所有La-1-i计算,并且它们也会使代码更清晰(恕我直言)。

另一点是删除(int)和(char)强制转换;他们不需要。

第三点是不使用除法和模数,如果你可以帮助它 - 它们可能是相对冗长的操作。在这个循环中你知道2位数的加法最多可以是18,所以做x/10太复杂了,可以用简单的if结构替换,比如temp = x>9? x-10: x。同样适用于%。

您可以采取的更具设计性的决策是关于数字的文本和数字表示之间的不断转换。如果你的big-int-strings在计算中花费的时间多于在输入/输出中的时间,那么将它们预转换和后转换它们可能是明智的。因此,首先将文本字符串映射到它的数字形式(每个字符 - ='0'),然后使用此表单进行所有计算,并且只有在再次输出之前,再次使所有数字成为文本字符(每个字符+ =' 0' )。

另一个(微观)优化:不使用后期修复 - 当预修复版本也会这样做时,所以在这里使用--ia而不是ia--。 x--有一些开销,因为它在递减之前返回x的值,这导致像int temp = x, --x, return temp这样的代码。

答案 3 :(得分:0)

我相信如果你想正确地实现除法和模运算符,那么你应该将数字存储为“原始数据”而不是ASCII格式(换句话说,将它表示在base-2而不是base-10)。

下面是我对一个类的实现,该类存储任何可想到的大小的自然数。它支持C ++提供的任何算术运算,并提供一个接口,用于将数字转换为任何基础上的ASCII字符串(最多为base-36,因为除此之外没有更多的数字和字母)。

该数字保持为little-endian,但代码与两种类型的体系结构兼容。

以下是如何使用它来实现char* Add(char *s1,char *s2)功能:

NaturalNum n1 = StringToNaturalNum(s1,10);
NaturalNum n2 = StringToNaturalNum(s2,10);
NaturalNum sum = n1+n2;
int s1len = strlen(s1);
int s2len = strlen(s2);
char* str = new char[MAX(s1len,s2len)+2];
sum.ToString(str,10);
return str;

以下是NaturalNum类本身的实现:

File NaturalNum.h:

#ifndef NATURAL_NUM_H
#define NATURAL_NUM_H


class NaturalNum
{
public: //Constructors + Destructor
    NaturalNum();
    virtual ~NaturalNum();
    NaturalNum(unsigned int iNaturalNum);
    NaturalNum(const NaturalNum& cNaturalNum);
    //---------------------------------------------------------------------------------------------
public: //Assignment Operators
    virtual const NaturalNum& operator=(const NaturalNum& cNaturalNum);
    virtual const NaturalNum& operator+=(const NaturalNum& cNaturalNum);
    virtual const NaturalNum& operator-=(const NaturalNum& cNaturalNum);
    virtual const NaturalNum& operator*=(const NaturalNum& cNaturalNum);
    virtual const NaturalNum& operator/=(const NaturalNum& cNaturalNum);
    virtual const NaturalNum& operator%=(const NaturalNum& cNaturalNum);
    virtual const NaturalNum& operator|=(const NaturalNum& cNaturalNum);
    virtual const NaturalNum& operator&=(const NaturalNum& cNaturalNum);
    virtual const NaturalNum& operator^=(const NaturalNum& cNaturalNum);
    virtual const NaturalNum& operator<<=(unsigned int iShift);
    virtual const NaturalNum& operator>>=(unsigned int iShift);
    //---------------------------------------------------------------------------------------------
public: //Unary Operators
    virtual NaturalNum operator~() const;
    virtual const NaturalNum& operator++();
    virtual const NaturalNum& operator--();
    virtual NaturalNum operator++(int dummy);
    virtual NaturalNum operator--(int dummy);
    //---------------------------------------------------------------------------------------------
public: //Binary Operators
    friend NaturalNum operator+(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend NaturalNum operator-(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend NaturalNum operator*(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend NaturalNum operator/(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend NaturalNum operator%(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend NaturalNum operator|(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend NaturalNum operator&(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend NaturalNum operator^(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    virtual NaturalNum operator<<(unsigned int iShift) const;
    virtual NaturalNum operator>>(unsigned int iShift) const;
    //---------------------------------------------------------------------------------------------
public: //Binary Comperators
    friend bool operator<(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend bool operator>(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend bool operator==(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend bool operator<=(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend bool operator>=(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    friend bool operator!=(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2);
    //---------------------------------------------------------------------------------------------
public: //Interface Routines
    unsigned int BitCount() const;
    void ToBuffer(unsigned char aBuffer[]) const;
    void ToString(char aString[],unsigned int iBase) const;
    friend NaturalNum StringToNaturalNum(const char aString[],unsigned int iBase);
    //---------------------------------------------------------------------------------------------
protected: //Internal Routines
    void Allocate(unsigned int iBytes);
    void DeallocateAll();
    void RemoveRedundantZeros();
    //---------------------------------------------------------------------------------------------
protected: //Object Attributes
    unsigned int   m_iLength;
    unsigned char* m_aValues;
    //---------------------------------------------------------------------------------------------
};


#endif

File NaturalNum.cpp:

#include "NaturalNum.h"


///////////////////////////////////////
// Constructors + Destructor (below) //


NaturalNum::NaturalNum()
{
    Allocate(0);
}


NaturalNum::~NaturalNum()
{
    DeallocateAll();
}


NaturalNum::NaturalNum(unsigned int iNaturalNum)
{
    Allocate(sizeof(iNaturalNum));

    for (unsigned int i=0; i<m_iLength; i++)
        m_aValues[i]=iNaturalNum>>(i*8);

    RemoveRedundantZeros();
}


NaturalNum::NaturalNum(const NaturalNum& cNaturalNum)
{
    Allocate(0);
    *this=cNaturalNum;
}


// Constructors + Destructor (above) //
///////////////////////////////////////


//////////////////////////////////
// Assignment Operators (below) //


const NaturalNum& NaturalNum::operator=(const NaturalNum& cNaturalNum)
{
    if (this==&cNaturalNum)
        return *this;

    DeallocateAll();
    Allocate(cNaturalNum.m_iLength);

    for (unsigned int i=0; i<m_iLength; i++)
        m_aValues[i]=cNaturalNum.m_aValues[i];

    return *this;
}


const NaturalNum& NaturalNum::operator+=(const NaturalNum& cNaturalNum)
{
    return *this=*this+cNaturalNum;
}


const NaturalNum& NaturalNum::operator-=(const NaturalNum& cNaturalNum)
{
    return *this=*this-cNaturalNum;
}


const NaturalNum& NaturalNum::operator*=(const NaturalNum& cNaturalNum)
{
    return *this=*this*cNaturalNum;
}


const NaturalNum& NaturalNum::operator/=(const NaturalNum& cNaturalNum)
{
    return *this=*this/cNaturalNum;
}


const NaturalNum& NaturalNum::operator%=(const NaturalNum& cNaturalNum)
{
    return *this=*this%cNaturalNum;
}


const NaturalNum& NaturalNum::operator|=(const NaturalNum& cNaturalNum)
{
    return *this=*this|cNaturalNum;
}


const NaturalNum& NaturalNum::operator&=(const NaturalNum& cNaturalNum)
{
    return *this=*this&cNaturalNum;
}


const NaturalNum& NaturalNum::operator^=(const NaturalNum& cNaturalNum)
{
    return *this=*this^cNaturalNum;
}


const NaturalNum& NaturalNum::operator<<=(unsigned int iShift)
{
    return *this=*this<<iShift;
}


const NaturalNum& NaturalNum::operator>>=(unsigned int iShift)
{
    return *this=*this>>iShift;
}


// Assignment Operators (above) //
//////////////////////////////////


/////////////////////////////
// Unary Operators (below) //


NaturalNum NaturalNum::operator~() const
{
    NaturalNum cRes;
    cRes.Allocate(m_iLength);

    for (unsigned int i=0; i<m_iLength; i++)
        cRes.m_aValues[i]=~m_aValues[i];

    return cRes;
}


const NaturalNum& NaturalNum::operator++()
{
    *this+=1;
    return *this;
}


const NaturalNum& NaturalNum::operator--()
{
    *this-=1;
    return *this;
}


NaturalNum NaturalNum::operator++(int dummy)
{
    NaturalNum cRes=*this;
    *this+=1;
    return cRes;
}


NaturalNum NaturalNum::operator--(int dummy)
{
    NaturalNum cRes=*this;
    *this-=1;
    return cRes;
}


// Unary Operators (above) //
/////////////////////////////


//////////////////////////////
// Binary Operators (below) //


NaturalNum operator+(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    if (cNaturalNum2.m_iLength<cNaturalNum1.m_iLength)
        return cNaturalNum2+cNaturalNum1;

    NaturalNum cRes;
    cRes.Allocate(cNaturalNum2.m_iLength+1);

    unsigned int   i;
    unsigned short iSum;
    unsigned char  iRem=0;

    for (i=0; i<cNaturalNum1.m_iLength; i++)
    {
        iSum=iRem+cNaturalNum1.m_aValues[i]+cNaturalNum2.m_aValues[i];
        cRes.m_aValues[i]=iSum&0xFF;
        iRem=iSum>>8;
    }
    for (; i<cNaturalNum2.m_iLength; i++)
    {
        iSum=iRem+cNaturalNum2.m_aValues[i];
        cRes.m_aValues[i]=iSum&0xFF;
        iRem=iSum>>8;
    }
    cRes.m_aValues[i]=iRem;

    cRes.RemoveRedundantZeros();
    return cRes;
}


NaturalNum operator-(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    if (cNaturalNum2>cNaturalNum1)
        throw "Negative Result";

    NaturalNum cRes;
    cRes.Allocate(cNaturalNum1.m_iLength);

    unsigned int i;
    signed short iDif;
    signed char  iRem=0;

    for (i=0; i<cNaturalNum2.m_iLength; i++)
    {
        iDif=iRem+cNaturalNum1.m_aValues[i]-cNaturalNum2.m_aValues[i];
        cRes.m_aValues[i]=iDif&0xFF;
        iRem=iDif>>8;
    }
    for (; i<cNaturalNum1.m_iLength; i++)
    {
        iDif=iRem+cNaturalNum1.m_aValues[i];
        cRes.m_aValues[i]=iDif&0xFF;
        iRem=iDif>>8;
    }

    cRes.RemoveRedundantZeros();
    return cRes;
}


NaturalNum operator*(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    NaturalNum cRes=0;

    for (unsigned int i=0; i<cNaturalNum1.m_iLength; i++)
        for (unsigned int j=0; j<cNaturalNum2.m_iLength; j++)
            cRes+=(NaturalNum)(cNaturalNum1.m_aValues[i]*cNaturalNum2.m_aValues[j])<<((i+j)*8);

    return cRes;
}


NaturalNum operator/(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    if (cNaturalNum2==0)
        throw "Infinite Result";

    NaturalNum cRes=0;

    NaturalNum cTmp1=cNaturalNum1;
    unsigned int iTmp1Len=cTmp1.BitCount();
    unsigned int iNaturalNum2Len=cNaturalNum2.BitCount();

    while (iTmp1Len>iNaturalNum2Len)
    {
        cRes+=(NaturalNum)1<<(iTmp1Len-iNaturalNum2Len-1);
        cTmp1-=cNaturalNum2<<(iTmp1Len-iNaturalNum2Len-1);
        iTmp1Len=cTmp1.BitCount();
    }

    if (cTmp1>=cNaturalNum2)
        return cRes+1;

    return cRes;
}


NaturalNum operator%(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    return cNaturalNum1-cNaturalNum1/cNaturalNum2*cNaturalNum2;
}


NaturalNum operator|(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    if (cNaturalNum2.m_iLength<cNaturalNum1.m_iLength)
        return cNaturalNum2|cNaturalNum1;

    NaturalNum cRes;
    cRes.Allocate(cNaturalNum2.m_iLength);

    unsigned int i;
    for (i=0; i<cNaturalNum1.m_iLength; i++)
        cRes.m_aValues[i]=cNaturalNum1.m_aValues[i]|cNaturalNum2.m_aValues[i];
    for (; i<cNaturalNum2.m_iLength; i++)
        cRes.m_aValues[i]=0|cNaturalNum2.m_aValues[i];

    cRes.RemoveRedundantZeros();
    return cRes;
}


NaturalNum operator&(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    if (cNaturalNum2.m_iLength<cNaturalNum1.m_iLength)
        return cNaturalNum2&cNaturalNum1;

    NaturalNum cRes;
    cRes.Allocate(cNaturalNum2.m_iLength);

    unsigned int i;
    for (i=0; i<cNaturalNum1.m_iLength; i++)
        cRes.m_aValues[i]=cNaturalNum1.m_aValues[i]&cNaturalNum2.m_aValues[i];
    for (; i<cNaturalNum2.m_iLength; i++)
        cRes.m_aValues[i]=0&cNaturalNum2.m_aValues[i];

    cRes.RemoveRedundantZeros();
    return cRes;
}


NaturalNum operator^(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    if (cNaturalNum2.m_iLength<cNaturalNum1.m_iLength)
        return cNaturalNum2^cNaturalNum1;

    NaturalNum cRes;
    cRes.Allocate(cNaturalNum2.m_iLength);

    unsigned int i;
    for (i=0; i<cNaturalNum1.m_iLength; i++)
        cRes.m_aValues[i]=cNaturalNum1.m_aValues[i]^cNaturalNum2.m_aValues[i];
    for (; i<cNaturalNum2.m_iLength; i++)
        cRes.m_aValues[i]=0^cNaturalNum2.m_aValues[i];

    cRes.RemoveRedundantZeros();
    return cRes;
}


NaturalNum NaturalNum::operator<<(unsigned int iShift) const
{
    unsigned int iByteShift=iShift/8;
    unsigned int iBitsShift=iShift%8;

    if (m_iLength==0)
        return 0;

    NaturalNum cRes;
    cRes.Allocate(m_iLength+iByteShift+1);

    for (unsigned int n=0; n<iByteShift; n++)
        cRes.m_aValues[n]=0;

    unsigned int  i;
    unsigned char iRem=0;
    for (i=iByteShift; i<m_iLength+iByteShift; i++)
    {
        cRes.m_aValues[i]=(m_aValues[i-iByteShift]<<iBitsShift)|iRem;
        iRem=m_aValues[i-iByteShift]>>(8-iBitsShift);
    }
    cRes.m_aValues[i]=iRem;

    cRes.RemoveRedundantZeros();
    return cRes;
}


NaturalNum NaturalNum::operator>>(unsigned int iShift) const
{
    unsigned int iByteShift=iShift/8;
    unsigned int iBitsShift=iShift%8;

    if (m_iLength<=iByteShift)
        return 0;

    NaturalNum cRes;
    cRes.Allocate(m_iLength-iByteShift);

    unsigned int  i;
    unsigned char iRem;
    for (i=0; i<m_iLength-iByteShift-1; i++)
    {
        iRem=m_aValues[i+iByteShift+1]<<(8-iBitsShift);
        cRes.m_aValues[i]=(m_aValues[i+iByteShift]>>iBitsShift)|iRem;
    }
    iRem=m_aValues[i+iByteShift]>>iBitsShift;
    cRes.m_aValues[i]=iRem;

    cRes.RemoveRedundantZeros();
    return cRes;
}


// Binary Operators (above) //
//////////////////////////////


////////////////////////////////
// Binary Comperators (below) //


bool operator<(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    if (cNaturalNum1.m_iLength!=cNaturalNum2.m_iLength)
        return cNaturalNum1.m_iLength<cNaturalNum2.m_iLength;

    for (unsigned int i=cNaturalNum1.m_iLength; i>0; i--)
        if (cNaturalNum1.m_aValues[i-1]!=cNaturalNum2.m_aValues[i-1])
            return cNaturalNum1.m_aValues[i-1]<cNaturalNum2.m_aValues[i-1];

    return false;
}


bool operator>(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    if (cNaturalNum1.m_iLength!=cNaturalNum2.m_iLength)
        return cNaturalNum1.m_iLength>cNaturalNum2.m_iLength;

    for (unsigned int i=cNaturalNum1.m_iLength; i>0; i--)
        if (cNaturalNum1.m_aValues[i-1]!=cNaturalNum2.m_aValues[i-1])
            return cNaturalNum1.m_aValues[i-1]>cNaturalNum2.m_aValues[i-1];

    return false;
}


bool operator==(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    if (cNaturalNum1.m_iLength!=cNaturalNum2.m_iLength)
        return false;

    for (unsigned int i=cNaturalNum1.m_iLength; i>0; i--)
        if (cNaturalNum1.m_aValues[i-1]!=cNaturalNum2.m_aValues[i-1])
            return false;

    return true;
}


bool operator<=(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    return !(cNaturalNum1>cNaturalNum2);
}


bool operator>=(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    return !(cNaturalNum1<cNaturalNum2);
}


bool operator!=(const NaturalNum& cNaturalNum1,const NaturalNum& cNaturalNum2)
{
    return !(cNaturalNum1==cNaturalNum2);
}


// Binary Comperators (above) //
////////////////////////////////


////////////////////////////////
// Interface Routines (below) //


unsigned int NaturalNum::BitCount() const
{
    if (m_iLength==0)
        return 0;

    unsigned int iBitCount=(m_iLength-1)*8;
    for (unsigned int i=1; i<=m_aValues[m_iLength-1]; i<<=1)
        iBitCount++;

    return iBitCount;
}


void NaturalNum::ToBuffer(unsigned char aBuffer[]) const
{
    for (unsigned int i=0; i<m_iLength; i++)
        aBuffer[i]=m_aValues[i];
}


void NaturalNum::ToString(char aString[],unsigned int iBase) const
{
    unsigned int iIndex=0;

    for (NaturalNum cTmp=*this; cTmp>0; cTmp/=iBase)
    {
        NaturalNum cDigit=cTmp%iBase;
        if (cDigit==0)
            aString[iIndex]='0';
        else if (cDigit<10)
            aString[iIndex]='0'+cDigit.m_aValues[0];
        else
            aString[iIndex]='A'+cDigit.m_aValues[0]-10;
        iIndex++;
    }

    for (unsigned int i=0; i<iIndex/2; i++)
    {
        char iDigit=aString[i];
        aString[i]=aString[iIndex-1-i];
        aString[iIndex-1-i]=iDigit;
    }

    if (iIndex==0)
        aString[iIndex++]='0';

    aString[iIndex]=0;
}


NaturalNum StringToNaturalNum(const char aString[],unsigned int iBase)
{
    NaturalNum cRes=0;

    for (unsigned int i=0; aString[i]!=0; i++)
    {
        NaturalNum cDigit;
        if ('0'<=aString[i] && aString[i]<='9')
            cDigit=aString[i]-'0';
        else if ('A'<=aString[i] && aString[i]<='Z')
            cDigit=aString[i]-'A'+10;
        else if ('a'<=aString[i] && aString[i]<='z')
            cDigit=aString[i]-'a'+10;
        else
            break;
        cRes*=iBase;
        cRes+=cDigit;
    }

    return cRes;
}


// Interface Routines (above) //
////////////////////////////////


///////////////////////////////
// Internal Routines (below) //


void NaturalNum::Allocate(unsigned int iBytes)
{
    m_iLength=iBytes;
    if (m_iLength>0)
        m_aValues=new unsigned char[m_iLength];
}


void NaturalNum::DeallocateAll()
{
    if (m_iLength>0)
        delete[] m_aValues;
    m_iLength=0;
}


void NaturalNum::RemoveRedundantZeros()
{
    while (m_iLength>0 && m_aValues[m_iLength-1]==0)
        if (--m_iLength==0)
            delete[] m_aValues;
}


// Internal Routines (above) //
///////////////////////////////