大數運算(加減乘除)

大數運算的實現方法主要有以下幾種:
1) 用字符串表示大數。將大數用十進制字符數組表示,然後按照“豎式計算”的思想進行計算。這種方法比較容易理解,但是計算效率比較低。
2) 將大數看成二進制流進行處理。使用各種位運算和邏輯操作來實現打算的運算。該方法設計複雜,可讀性較差,而且難以調試。
3) 將大數表示成一個n進制數組。n的取值越大,數組的大小越小,這樣可以縮短運算的時間及空間複雜度,提高算法的效率。在32位系統中,n可以取2^32,這時每一位的取值範圍是0~0xffffffff。

下面就針對第1)種方法進行描述與實現:
1、構造函數
1>定義全局變量:

typedef long long INT64;                 //對long long進行重命名
const INT64 INVALID = 0xcccccccccccccccc; //隨機值
const INT64 MAX =  9223372036854775807;   //最大值(0x7FFFFFFFFFFFFFFF)
const INT64 MIN = -9223372036854775808;   //最小值(0x8000000000000000)

2>定義類的成員變量

class BigData
{
private:
    string _pData;
    INT64 _value;
};

3>判斷數據溢出函數

bool IsOverFlow()//判斷數據是否溢出
    {
        //先求當前字符串的長度
        int len = _pData.size();

        //與INT64的最大值與最小值的長度作比較,如果大於MAX和MIN的長度,說明溢出
        if (len > 21)//"+9223372036854775807\0"  "-9223372036854775808\0"(21位)
        {
            return true;
        }
        else if (len < 21)//如果大於MAX和MIN的長度,說明溢出
        {
            return false;
        }
        else//如果等於MAX和MIN的長度,則需要繼續判斷
        {
            if (_pData[0] == '+' && strcmp(_pData.c_str(),"+9223372036854775807")>0)
                return true;
            if (_pData[0] == '-' && strcmp(_pData.c_str(),"-9223372036854775808")>0)
                return true;
            return false;
        }
    }

4>無參的構造函數

BigData()//無參構造函數
        :_pData("")
        ,_value(INVALID)
    {}

5>給一個不溢出的整數作爲參數的構造函數

BigData(INT64 value)//給一個整數串的構造函數(注意要保證MIN<value<MAX,否則會出錯)
    {
        if(value==0)
        {
            _pData.resize(3);
            _pData[0] = '+';//默認0是正的
            _pData[1] = '0';
            _pData[2] = '\0';
            return;
        }

        _value = value;

        char count = 0;//統計所給整數的位數
        INT64 tmp = value;//給出臨時變量tmp做計算
        //統計所給整數有多少位
        while(tmp)
        {
            ++count;
            tmp /= 10;
        }
        _pData.resize(count+2);//給符號和'\0'多開闢倆個字節
        //確認符號
        if (value > 0)
            _pData[0] = '+';
        else
            _pData[0] = '-';

        //從後向前給字符數組賦值
        tmp = value;
        if (tmp < 0)
            tmp = 0 - tmp;//如果tmp是負數,將其改爲正數
        for (int i = count; i > 0; --i)
        {
            char c = tmp%10 + '0';//取最低位
            _pData[i] = c;
            tmp /= 10;
        }
    }

6>字符串做參數的構造參數(需考慮異常情況)

BigData(const char* s)//用字符串構造大數的構造函數
        :_value(0)
    {
        int len = strlen(s);//求所給字符串的長度
        _pData.resize(len+2,0);//爲符號位和'\0'多開闢兩個空間
        char sign = '+';//默認符號爲正
        char* str = (char*)s;//用一個字符串指向s
        size_t size = 0;//記錄實際有效的字符串個數

        //跳過前面的'0'和' '(比如"00003526727"  "   6767867")
        while(*str == '0' || *str == ' ')
            ++str;

        //預防"000000" 和 "     "
        if (*str == '\0')
        {
            _value = 0;
            _pData[0] = sign;//默認0爲正
            _pData[1] = '0';
            _pData.resize(3);//'+' '0' '\0'
            return;
        }

        //確認符號
        if (str[0] == '-' || str[0] == '+')
        {
            sign = *str++;
        }

        //預防"+000006458"  "-    648"
        while(*str == '0' || *str == ' ')
            ++str;

        //預防"+000000" 和 "-     "
        if (*str == '\0')
        {
            _value = 0;
            _pData[0] = sign;
            _pData[1] = '0';
            _pData.resize(3);
            return;
        }

        //從第1位開始賦值,第0位放符號位
        for (int i = 1; i <= len; ++i)
        {
            //只有遇到數字字符才向字符數組和_value中賦值
            if(*str >= '0' && *str <= '9')
            {
                _value = _value*10 + (*str - '0');
                _pData[i] = *str;
                ++size;
                str++;
            }
            else
            {
                if(i == 1)//處理"abc2654738"
                    _pData[i] = '0';
                break;
            }
        }

        _pData[0] = sign;//將0號位置賦值爲符號位
        _pData.resize(size+2);//重置大小    

        //確定_value的符號
        if (sign == '-')
            _value = 0 - _value;
    }

7>構造函數的測試代碼及結果
測試代碼:

void Test1()    //構造函數的測試
{
    cout<<BigData()<<endl;
    cout<<BigData(25643787278947)<<endl;
    cout<<BigData("123456789\0")<<endl;
    cout<<BigData("    +000123456789")<<endl;
    cout<<BigData("000+0000")<<endl;
    cout<<BigData("000-   123456789")<<endl;
    cout<<BigData("000+000abc123456789")<<endl;
    cout<<BigData("000-000123456789abc123456789")<<endl;
}

運行結果:
構造函數的測試結果

2、加法函數
1>加法函數的整體邏輯
加法函數的邏輯

2>加法重載:operator+

