大数据运算

1、大数的数据类型设计
    可以用一个string和一个long long类型来表示一个大数类型,long long类型表示没有超出范围,string表示超出范围的大数。在初始化的时候我们可以将string和long 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;
}
5、除法的实现 
除法的实现有些复杂,原理如下图所示: 
这里写图片描述

BigData BigData::operator/(BigData b)
{
       if ("+0" == b._strData)        //除数不为0
       {
              cout << "exception" << endl;
              return BigData("");
       }

        //考虑一些特殊情况
       if (!isINIT64overflow(_strData) && !isINIT64overflow(b._strData))
       {
              return _value / b._value;
       }
       if ("+0" == _strData || _strData.size()<b._strData.size() || \
              (_strData.size()==b._strData.size() && strncmp(_strData.c_str()+1,b._strData.c_str()+1,_strData.size()-1)<0))
              return BigData(0);
       if (_strData.size() == b._strData.size() && strncmp(_strData.c_str() + 1, b._strData.c_str() + 1, _strData.size() - 1)==0)
       {
              if (_strData[0]==b._strData[0])
                     return BigData(1);
              else
                     return BigData(-1);
       }
       if ("+1" == b._strData)
              return BigData(_strData);
       else if ("-1" == b._strData)
       {
              string ret= _strData;
              ret[0] = '+';
              if ('+' == _strData[0])
                     ret[0] = '-';
              return BigData(ret);
       }

       return BigData(Div(_strData,b._strData));
}
string BigData::Div(string strLeft, string strRight)
{
       char symbol = '+';
       if (strLeft[0] != strRight[0])
              symbol = '-';
       size_t LSize = strLeft.size();
       size_t RSize = strRight.size();
       char *pLeft = (char*)strLeft.c_str()+1;
       char *pRight = (char*)strRight.c_str()+1;
       size_t dataLen =0;
       string strTemp;
       strTemp.append(1,symbol);
       while ('\0'!=(*(pLeft+dataLen-1)))
       {
              if ('0' == *pLeft)
              {
                     pLeft++;
                     strTemp.append(1, '0');
                     continue;
              }
              if (!isLgtR(pLeft, dataLen, pRight, RSize-1))
              {
                     strTemp.append(1,'0');
                     dataLen++;
              }
              else
              {
                     strTemp.append (1,SubLoop(pLeft, dataLen, pRight, RSize)+'0');
                     dataLen++;
              }
       }
       return strTemp;
}
char BigData::SubLoop(char* &pLeft, size_t& dataLen, const char *pRight,const size_t RSize)
{
       char count = 0;
       while (isLgtR(pLeft, dataLen, pRight, RSize-1))
       {
              for (size_t index = 1; index <= dataLen; index++)
              {
                     char ret = *(pLeft + dataLen - index) - '0';
                     if (RSize>index)
                     {
                           ret -= (*(pRight + RSize - index-1) - '0');
                     }
                     if (ret < 0)
                     {
                           *(pLeft + dataLen - index - 1) -= 1;
                           ret += 10;
                     }
                     *(pLeft + dataLen - index) = ret + '0';
              }
              count++;
              while ('0' == *pLeft&&dataLen>0)
              {
                     pLeft++;
                     dataLen--;
              }
       }
       return count;
}
//判断以pLeft开始dataLen长度所表示的数的大小是不是大于除数
bool BigData::isLgtR(const char* pLeft,const size_t dataLen, const char *pRight, const size_t RSize)  
{
       if (dataLen > RSize)
              return true;
       else if (dataLen == RSize)
       {
              if (strncmp(pLeft, pRight, dataLen) >= 0)
                     return true;
       }
       return false;
}

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值