《C++大數據運算(+、-、*、/)》

計算機中整數數據的最大類型爲long long類型,依據計算機位數的不同它的範圍也不同,以32位爲例long long類型的取值範圍爲【-9223372036854775808,9223372036854775807】,那麼計算機可以進行的數值運算就必須在這個範圍之內嗎?未必,所以產生了大數據運算來解決更大範圍內的數值運算,它的思想是以字符串代表數值進行各類運算。
這裏寫圖片描述
Test.c

#include"BigData.h"

int main()
{
    BigData bg1(9900000099);
    BigData bg2(33);
    BigData bg3;
    bg3 = bg1 - bg2;
    cout << bg3 << endl;
    return 0;
}

BigData.h

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<string>
#include<assert.h>
#include<ctype.h>
using namespace std;

typedef long long INT64;
const INT64 MAX_VALUE = 9223372036854775807;
const INT64 MIN_VALUE = -9223372036854775808;


class BigData
{
public:
    BigData(INT64 value = 0);
    BigData(const string& str);

    BigData operator+(const BigData& bg) const;
    BigData operator-(BigData bg) const;
    BigData operator*(const BigData& bg) const;
    BigData operator/(const BigData& bg) const;
    friend ostream& operator<<(ostream& cou,const BigData& bg);

    bool IsINT64OverFlow() const;
private:
    string _strData;
    INT64 _value;
};

BigData.cpp


#include"BigData.h"

BigData::BigData(INT64 value)//用數值初始化對象的構造函數
    : _value(value)
{
    char Symbol = '+';
    if (value < 0)
        Symbol = '-';
    do
    {

        _strData += (value % 10) + '0';
        value /= 10;
    }
    while (value);
    _strData += Symbol;
    char* ptr = (char*)_strData.c_str();
    reverse(ptr, ptr + _strData.size());//逆置字符串
}
BigData::BigData(const string& str)//用字符串初始化對象的構造函數
:_strData("+0")
, _value(0)
{
    char* ptr = (char*)str.c_str();
    while (isspace(*ptr))//排除空白字符串
    {
        ptr++;
    }
    if (*ptr == '\0')
        return;
    char Symbol = 0;
    if (*ptr == '+' || *ptr == '-')
    {
        Symbol = *ptr;
        ptr++;
    }
    else if (isdigit(*ptr))
    {
        Symbol = '+';
    }
    else
        return;
    while (*ptr == '0')//排除數字最開始處的零
        *ptr++;
    if (*ptr == '\0')
        return;
    _strData[0] = Symbol;
    int count = 1;
    _strData.resize(strlen(ptr) + 1);
    while (isdigit(*ptr))
    {
        _strData[count] = *ptr;
        _value = _value*10 + (*ptr - '0');
        count++;
        ptr++;
    }
    if (_strData[0] == '-')
        _value = -_value;
}

bool BigData::IsINT64OverFlow() const//判斷對象中的_value是否超出long long類型的範圍
{
    string strRet("+9223372036854775807");
    if (_strData[0] == '-')
        strRet = "-9223372036854775808";
    if ((strRet.size() > _strData.size()) || (_strData.size() == strRet.size() && strcmp(_strData.c_str(), strRet.c_str()) <= 0))
        return false;
    return true;
}