BigData operator+(BigData& bd)
    {
        BigData* l = this;//左操作數
        BigData* r = &bd;//右操作數

        int lSize = l->_pData.size();
        int rSize = r->_pData.size();
        //將較長的數放於左操作數
        if (lSize < rSize)
        {
            swap(l,r);
            swap(lSize,rSize);
        }
        //如果兩個數據長度一樣,就將(除符號)大的數放於左操作數
        if (lSize == rSize)
        {
            if (strcmp(l->_pData.c_str()+1,r->_pData.c_str()+1) < 0)
            {
                swap(l,r);
                swap(lSize,rSize);
            }
        }

        //兩個數據同號(結果與數據符號相同)
        if (l->_pData[0] == r->_pData[0])
        {
            //兩個數據至少有一個溢出了
            if (l->IsOverFlow() || r->IsOverFlow())
                return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數

            //兩個數據都沒溢出,但結果有可能溢出
            else
            {
                //同號正溢出:結果溢出了  5 - 2 < 4
                if (l->_pData[0] == '+' && MAX - l->_value < r->_value)
                {
                    return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
                }
                //同號負溢出:結果溢出了  -5 - (-3) > -3
                else if (l->_pData[0] == '-' && MIN - l->_value > r->_value)
                {
                    return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
                }
                //兩個數據都沒有溢出,和也沒有溢出
                else
                {
                    //直接相加兩個數據,然後構造臨時對象返回
                    return BigData(l->_value+r->_value);
                }
            }
        } 
        //兩個數據異號(結果的符號爲數據較大的數據的符號,即左操作數)
        else
        {
            //兩個數據都沒溢出,結果肯定沒溢出
            if (!l->IsOverFlow() && !r->IsOverFlow())
            {
                //直接相加兩個數據,然後構造臨時對象返回
                return BigData(l->_value+r->_value);
            }
            //兩個數據至少有一個溢出了
            else
            {
                return BigData(l->SUB(r->_pData).c_str());//如果有溢出,調用字符串相減函數
            }
        }
    }

3>自擬字符串加法:ADD()


        char step = 0;//進位
        char cRet = 0;
        for (int i = 2; i < lSize; ++i)
        {
            //右操作數的位數還沒加完,左+右+進位
            if (rSize-i > 0)
            {
                cRet = _pData[lSize-i] - '0' + s[rSize-i] -'0'+ step;
            }
            //右操作數加完後,左+進位
            else
            {
                cRet = _pData[lSize-i] - '0' + step;
            }
            step = cRet/10;
            cRet = cRet%10;
            ret[lSize+1-i] = cRet + '0';
        }
        ret[0] = _pData[0];   //確定符號位
        ret[1] = step+'0';    //保存最後一個進位

        return ret;
    }

4>加法函數的測試用例

(異號測試)
    //BigData bd1("-9999");
    //BigData bd2("+1234567");
    //cout<<bd1 + bd2<<endl;//異號都沒溢出----結果沒溢出
    //BigData bd3("-99999999999999999999999999999999999999");
    //BigData bd4("+11111111111111111111111111111111111111");
    //cout<<bd3 + bd4<<endl;//異號都溢出了----結果溢出
    //BigData bd5("-9999999999999999999999999999999");
    //BigData bd6("1000");
    //cout<<bd5 + bd6<<endl;//異號負數溢出----結果負溢出
    //BigData bd7("-1000");
    //BigData bd8("+9999999999999999999999999999999");
    //cout<<bd7 + bd8<<endl;//異號正數溢出----結果正溢出
    //BigData bd9(" -1111111111111111111111111111111");
    //BigData bd10("+9999999999999999999999999999999");
    //cout<<bd9 + bd10<<endl;//異號正數溢出----結果正溢出
}

5>運行結果
同號:
加法函數同號測試結果

異號:
加法函數異號測試結果

3、減法函數
1>減法函數的整體邏輯
減法的整體邏輯

2>減法重載:operator-

BigData operator-(BigData& bd)
    {
        BigData* l = this;//左操作數
        BigData* r = &bd;//右操作數

        int lSize = l->_pData.size();
        int rSize = r->_pData.size();
        //將較長的數放於左操作數
        if (lSize < rSize)
        {
            swap(l,r);
            swap(lSize,rSize);
        }
        //如果兩個數據長度一樣,就將(除符號)大的數放於左操作數
        if (lSize == rSize)
        {
            if (strcmp(l->_pData.c_str()+1,r->_pData.c_str()+1) < 0)
            {
                swap(l,r);
                swap(lSize,rSize);
            }
        }

        //兩個數據同號
        if (l->_pData[0] == r->_pData[0])
        {
            //兩個數據都沒溢出,結果肯定也沒溢出
            if (!l->IsOverFlow() && !r->IsOverFlow())
            {
                //直接相減兩個數據,然後構造臨時對象返回
                return BigData(l->_value - r->_value);
            }
            //兩個數據至少有一個溢出了,調用字符串相減函數
            else
            {
                return BigData(l->SUB(r->_pData).c_str());
            }
        }
        //兩個數據異號
        else
        {
            //兩個數據至少有一個溢出了,直接調用字符串相加函數
            if (l->IsOverFlow() || r->IsOverFlow())
            {
                return BigData(l->ADD(r->_pData).c_str());
            }
            //兩個數據都沒有溢出,結果有可能溢出也有可能不溢出
            else
            {
                //異號正溢出:結果溢出了  5 - 2 < 4
                if (l->_pData[0] == '+' && MAX - l->_value < r->_value)
                {
                    return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
                }
                //異號負溢出:結果溢出了  -5 - (-3) > -3
                else if (l->_pData[0] == '-' && MIN - l->_value > r->_value)
                {
                    return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
                }
                //兩個數據都沒有溢出,和也沒有溢出
                else
                {
                    //直接相減兩個數據,然後構造臨時對象返回
                    return BigData(l->_value-r->_value);
                }
            }
        }
    }

