大数运算

1、大数的数据类型设计
    可以用一个string和一个long long类型来表示一个大数类型,long long类型表示没有超出范围,string表示超出范围的大数。在初始化的时候我们可以将stringlong long都进行初始化,在运算的时候再判断是用long long运算还是用string进行运算。
typedef long long INIT64;
class BigData
{
       friend ostream& operator<<(ostream& os,const BigData& b);
public:
       BigData(INIT64  value=0);
       BigData(string strData);
       BigData operator+(BigData b);
       BigData operator-(BigData b);
       BigData operator*(BigData b);
       BigData operator/(BigData b);
private:
       bool isINIT64overflow(const string& strData);
       string Add(string strLeft, string strRight);
       string Sub(string strLeft, string strRight);
       string Mul(string strLeft, string strRight);
       string Div(string strLeft, string strRight);
       char SubLoop(char* &pLeft, size_t& dataLen, const char *pRight, const size_t RSize);
       bool isLgtR(const char* pLeft, const size_t dataLen, const char *pRight, const size_t RSize);
private:
       INIT64 _value;
       string _strData;
};

1.1、用一个整数初始化大数对象,其中sprintf的作用就相当于itoa.
BigData::BigData(INIT64  value)
       :_value(value)
{
       char buf[128] = { 0 };
       sprintf(buf,"%lld",_value);
       _strData =buf;
}
1.2、用一个字符串初始化一个大数对象,考虑到输入的字符串可能有各种异常情况,比如前面一空白字符或0开头,出现字母等等,我们将常见的异常情况过滤掉(可以参考atoi是怎么进行过滤的)。
BigData::BigData(string strData)
       :_value(0)
       , _strData("+0")
{
       char* pData = (char*)strData.c_str();
       while (isspace(*pData))              //过滤空白
              pData++;
       if ('\0' == *pData)
              return;
       char symbol = *pData;
       if (('+' == *pData) || ('-' == *pData))    //过滤符号
              pData++;
       else if (isdigit(*pData))
              symbol = '+';
       else
              return;
       while('0' == *pData)         //过滤前面的0
              pData++;
       if ('\0' == *pData)
              return;
       _strData.resize(strlen(pData)+1);
       _strData[0] = symbol;
       int count = 1;
       while (*pData>='0' && *pData<='9')
       {
              _value = _value * 10 + *pData - '0';
              _strData[count++] = *pData;
              pData++;
       }
       if (*pData)
              _strData.resize(count);
       if (symbol == '-')
              _value = 0 - _value;
}

1.3、判断一个大数是不是超出范围,因为整数的最大数据类型是long long类型,我们必须用string中的值进行判断,判断大数是不是超出范围。
bool BigData::isINIT64overflow(const string& strData)
{
       const string max_value= "+9223372036854775807";
       const string min_value= "-9223372036854775808";
       if (strData.size() < max_value.size())
              return false;
       else if (strData.size() == max_value.size())
       {
              if (('+'==strData[0]&&strData<=max_value)\
                     ||('-'==strData[0]&&strData>=min_value))
                     return false;
       }
       return true;
}

ostream& operator<<(ostream& os, const BigData& b)
{
       const char *str = b._strData.c_str();
       if ('+' == *str)
              cout << str + 1;
       else
              cout << str;
       return os;
}

2、加法的实现
BigData BigData::operator+(BigData b)
{
       if (!isINIT64overflow(_strData) && !isINIT64overflow(b._strData))   //如果都没溢出
       {
              if (_strData[0] != b._strData[0])     //异号直接相加,不会溢出
                     return _value + b._value;
              else if ('+' == _strData[0] && '+' == b._strData[0])
              {
                     INIT64 max_value = 9223372036854775807;
                     if (max_value - _value >= b._value)       //两个正数相加不会溢出
                     {
                           return _value + b._value;
                     }
              }
              else if ('-' == _strData[0] && '-' == b._strData[0])
              {
                     INIT64 min_value =0-9223372036854775808;
                     if (min_value - _value <= b._value)   //两个负数相加不会溢出
                     {
                           return _value + b._value;
                     }
              }
       }
       if (_strData[0] == b._strData[0])      //同号相加
              return BigData(Add(_strData, b._strData));
       else                                         //异号相加可以转换成减法
       {
               //异号相加转换成正号相减
              string Left = _strData;       
              string Right = b._strData;
              Left[0] = '+';
              Right[0] = '+';
              if ('-' == _strData[0])       
                     swap(Left,Right);
              return BigData(Sub(Left,Right));
       }
}