string Add(string strLeft, string strRight)//同號加法
{
    string strRet;
    size_t LSize = strLeft.size();
    size_t RSize = strRight.size();
    if (LSize < RSize)//將左參數調整爲最長字符串
    {
        strLeft.swap(strRet);
        swap(LSize, RSize);
    }
    strRet.resize(LSize + 1);//結果字符串最長長度
    strRet[0] = strLeft[0];
    char Step = 0;//進位
    for (size_t i = 1; i < LSize; i++)
    {
        char Ret = (strLeft[LSize - i] - '0') + Step;
        if (i < RSize)
            Ret += strRight[RSize - i] - '0';
        if (Ret >= 10)
        {
            Step = Ret / 10;
            Ret = Ret % 10;
        }
        strRet[LSize - i + 1] = Ret + '0';
    }
    strRet[1] = Step + '0';
    return strRet;
}
string Sub(string strLeft, string strRight)//異號加法
{
    size_t LSize = strLeft.size();
    size_t RSize = strRight.size();
    string strRet;//調整左字符串爲長度最長或字符串最大的字符(不含符號位)
    if (LSize < RSize || (LSize == RSize && strcmp(strLeft.c_str() + 1, strRight.c_str() + 1) < 0))
    {
        strLeft.swap(strRight);
        swap(LSize, RSize);
    }
    strRet.resize(LSize);
    strRet[0] = strLeft[0];
    for (size_t i = 1; i < LSize; i++)
    {
        char Ret = (strLeft[LSize - i] - '0');
        if (i < RSize)
            Ret -= strRight[RSize - i] - '0';
        if (Ret < 0)
        {
            strRet[LSize - i - 1] -= 1;
            Ret += 10;
        }
        strRet[LSize - i] = Ret + '0';
    }
    return strRet;
}

string Mul(string strLeft, string strRight)//乘法
{
    string strRet;
    size_t LSize = strLeft.size();
    size_t RSize = strRight.size();
    if (LSize > RSize)
    {
        strLeft.swap(strRight);
        swap(LSize, RSize);
    }
    strRet.resize(LSize + RSize - 1, '0');
    if (strLeft[0] == strRight[0])
        strRet[0] = '+';
    else
        strRet[0] = '-';
    char offset = 0;
    for (size_t i = 1; i < LSize; i++)
    {
        char Step = 0;
        char Ret = strLeft[LSize - i] - '0';//左字符串的從右往左每一位
        for (size_t j = 1; j < RSize; j++)//用左字符串取出的一位位乘右字符串的每一位
        {
            char Res = Ret*(strRight[RSize - j] - '0') + Step
                + (strRet[LSize + RSize - 1 - j - offset] - '0');
            Step = 0;
            if (Res > 10)
            {
                Step = Res / 10;
            }
            strRet[LSize + RSize - 1 - j - offset] = (Res % 10) + '0';
        }
        strRet[LSize - offset - 1] = Step + '0';
        offset++;
    }
    return strRet;
}

bool IsLeftBig(char* pLeft,size_t DataLen,char* pRight,size_t RSize)
//判斷除法中每一次進入SubLoop函數中的左參數字符串是否大於右參數字符串
{
    if (DataLen > RSize || 
        (DataLen == RSize && strcmp(pLeft, pRight) >= 0))
        return true;
    return false;
}

char SubLoop(char*& pLeft, size_t& DataLen, char*& pRight, size_t& RSize)
//除法中的減法
{
    char Com = '0';//循環次數 == 商數
    while (1)
    {
        while (*pLeft == '0' && DataLen > 0)//最多跳過DataLen個0
        {
            pLeft++;
            DataLen--;
        }
        if (!IsLeftBig(pLeft, DataLen, pRight, RSize))
            break;
        for (size_t i = 1; i <= RSize; i++)//一次減法
        {
            char Ret = pLeft[DataLen - i] - '0';
            Ret -= pRight[RSize - i] - '0';
            if (Ret < 0)
            {
                pLeft[DataLen - i - 1] -= 1;
                Ret += 10;
            }
            pLeft[DataLen - i] = Ret + '0';
        }
        Com++;
    }
    return Com;
}

string Div(string strLeft, string strRight)//除法
{
    string strRet;
    char* pLeft = (char*)(strLeft.c_str() + 1);
    char* pRight = (char*)(strRight.c_str() + 1);
    size_t LSize = strLeft.size();
    size_t RSize = strRight.size() - 1;
    size_t DataLen = RSize;
    if (strLeft[0] == strRight[0])
        strRet += '+';
    else
        strRet += '-';
    while (strRet.size() < (LSize - RSize + 1))
    {
        if (*pLeft == '0')//如果下一位爲零,則商零
        {
            strRet += '0';
            pLeft++;
            continue;
        }
        if (!IsLeftBig(pLeft,DataLen,pRight,RSize))
        {
            strRet += '0';
            DataLen++;
            strRet += SubLoop(pLeft, DataLen, pRight, RSize);
        }
        else
        {
            strRet += SubLoop(pLeft, DataLen, pRight, RSize);
        }
        DataLen++;
    }
    return strRet;
}