3>自擬字符串減法:SUB()

string SUB(string& s)//字符串減法
    {
        int lSize = _pData.size();
        int rSize = s.size();

        string ret;//定義返回值
        ret.resize(lSize+1);//99999-(-99)=100098(位數最多爲左操作數+1個)

        char step = 0;//借位
        char cRet = 0;
        for (int i = 2; i < lSize; ++i)
        {
            //右操作數的位數還沒減完,左-右-借位
            if (rSize-i > 0)
            {
                cRet = (_pData[lSize-i]-'0') - (s[rSize-i]-'0') - step; 
                step = 0;
            }
            //右操作數減完後,左-借位
            else
            {
                cRet = _pData[lSize-i] - '0' - step;
                step = 0;
            }

            if(cRet < 0)//不夠減就進行借位
            {
                cRet += 10;//當前0位+10
                step = 1;//向前面借一位
            }

            ret[lSize+1-i] = cRet + '0';
        }
        ret[0] = _pData[0];   //確定符號位
        ret[1] = step+'0';    //保存最後一個借位

        return ret;
    }

4>減法函數的測試用例

void Test3()//減法測試
{
    ////(同號測試)
    //BigData bd1("+999999999");
    //BigData bd2("+1234567");
    //cout<<bd1 - bd2<<endl;//同號都沒溢出----結果沒溢出
    //BigData bd3("99999999999999999999999999999999999999");
    //BigData bd4("11111111111111111111111111111111111111");
    //cout<<bd3 - bd4<<endl;//同號都溢出了----結果溢出
    //BigData bd5("777777777777777777777777777");
    //BigData bd6("1000");
    //cout<<bd5 - bd6<<endl;//同號正數溢出----結果沒溢出
    //BigData bd7("-1000");
    //BigData bd8("-88888888888888888888888888888888");
    //cout<<bd7 + bd8<<endl;//同號負數溢出----結果溢出

    //(異號測試)
    BigData bd1("-9999");
    BigData bd2("+1234567");
    cout<<bd1 - bd2<<endl;//異號都沒溢出----結果沒溢出
    BigData bd3("-99999999999999999999999999999999999999");
    BigData bd4("+11111111111111111111111111111111111111");
    cout<<bd3 - bd4<<endl;//異號都溢出了----結果溢出
    BigData bd5("-9999999999999999999999999999999");
    BigData bd6("1000");
    cout<<bd5 - bd6<<endl;//異號負數溢出----結果負溢出
    BigData bd7("-1000");
    BigData bd8("+9999999999999999999999999999999");
    cout<<bd7 - bd8<<endl;//異號正數溢出----結果正溢出
    BigData bd9(" -1111111111111111111111111111111");
    BigData bd10("+9999999999999999999999999999999");
    cout<<bd9 - bd10<<endl;//異號都溢出了----結果溢出
}

5>運行結果
同號:
減法函數的同號測試

異號:
減法函數的異號測試

4、乘法函數
1>乘法函數的整體邏輯
乘法的整體邏輯

2>重載乘法:operator*

BigData operator*(BigData& bd)
    {
        BigData* l = this;//左操作數
        BigData* r = &bd;//右操作數

        int lSize = l->_pData.size();
        int rSize = r->_pData.size();

        //將較長的數放於左操作數
        if (lSize < rSize)
        {
            swap(l,r);
            swap(lSize,rSize);
        }

        //兩個數據同號,運算結果符號爲正
        if (l->_pData[0] == r->_pData[0])
        {
            //至少有一個數據溢出,調用字符串乘法函數
            if (l->IsOverFlow() || r->IsOverFlow())
            {
                return BigData(l->MUL(r->_pData).c_str());
            }
            //兩個數據都沒溢出,結果可能溢出也可能不溢出
            else
            {
                //正溢出:結果溢出了  5 / 2 < 4
                if (MAX / l->_value < r->_value)
                {
                    return BigData(l->MUL(r->_pData).c_str());//如果有溢出,調用字符串相乘函數
                }
                //兩個數據都沒有溢出,積也沒有溢出
                else
                {
                    //直接相乘兩個數據,然後構造臨時對象返回
                    return BigData(l->_value*r->_value);
                }
            }
        }

         //兩個數據異號,運算結果爲負
        else                       
        {
            //至少有一個數據溢出,調用字符串乘法函數
            if (l->IsOverFlow() || r->IsOverFlow())
            {
                return BigData(l->MUL(r->_pData).c_str());
            }
            //兩個數據都沒溢出,結果可能溢出也可能不溢出
            else
            {
                //負溢出:結果溢出了  -5 / (-3) > 3
                if (MIN / l->_value > r->_value)
                {
                    return BigData(l->MUL(r->_pData).c_str());//如果有溢出,調用字符串相乘函數
                }
                //兩個數據都沒有溢出,和也沒有溢出
                else
                {
                    //直接相乘兩個數據,然後構造臨時對象返回
                    return BigData(l->_value*r->_value);
                }
            } 
        }
    }

3>自擬字符串乘法:MUL()

string MUL(string& s)
    {
        int lSize = _pData.size();
        int rSize = s.size();

        string ret;//定義返回值
        //結果最多爲lSize+rSize-2位 "+9999\0" * "+99\0" = "+989901\0"
        ret.resize(lSize+rSize-2);

        char step = 0;//進位
        char count = 0;//錯位
        char cRet = 0;
        for (int i = 2; i < rSize; ++i)//右操作數比較短,應放於外層循環
        {
            step = 0;
            for (int j = 2; j < lSize; ++j)//左操作數比較長,應放在內層循環
            {
                cRet = (s[rSize-i]-'0') * (_pData[lSize-j]-'0') + step;
                if(count > 0)
                    cRet += ret[lSize+rSize-2-j-count] - '0';
                step = cRet/10;
                cRet %= 10;
                ret[lSize+rSize-2-j-count] = cRet + '0';
            }
            count++;//每次向前錯一位
            ret[rSize-1-count] += step + '0';//保存最後一個進位
        }

        //確定結果的符號:同號爲正,異號爲負
        if (_pData[0] == s[0])
            ret[0] = '+';
        else
            ret[0] = '-';

        return ret;
    }

