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)
{
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;
}
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