BigData BigData::operator+(const BigData& bg) const
{
    if (!IsINT64OverFlow() && !bg.IsINT64OverFlow())
    {
        if (_strData[0] != bg._strData[0])
        {
            return BigData(_value + bg._value);
        }
        else if ((_strData[0] == '+' && (MAX_VALUE - _value >= bg._value)) 
            || (_strData[0] == '-' && (MIN_VALUE - _value <= bg._value)))
        {
            return BigData(_value + bg._value);
        }
    }
    if (_strData[0] == bg._strData[0])
        return BigData(Add(_strData, bg._strData));
    return BigData(Sub(_strData, bg._strData));
}
BigData BigData::operator-(BigData bg) const
{
    if (!IsINT64OverFlow() && !bg.IsINT64OverFlow())
    {
        if (_strData[0] == bg._strData[0])
        {
            return BigData(_value - bg._value);
        }
        else if ((_strData[0] == '+' && MAX_VALUE + bg._value >= _value)
            || (_strData[0] == '-' && MIN_VALUE + bg._value <= _value))
        {
            return BigData(_value - bg._value);
        }
    }
    if (_strData[0] == bg._strData[0])
    {
        if (_strData[0] == '+')
            bg._strData[0] = '-';
        else
            bg._strData[0] = '+';
        return BigData(Sub(_strData,bg._strData));
    }
    else
    {
        if (_strData[0] == '+')
            bg._strData[0] = '+';
        else
            bg._strData[0] = '-';
        return BigData(Add(_strData,bg._strData));
    }
}
BigData BigData::operator*(const BigData& bg) const
{
    if (_strData == "+0" || bg._strData == "+0")
        return BigData(0);
    if (!IsINT64OverFlow() && !bg.IsINT64OverFlow())
    {
        if (_strData[0] == bg._strData[0])
        {
            if ((_strData[0] == '+' && MAX_VALUE / _value >= bg._value)
                || (_strData[0] == '-' && MAX_VALUE / _value <= bg._value))
            {
                return BigData(_value * bg._value);
            }
        }
        else
        {
            if ((_strData[0] == '+' && MIN_VALUE / _value <= bg._value)
                || (_strData[0] == '-' && MIN_VALUE / _value >= bg._value))
            {
                return BigData(_value * bg._value);
            }
        }
    }
    return BigData(Mul(_strData, bg._strData));
}
BigData BigData::operator/(const BigData& bg) const
{
    //除數爲0
    if (bg._strData == "+0")
    {
        assert(0);
    }
    if (_strData == "+0")
        return BigData(0);
    //左邊小於右邊
    if ((_strData.size() < bg._strData.size())
        || ((_strData.size() == bg._strData.size())
        && strcmp(_strData.c_str() + 1, bg._strData.c_str() + 1) < 0))
        return BigData(0);
    if ((_strData.size() == bg._strData.size())
        && strcmp(_strData.c_str() + 1, bg._strData.c_str() + 1) == 0)
    {
        if (_strData[0] == bg._strData[0])
            return BigData(1);
        else
            return BigData(-1);
    }
    if (bg._strData == "+1" || bg._strData == "-1")
    {
        BigData tmp(*this);
        if (_strData[0] == bg._strData[0])
        {
            tmp._strData[0] = '+';
        }
        else
        {
            tmp._strData[0] = '-';
        }
        return tmp;
    }
    if (!IsINT64OverFlow() && !bg.IsINT64OverFlow())
        return BigData(_value / bg._value);
    return BigData(Div(_strData, bg._strData));
}

ostream& operator<<(ostream& cou,const BigData& bg)
{
    cou << "string:" << bg._strData << "  value:" << bg._value;
    return cou;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章