4>乘法的測試用例

void Test4()//乘法測試
{
    //(同號測試)
    BigData bd1("+999999999");
    BigData bd2("+111111");
    cout<<bd1 * bd2<<endl;//同號都沒溢出----結果沒溢出
    BigData bd3("-99999999999999999999999999999999999999");
    BigData bd4("-11111111111111111111111111111111111111");
    cout<<bd3 * bd4<<endl;//同號都溢出了----結果溢出
    BigData bd5("9999999999999");
    BigData bd6("9999999999999");
    cout<<bd5 * bd6<<endl;//同號都沒溢出----結果正溢出
    //異號測試
    BigData bd7("-1000");
    BigData bd8("7654321");
    cout<<bd7 * bd8<<endl;//異號都沒溢出----結果沒溢出
    BigData bd9("-9999999999999999999999999999");
    BigData bd10("+1000000000");
    cout<<bd9 * bd10<<endl;//異號溢出了----結果負溢出
    BigData bd11("9999999999999");
    BigData bd12("-9999999999999");
    cout<<bd11 * bd12<<endl;//同號都沒溢出----結果負溢出
}

5>運行結果
乘法函數的運行結果

5、除法函數
1>除法函數的整體邏輯
除法的整體邏輯

2>重載除法:operator/

BigData operator/(BigData& bd)
    {
        if(strcmp(bd._pData.c_str()+1,"0")==0)//防止除數爲0
            assert(false);
        int lSize = _pData.size();
        int rSize = bd._pData.size();

        //左操作數小於右操作數或者被除數爲0,結果爲0
        if (lSize < rSize  || strcmp(_pData.c_str()+1,"0")==0)
            return BigData((INT64)0);
        //兩個數據絕對值相等,結果爲1或-1
        else if (lSize == rSize && strcmp(_pData.c_str()+1,bd._pData.c_str()+1)==0)
        {
            if(_pData[0] != bd._pData[0])
                return BigData((INT64)-1);
            else
                return BigData((INT64)1);
        }
        //右操作數爲+1或-1,結果爲 +左操作數 或 -左操作數
        else if (rSize == 3 && bd._pData[1] == '1')
        {
            if(bd._pData[0] == '+')
            {
                return BigData(_pData.c_str());
            }
            else
            {
                string tmp = _pData;
                tmp[0] = '-';
                return BigData(tmp.c_str());
            }
        }
        else
        {
            //至少有一個數據溢出
            if (IsOverFlow() || bd.IsOverFlow())
            {
                return BigData(DIV(bd._pData).c_str());
            }
            //兩個數據都沒溢出,結果也沒溢出
            else
            {
                return BigData(_value/bd._value);
            }
        }
    }

3>自擬字符串除法:DIV()

string DIV(string& s)
    {
        int lSize = _pData.size();
        int rSize = s.size();

        string ret;//定義返回值
        //結果最多爲lSize位 "+9999\0" * "+1\0" = "+9999\0"
        ret.reserve(lSize); 

        string sleft(_pData.c_str(),rSize-1);//被除數
        string sright(s.c_str(),rSize-1);//除數
        int index = rSize-1;
        while(index < lSize)
        {
            //不夠除
            while (sleft.size()==sright.size() && strcmp(sleft.c_str(),sright.c_str())<0)
            {
                sleft += _pData[index++];//借位
                ret.push_back('0');
                if (index > lSize)
                    break;
            }
            //夠除
            int count = 0;
            while(sleft.size()>sright.size() ||\
                 (sleft.size()==sright.size()&&strcmp(sleft.c_str(),sright.c_str())>0))
            {
                BigData tmp(sleft.c_str());
                sleft = tmp.SUB(BigData(sright.c_str())._pData);
                ++count;
                sleft = BigData(sleft.c_str())._pData;//去掉多餘的0
                sleft = string(sleft.c_str(),sleft.size()-1);//去掉後面的'\0'
            }
            ret.push_back(count+'0');
            sleft += _pData[index++];//借位
        }
        //確定結果的符號:同號爲正,異號爲負
        if (_pData[0] == s[0])
            ret[0] = '+';
        else
            ret[0] = '-';
        return ret;
    }

4>除法函數的測試用例

void Test5()//測試除法
{
    BigData bd1("+999999999");
    BigData bd2("+11111111111111");
    cout<<bd1 / bd2<<endl;//左操作數小於有操作數----結果爲0
    BigData bd3("0");
    BigData bd4("-11111111111111111");
    cout<<bd3 / bd4<<endl;//左操作數--是0--結果爲0
    BigData bd5("9999999999999");
    BigData bd6("9999999999999");
    cout<<bd5 / bd6<<endl;//同號且絕對值相等----結果爲1
    BigData bd7("-9999999999999");
    BigData bd8("9999999999999");
    cout<<bd7 / bd8<<endl;//異號且絕對值相等----結果爲-1
    BigData bd9("-9999999999999999999999999999");
    BigData bd10("+1");
    cout<<bd9 / bd10<<endl;//右操作數爲1---結果爲左操作數
    BigData bd11("9999999999999");
    BigData bd12("-1");
    cout<<bd11 / bd12<<endl;//右操作數爲-1---結果爲 -左操作數
    BigData bd13("-9999999999999999999999999999");
    BigData bd14("+100000000");
    cout<<bd13 / bd14<<endl;//異號且至少有一個溢出
    BigData bd15("9999999999999");
    BigData bd16("100000");
    cout<<bd15 / bd16<<endl;//同號且都沒有溢出
}