string BigData::Add(string strLeft,string strRight)
{
       size_t LSize = strLeft.size();
       size_t RSize = strRight.size();
       if (LSize < RSize)                 //为了方便,我们保证+号左边的数的位数不小于加号右边的数
       {
              swap(strLeft,strRight);
              swap(LSize,RSize);
       }
       string strTemp;
       strTemp.resize(LSize+1);                 //两个数相加,结果的位数最长是两个运算数中位数最长的运算数加+1
       strTemp[0] = strLeft[0];                
       char step = 0;                            //记录进位
       for (size_t index = 1; index < LSize;index++)
       {
              char ret = strLeft[LSize - index]-'0';
              ret += step;
              if (RSize>index)
              {
                     ret=ret+strRight[RSize-index] - '0';
              }
              step = ret / 10;                     //保存进位情况
              strTemp[LSize + 1 - index] = ret%10+'0'; 
       }
       strTemp[1] = step+'0';                   //向最高位进位,取决于step的值
       return strTemp;
}

3、减法的实现参考加法

4、乘法的实现
BigData BigData::operator * (BigData b)
{
       if ("+0" == _strData || "+0" == b._strData)
              return BigData(0);
       if (!isINIT64overflow(_strData) && !isINIT64overflow(b._strData))
       {
              INIT64 max_value = 9223372036854775807;
              INIT64 min_value = 0 - 9223372036854775808;
              if (_strData[0] == b._strData[0])
              {
                     if (('+' == _strData[0] && max_value / _value >= b._value) || \
                           ('-' == _strData[0] && max_value / _value <= b._value))
                           return _value*b._value;
              }
              else
              {
                     if (('+' == _strData[0] && min_value / _value <= b._value) || \
                           ('-' == _strData[0] && min_value / _value >= b._value))
                           return BigData(_value*b._value);
              }
       }
       //判断运算数中有没有为正负1的特殊情况
       if ("+1"==_strData)
              return BigData(b._strData);
       if ("+1" == b._strData)
              return BigData(_strData);
       if ("-1" == _strData)
       {
              string ret = b._strData;
              if ('+' == b._strData[0])
                     ret[0] = '-';
              else
                     ret[0] = '+';
              return BigData(ret);
       }
       if ("-1" == b._strData)
       {
              string ret =_strData;
              if ('+' ==_strData[0])
                     ret[0] = '-';
              else
                     ret[0] = '+';
              return BigData(ret);
       }
       return BigData(Mul(_strData, b._strData));
}


string BigData::Mul(string strLeft, string strRight)
{
       size_t LSize = strLeft.size();
       size_t RSize = strRight.size();

       //乘法相乘的时候,保证*号左边的数的长度小于等于*号右边的数
       if(LSize > RSize)
       {
              swap(LSize,RSize);
              swap(strLeft,strRight);
       }
       char symbol = '+';
       if (strLeft[0] != strRight[0])         //异号相乘为负
              symbol='-';
       string strTemp;
       strTemp.resize(LSize+RSize-1,'0');      //两数相乘,结果的位数最长是两个运算数位数之和
       strTemp[0] = symbol;
       //因为两个数相乘,即乘数的每一位都要和被乘数相运算,所以必须用两个循环
       for (size_t i = 1; i < LSize;i++)
       {
              if ('0' == strLeft[LSize - i])
                     continue;
              char step=0;                         //记录进位
              for (size_t j=1;j<RSize;j++)
              {
                     char ret = strLeft[LSize-i]-'0';
                     ret*=(strRight[RSize-j]-'0');
                     ret += step+strTemp[LSize + RSize - j - i] - '0';
                     strTemp[LSize + RSize - j - i]= ret%10+'0';
                     step = ret / 10;
              }
              strTemp[LSize- i] += step;
       }
       return strTemp;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值