5>運行結果
除法的運行結果

6、完整代碼
算法實現:

#pragma once
#include <iostream>
#include <string>
#include <cassert>
using namespace std;

typedef long long INT64;                 //對long long進行重命名
const INT64 INVALID = 0xcccccccccccccccc; //隨機值
const INT64 MAX =  9223372036854775807;   //最大值(0x7FFFFFFFFFFFFFFF)
const INT64 MIN = -9223372036854775808;   //最小值(0x8000000000000000)

class BigData
{
public:
    friend ostream& operator<<(ostream& _cout,const BigData& bd);

    BigData()//無參構造函數
        :_pData("")
        ,_value(INVALID)
    {}
    BigData(INT64 value)//給一個整數串的構造函數(注意要保證MIN<value<MAX,否則會出錯)
    {
        if(value==0)
        {
            _pData.resize(3);
            _pData[0] = '+';//默認0是正的
            _pData[1] = '0';
            _pData[2] = '\0';
            return;
        }

        _value = value;

        char count = 0;//統計所給整數的位數
        INT64 tmp = value;//給出臨時變量tmp做計算
        //統計所給整數有多少位
        while(tmp)
        {
            ++count;
            tmp /= 10;
        }
        _pData.resize(count+2);//給符號和'\0'多開闢倆個字節
        //確認符號
        if (value > 0)
            _pData[0] = '+';
        else
            _pData[0] = '-';

        //從後向前給字符數組賦值
        tmp = value;
        if (tmp < 0)
            tmp = 0 - tmp;//如果tmp是負數,將其改爲正數
        for (int i = count; i > 0; --i)
        {
            char c = tmp%10 + '0';//取最低位
            _pData[i] = c;
            tmp /= 10;
        }
    }
    BigData(const char* s)//用字符串構造大數的構造函數
        :_value(0)
    {
        int len = strlen(s);//求所給字符串的長度
        _pData.resize(len+2,0);//爲符號位和'\0'多開闢兩個空間
        char sign = '+';//默認符號爲正
        char* str = (char*)s;//用一個字符串指向s
        size_t size = 0;//記錄實際有效的字符串個數

        //跳過前面的'0'和' '(比如"00003526727"  "   6767867")
        while(*str == '0' || *str == ' ')
            ++str;

        //預防"000000" 和 "     "
        if (*str == '\0')
        {
            _value = 0;
            _pData[0] = sign;//默認0爲正
            _pData[1] = '0';
            _pData.resize(3);//'+' '0' '\0'
            return;
        }

        //確認符號
        if (str[0] == '-' || str[0] == '+')
        {
            sign = *str++;
        }

        //預防"+000006458"  "-    648"
        while(*str == '0' || *str == ' ')
            ++str;

        //預防"+000000" 和 "-     "
        if (*str == '\0')
        {
            _value = 0;
            _pData[0] = sign;
            _pData[1] = '0';
            _pData.resize(3);
            return;
        }

        //從第1位開始賦值,第0位放符號位
        for (int i = 1; i <= len; ++i)
        {
            //只有遇到數字字符才向字符數組和_value中賦值
            if(*str >= '0' && *str <= '9')
            {
                _value = _value*10 + (*str - '0');
                _pData[i] = *str;
                ++size;
                str++;
            }
            else
            {
                if(i == 1)//處理"abc2654738"
                    _pData[i] = '0';
                break;
            }
        }

        _pData[0] = sign;//將0號位置賦值爲符號位
        _pData.resize(size+2);//重置大小    

        //確定_value的符號
        if (sign == '-')
            _value = 0 - _value;
    }

    BigData operator+(BigData& bd)
    {
        BigData* l = this;//左操作數
        BigData* r = &bd;//右操作數

        int lSize = l->_pData.size();
        int rSize = r->_pData.size();
        //將較長的數放於左操作數
        if (lSize < rSize)
        {
            swap(l,r);
            swap(lSize,rSize);
        }
        //如果兩個數據長度一樣,就將(除符號)大的數放於左操作數
        if (lSize == rSize)
        {
            if (strcmp(l->_pData.c_str()+1,r->_pData.c_str()+1) < 0)
            {
                swap(l,r);
                swap(lSize,rSize);
            }
        }

        //兩個數據同號(結果與數據符號相同)
        if (l->_pData[0] == r->_pData[0])
        {
            //兩個數據至少有一個溢出了
            if (l->IsOverFlow() || r->IsOverFlow())
                return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數

            //兩個數據都沒溢出,但結果有可能溢出
            else
            {
                //同號正溢出:結果溢出了  5 - 2 < 4
                if (l->_pData[0] == '+' && MAX - l->_value < r->_value)
                {
                    return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
                }
                //同號負溢出:結果溢出了  -5 - (-3) > -3
                else if (l->_pData[0] == '-' && MIN - l->_value > r->_value)
                {
                    return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
                }
                //兩個數據都沒有溢出,和也沒有溢出
                else
                {
                    //直接相加兩個數據,然後構造臨時對象返回
                    return BigData(l->_value+r->_value);
                }
            }
        } 
        //兩個數據異號(結果的符號爲數據較大的數據的符號,即左操作數)
        else
        {
            //兩個數據都沒溢出,結果肯定沒溢出
            if (!l->IsOverFlow() && !r->IsOverFlow())
            {
                //直接相加兩個數據,然後構造臨時對象返回
                return BigData(l->_value+r->_value);
            }
            //兩個數據至少有一個溢出了
            else
            {
                return BigData(l->SUB(r->_pData).c_str());//如果有溢出,調用字符串相減函數
            }
        }
    }
    BigData operator-(BigData& bd)
    {
        BigData* l = this;//左操作數
        BigData* r = &bd;//右操作數

        int lSize = l->_pData.size();
        int rSize = r->_pData.size();
        //將較長的數放於左操作數
        if (lSize < rSize)
        {
            swap(l,r);
            swap(lSize,rSize);
        }
        //如果兩個數據長度一樣,就將(除符號)大的數放於左操作數
        if (lSize == rSize)
        {
            if (strcmp(l->_pData.c_str()+1,r->_pData.c_str()+1) < 0)
            {
                swap(l,r);
                swap(lSize,rSize);
            }
        }

        //兩個數據同號
        if (l->_pData[0] == r->_pData[0])
        {
            //兩個數據都沒溢出,結果肯定也沒溢出
            if (!l->IsOverFlow() && !r->IsOverFlow())
            {
                //直接相減兩個數據,然後構造臨時對象返回
                return BigData(l->_value - r->_value);
            }
            //兩個數據至少有一個溢出了,調用字符串相減函數
            else
            {
                return BigData(l->SUB(r->_pData).c_str());
            }
        }
        //兩個數據異號
        else
        {
            //兩個數據至少有一個溢出了,直接調用字符串相加函數
            if (l->IsOverFlow() || r->IsOverFlow())
            {
                return BigData(l->ADD(r->_pData).c_str());
            }
            //兩個數據都沒有溢出,結果有可能溢出也有可能不溢出
            else
            {
                //異號正溢出:結果溢出了  5 - 2 < 4
                if (l->_pData[0] == '+' && MAX - l->_value < r->_value)
                {
                    return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
                }
                //異號負溢出:結果溢出了  -5 - (-3) > -3
                else if (l->_pData[0] == '-' && MIN - l->_value > r->_value)
                {
                    return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
                }
                //兩個數據都沒有溢出,和也沒有溢出
                else
                {
                    //直接相減兩個數據,然後構造臨時對象返回
                    return BigData(l->_value-r->_value);
                }
            }
        }
    }
    BigData operator*(BigData& bd)
    {
        BigData* l = this;//左操作數
        BigData* r = &bd;//右操作數

        int lSize = l->_pData.size();
        int rSize = r->_pData.size();

        //將較長的數放於左操作數
        if (lSize < rSize)
        {
            swap(l,r);
            swap(lSize,rSize);
        }

        //兩個數據同號,運算結果符號爲正
        if (l->_pData[0] == r->_pData[0])
        {
            //至少有一個數據溢出,調用字符串乘法函數
            if (l->IsOverFlow() || r->IsOverFlow())
            {
                return BigData(l->MUL(r->_pData).c_str());
            }
            //兩個數據都沒溢出,結果可能溢出也可能不溢出
            else
            {
                //正溢出:結果溢出了  5 / 2 < 4
                if (MAX / l->_value < r->_value)
                {
                    return BigData(l->MUL(r->_pData).c_str());//如果有溢出,調用字符串相乘函數
                }
                //兩個數據都沒有溢出,積也沒有溢出
                else
                {
                    //直接相乘兩個數據,然後構造臨時對象返回
                    return BigData(l->_value*r->_value);
                }
            }
        }

         //兩個數據異號,運算結果爲負
        else                       
        {
            //至少有一個數據溢出,調用字符串乘法函數
            if (l->IsOverFlow() || r->IsOverFlow())
            {
                return BigData(l->MUL(r->_pData).c_str());
            }
            //兩個數據都沒溢出,結果可能溢出也可能不溢出
            else
            {
                //負溢出:結果溢出了  -5 / (-3) > 3
                if (MIN / l->_value > r->_value)
                {
                    return BigData(l->MUL(r->_pData).c_str());//如果有溢出,調用字符串相乘函數
                }
                //兩個數據都沒有溢出,和也沒有溢出
                else
                {
                    //直接相乘兩個數據,然後構造臨時對象返回
                    return BigData(l->_value*r->_value);
                }
            } 
        }
    }
    BigData operator/(BigData& bd)
    {
        if(strcmp(bd._pData.c_str()+1,"0")==0)//防止除數爲0
            assert(false);
        int lSize = _pData.size();
        int rSize = bd._pData.size();

        //左操作數小於右操作數或者被除數爲0,結果爲0
        if (lSize < rSize  || strcmp(_pData.c_str()+1,"0")==0)
            return BigData((INT64)0);
        //兩個數據絕對值相等,結果爲1或-1
        else if (lSize == rSize && strcmp(_pData.c_str()+1,bd._pData.c_str()+1)==0)
        {
            if(_pData[0] != bd._pData[0])
                return BigData((INT64)-1);
            else
                return BigData((INT64)1);
        }
        //右操作數爲+1或-1,結果爲 +左操作數 或 -左操作數
        else if (rSize == 3 && bd._pData[1] == '1')
        {
            if(bd._pData[0] == '+')
            {
                return BigData(_pData.c_str());
            }
            else
            {
                string tmp = _pData;
                tmp[0] = '-';
                return BigData(tmp.c_str());
            }
        }
        else
        {
            //至少有一個數據溢出
            if (IsOverFlow() || bd.IsOverFlow())
            {
                return BigData(DIV(bd._pData).c_str());
            }
            //兩個數據都沒溢出,結果也沒溢出
            else
            {
                return BigData(_value/bd._value);
            }
        }
    }

protected:
    bool IsOverFlow()//判斷數據是否溢出
    {
        //先求當前字符串的長度
        int len = _pData.size();

        //與INT64的最大值與最小值的長度作比較,如果大於MAX和MIN的長度,說明溢出
        if (len > 21)//"+9223372036854775807\0"  "-9223372036854775808\0"(21位)
        {
            return true;
        }
        else if (len < 21)//如果大於MAX和MIN的長度,說明溢出
        {
            return false;
        }
        else//如果等於MAX和MIN的長度,則需要繼續判斷
        {
            if (_pData[0] == '+' && strcmp(_pData.c_str(),"+9223372036854775807")>0)
                return true;
            if (_pData[0] == '-' && strcmp(_pData.c_str(),"-9223372036854775808")>0)
                return true;
            return false;
        }
    }
    string ADD(string& s)//字符串加法
    {
        int lSize = _pData.size();
        int rSize = s.size();

        string ret;//定義返回值
        ret.resize(lSize+1);//99999+99=100098(位數最多爲左操作數+1)

        char step = 0;//進位
        char cRet = 0;
        for (int i = 2; i < lSize; ++i)
        {
            //右操作數的位數還沒加完,左+右+進位
            if (rSize-i > 0)
            {
                cRet = _pData[lSize-i] - '0' + s[rSize-i] -'0'+ step;
            }
            //右操作數加完後,左+進位
            else
            {
                cRet = _pData[lSize-i] - '0' + step;
            }
            step = cRet/10;
            cRet = cRet%10;
            ret[lSize+1-i] = cRet + '0';
        }
        ret[0] = _pData[0];   //確定符號位
        ret[1] = step+'0';    //保存最後一個進位

        return ret;
    }
    string SUB(string& s)//字符串減法
    {
        int lSize = _pData.size();
        int rSize = s.size();

        string ret;//定義返回值
        ret.resize(lSize+1);//99999-(-99)=100098(位數最多爲左操作數+1個)

        char step = 0;//借位
        char cRet = 0;
        for (int i = 2; i < lSize; ++i)
        {
            //右操作數的位數還沒減完,左-右-借位
            if (rSize-i > 0)
            {
                cRet = (_pData[lSize-i]-'0') - (s[rSize-i]-'0') - step; 
                step = 0;
            }
            //右操作數減完後,左-借位
            else
            {
                cRet = _pData[lSize-i] - '0' - step;
                step = 0;
            }

            if(cRet < 0)//不夠減就進行借位
            {
                cRet += 10;//當前0位+10
                step = 1;//向前面借一位
            }

            ret[lSize+1-i] = cRet + '0';
        }
        ret[0] = _pData[0];   //確定符號位
        ret[1] = step+'0';    //保存最後一個借位

        return ret;
    }
    string MUL(string& s)
    {
        int lSize = _pData.size();
        int rSize = s.size();

        string ret;//定義返回值
        //結果最多爲lSize+rSize-2位 "+9999\0" * "+99\0" = "+989901\0"
        ret.resize(lSize+rSize-2);

        char step = 0;//進位
        char count = 0;//錯位
        char cRet = 0;
        for (int i = 2; i < rSize; ++i)//右操作數比較短,應放於外層循環
        {
            step = 0;
            for (int j = 2; j < lSize; ++j)//左操作數比較長,應放在內層循環
            {
                cRet = (s[rSize-i]-'0') * (_pData[lSize-j]-'0') + step;
                if(count > 0)
                    cRet += ret[lSize+rSize-2-j-count] - '0';
                step = cRet/10;
                cRet %= 10;
                ret[lSize+rSize-2-j-count] = cRet + '0';
            }
            count++;//每次向前錯一位
            ret[rSize-1-count] += step + '0';//保存最後一個進位
        }

        //確定結果的符號:同號爲正,異號爲負
        if (_pData[0] == s[0])
            ret[0] = '+';
        else
            ret[0] = '-';

        return ret;
    }
    string DIV(string& s)
    {
        int lSize = _pData.size();
        int rSize = s.size();

        string ret;//定義返回值
        //結果最多爲lSize位 "+9999\0" * "+1\0" = "+9999\0"
        ret.reserve(lSize); 

        string sleft(_pData.c_str(),rSize-1);//被除數
        string sright(s.c_str(),rSize-1);//除數
        int index = rSize-1;
        while(index < lSize)
        {
            //不夠除
            while (sleft.size()==sright.size() && strcmp(sleft.c_str(),sright.c_str())<0)
            {
                sleft += _pData[index++];//借位
                ret.push_back('0');
                if (index > lSize)
                    break;
            }
            //夠除
            int count = 0;
            while(sleft.size()>sright.size() ||\
                 (sleft.size()==sright.size()&&strcmp(sleft.c_str(),sright.c_str())>0))
            {
                BigData tmp(sleft.c_str());
                sleft = tmp.SUB(BigData(sright.c_str())._pData);
                ++count;
                sleft = BigData(sleft.c_str())._pData;//去掉多餘的0
                sleft = string(sleft.c_str(),sleft.size()-1);//去掉後面的'\0'
            }
            ret.push_back(count+'0');
            sleft += _pData[index++];//借位
        }
        //確定結果的符號:同號爲正,異號爲負
        if (_pData[0] == s[0])
            ret[0] = '+';
        else
            ret[0] = '-';
        return ret;
    }

private:
    string _pData;
    INT64 _value;
};

ostream& operator<<(ostream& _cout,const BigData& bd)
{
    _cout<<bd._pData.c_str();
    return _cout;
}

測試用例:

#include <iostream>
#include "BigData.h"
using namespace std;

void Test1()    //構造函數的測試
{
    cout<<BigData()<<endl;
    cout<<BigData(25643787278947)<<endl;
    cout<<BigData("123456789\0")<<endl;
    cout<<BigData("    +000123456789")<<endl;
    cout<<BigData("000+0000")<<endl;
    cout<<BigData("000-   123456789")<<endl;
    cout<<BigData("000+000abc123456789")<<endl;
    cout<<BigData("000-000123456789abc123456789")<<endl;
}

void Test2()//加法測試
{
    ////(同號測試)
    //BigData bd1("9999");
    //BigData bd2("+1234567");
    //cout<<bd1 + bd2<<endl;//同號都沒溢出----結果沒溢出
    //BigData bd3("99999999999999999999999999999999999999");
    //BigData bd4("99999999999999999999999999999999999999");
    //cout<<bd3 + bd4<<endl;//同號都溢出了----結果溢出
    //BigData bd5("9223372036854775807");
    //BigData bd6("100");
    //cout<<bd5 + bd6<<endl;//同號都沒溢出----結果正溢出
    //BigData bd7("-9223372036854775808");
    //BigData bd8("-100");
    //cout<<bd7 + bd8<<endl;//同號都沒溢出----結果負溢出

    //(異號測試)
    BigData bd1("-9999");
    BigData bd2("+1234567");
    cout<<bd1 + bd2<<endl;//異號都沒溢出----結果沒溢出
    BigData bd3("-99999999999999999999999999999999999999");
    BigData bd4("+11111111111111111111111111111111111111");
    cout<<bd3 + bd4<<endl;//異號都溢出了----結果溢出
    BigData bd5("-9999999999999999999999999999999");
    BigData bd6("1000");
    cout<<bd5 + bd6<<endl;//異號負數溢出----結果負溢出
    BigData bd7("-1000");
    BigData bd8("+9999999999999999999999999999999");
    cout<<bd7 + bd8<<endl;//異號正數溢出----結果正溢出
    BigData bd9(" -1111111111111111111111111111111");
    BigData bd10("+9999999999999999999999999999999");
    cout<<bd9 + bd10<<endl;//異號正數溢出----結果正溢出
}

void Test3()//減法測試
{
    ////(同號測試)
    //BigData bd1("+999999999");
    //BigData bd2("+1234567");
    //cout<<bd1 - bd2<<endl;//同號都沒溢出----結果沒溢出
    //BigData bd3("99999999999999999999999999999999999999");
    //BigData bd4("11111111111111111111111111111111111111");
    //cout<<bd3 - bd4<<endl;//同號都溢出了----結果溢出
    //BigData bd5("777777777777777777777777777");
    //BigData bd6("1000");
    //cout<<bd5 - bd6<<endl;//同號正數溢出----結果沒溢出
    //BigData bd7("-1000");
    //BigData bd8("-88888888888888888888888888888888");
    //cout<<bd7 + bd8<<endl;//同號負數溢出----結果溢出

    //(異號測試)
    BigData bd1("-9999");
    BigData bd2("+1234567");
    cout<<bd1 - bd2<<endl;//異號都沒溢出----結果沒溢出
    BigData bd3("-99999999999999999999999999999999999999");
    BigData bd4("+11111111111111111111111111111111111111");
    cout<<bd3 - bd4<<endl;//異號都溢出了----結果溢出
    BigData bd5("-9999999999999999999999999999999");
    BigData bd6("1000");
    cout<<bd5 - bd6<<endl;//異號負數溢出----結果負溢出
    BigData bd7("-1000");
    BigData bd8("+9999999999999999999999999999999");
    cout<<bd7 - bd8<<endl;//異號正數溢出----結果正溢出
    BigData bd9(" -1111111111111111111111111111111");
    BigData bd10("+9999999999999999999999999999999");
    cout<<bd9 - bd10<<endl;//異號都溢出了----結果溢出
}

void Test4()//乘法測試
{
    //(同號測試)
    BigData bd1("+999999999");
    BigData bd2("+111111");
    cout<<bd1 * bd2<<endl;//同號都沒溢出----結果沒溢出
    BigData bd3("-99999999999999999999999999999999999999");
    BigData bd4("-11111111111111111111111111111111111111");
    cout<<bd3 * bd4<<endl;//同號都溢出了----結果溢出
    BigData bd5("9999999999999");
    BigData bd6("9999999999999");
    cout<<bd5 * bd6<<endl;//同號都沒溢出----結果正溢出
    //異號測試
    BigData bd7("-1000");
    BigData bd8("7654321");
    cout<<bd7 * bd8<<endl;//異號都沒溢出----結果沒溢出
    BigData bd9("-9999999999999999999999999999");
    BigData bd10("+1000000000");
    cout<<bd9 * bd10<<endl;//異號溢出了----結果負溢出
    BigData bd11("9999999999999");
    BigData bd12("-9999999999999");
    cout<<bd11 * bd12<<endl;//同號都沒溢出----結果負溢出
}

void Test5()//測試除法
{
    BigData bd1("+999999999");
    BigData bd2("+11111111111111");
    cout<<bd1 / bd2<<endl;//左操作數小於有操作數----結果爲0
    BigData bd3("0");
    BigData bd4("-11111111111111111");
    cout<<bd3 / bd4<<endl;//左操作數--是0--結果爲0
    BigData bd5("9999999999999");
    BigData bd6("9999999999999");
    cout<<bd5 / bd6<<endl;//同號且絕對值相等----結果爲1
    BigData bd7("-9999999999999");
    BigData bd8("9999999999999");
    cout<<bd7 / bd8<<endl;//異號且絕對值相等----結果爲-1
    BigData bd9("-9999999999999999999999999999");
    BigData bd10("+1");
    cout<<bd9 / bd10<<endl;//右操作數爲1---結果爲左操作數
    BigData bd11("9999999999999");
    BigData bd12("-1");
    cout<<bd11 / bd12<<endl;//右操作數爲-1---結果爲 -左操作數
    BigData bd13("-9999999999999999999999999999");
    BigData bd14("+100000000");
    cout<<bd13 / bd14<<endl;//異號且至少有一個溢出
    BigData bd15("9999999999999");
    BigData bd16("100000");
    cout<<bd15 / bd16<<endl;//同號且都沒有溢出
}
int main()
{
    //Test1();
    //Test2();
    //Test3();
    //Test4();
    Test5();
    system("pause");
    return 0;
}

沒有最好,只有更好!

發佈了122 篇原創文章 · 獲贊 269 · 訪問量 35萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章