專案:大數的運算
阿新 • • 發佈:2019-02-05
專案背景:資料的範圍超過long long等整型型別所能儲存的範圍。
專案簡介:實現大數的輸入和輸出以及對它進行加、減、乘和除運算。
開發平臺:Visual Studio 2012
技術要點:C++類和物件,string
程式碼實現:
//CalOfBigData.h
#pragma once
#include <string>
#include <iostream>
#include <cassert>
using namespace std;
#define UN_INIT 0xcccccccccccccccc
#define MAX_INT64 0x7fffffffffffffff
#define MIN_INT64 0x8000000000000000
typedef long long INT64;
int index = 0;
class BigData
{
public:
BigData(INT64 data = UN_INIT);
BigData(const char *pData);
BigData operator+(BigData& bigData);
BigData operator-(const BigData& bigData);
BigData operator*(const BigData& bigData);
BigData operator /(const BigData& bigData);
friend std::ostream& operator<<(std::ostream& _cout, const BigData& bigData);
friend std::istream& operator>>(std::istream& _cin, BigData bigData);
bool IsINT64Overflow()const;
private:
std::string Add(std::string left, std ::string right);
std::string Sub(std::string left, std::string right);
std::string Mul(std::string left, std::string right);
std::string Div(std::string left, std::string right);
void INT64ToString();
bool IsLeftStrBig(char *pLeft, size_t LSize, char *pRight, size_t RSize);
char SubLoop(char *&pLeft, int& LSize, char *pRight, size_t RSize);
private:
INT64 Data;
std::string strData;
};
//CalOfBigData.cpp
#include "BigData.h"
BigData::BigData(INT64 data)
: Data(data)
, strData("")
{
INT64ToString();
}
BigData::BigData(const char *_pdata)
{
assert(_pdata);
char csymbol = _pdata[0];
char* pdata = (char*)_pdata;
if (csymbol == '+' || csymbol == '-')
{
pdata++;
}
else if (*pdata >= '0'&& *pdata <= '9')
{
csymbol = '+';
}
else
{
Data = 0;
strData = '0';
return;
}
while (*pdata == '0')
{
pdata++;
}
strData.resize(strlen(pdata) + 1);
Data = 0;
strData[0] = csymbol;
int count = 1;
while (pdata)
{
if (*pdata >= '0' && *pdata <= '9')
{
Data = Data * 10 + *pdata - '0';
strData[count++] = *pdata++;
}
else
{
break;
}
}
if ('-' == csymbol)
{
Data = 0 - Data;
}
}
BigData BigData::operator+(BigData& bigData)
{
if (!IsINT64Overflow() && !bigData.IsINT64Overflow())
{
if (strData[0] != bigData.strData[0])
{
return BigData(Data + bigData.Data);
}
else
{
if ((strData[0] == '+' && MAX_INT64 - Data >= bigData.Data
|| (strData[0]) == '-' && MIN_INT64 - Data <= bigData.Data))
{
return BigData(Data + bigData.Data);
}
}
}
std::string strret;
if (strData[0] == bigData.strData[0])
{
strret = Add(strData, bigData.strData);
}
else
{
strret = Sub(strData, bigData.strData);
}
return BigData(strret.c_str());
}
BigData BigData::operator-(const BigData& bigData)
{
if (!IsINT64Overflow() && !bigData.IsINT64Overflow())
{
if (strData[0] == bigData.strData[0])
{
return BigData(Data - bigData.Data);
}
else
{
if ((strData[0] == '+' && MAX_INT64 + bigData.Data>= Data)
|| (strData[0] == '-' && MIN_INT64 + bigData.Data <= Data))
{
return BigData(Data - bigData.Data);
}
}
}
std::string strret;
if (strData[0] != bigData.strData[0])
{
strret = Add(strData, bigData.strData);
}
else
{
strret = Sub(strData, bigData.strData);
}
return BigData(strret.c_str());
}
BigData BigData::operator*(const BigData& bigData)
{
if (Data == 0 || bigData.Data == 0)
{
return BigData(INT64(0));
}
if (!IsINT64Overflow() && !bigData.IsINT64Overflow())
{
if (strData[0] == bigData.strData[0])
{
if ((strData[0] == '+' && MAX_INT64 / Data >= bigData.Data)
|| (strData[0] == '-' && MAX_INT64 / Data <= bigData.Data))
{
return BigData(Data * bigData.Data);
}
}
else
{
if ((strData[0] == '+' && MIN_INT64 / Data <= bigData.Data)
|| (strData[0] == '-' && MIN_INT64 / Data >= bigData.Data))
{
return BigData(Data * bigData.Data);
}
}
}
return BigData(Mul(strData, bigData.strData).c_str());
}
BigData BigData::operator/(const BigData& bigData)
{
if (bigData.Data == 0)
{
assert("除數不可以為0");
return BigData(INT64(0));
}
if (!IsINT64Overflow() && bigData.IsINT64Overflow())
{
return BigData(Data / bigData.Data);
}
return BigData(Div(strData, bigData.strData).c_str());
}
std::string BigData::Add(std::string left,std::string right)
{
int lsize = left.size();
int rsize = right.size();
char ch = left[0];
if (lsize < rsize)
{
std::swap(left,right);
std::swap(lsize,rsize);
}
std::string strret;
strret.resize(lsize + 1);
strret[0] = ch;
char cstep = 0;
int n = 1;
while (n < lsize)
{
char cret = left[lsize - n] - '0' + cstep;
if (n < rsize)
{
cret += right[rsize - n] - '0';
}
strret[lsize - n + 1] = (cret % 10 + '0');
cstep = cret / 10;
n++;
}
strret[1] = cstep + '0';
return strret;
}
std::string BigData::Sub(std::string left, std::string right)
{
int lsize = left.size();
int rsize = right.size();
char csymbol = left[0];
if ((lsize < rsize) ||
(lsize == rsize && left < right))
{
std::swap(left, right);
std::swap(lsize, rsize);
if (csymbol == '+')
{
csymbol = '-';
}
else
{
csymbol = '+';
}
}
std::string strret;
strret.resize(lsize);
strret[0] = csymbol;
int n = 1;
while (n < lsize)
{
char cret = left[lsize - n] - '0';
if (n < rsize)
{
cret -= right[rsize - n] - '0';
}
if (cret < 0)
{
left[lsize - n - 1] -= 1;
cret += 10;
}
strret[lsize - n] = (cret + '0');
n++;
}
return strret;
}
std::string BigData::Mul(std::string left, std::string right)
{
int lsize = left.size();
int rsize = right.size();
if (lsize > rsize)
{
swap(left, right);
swap(lsize, rsize);
}
char csymbol = '+';
if (left[0] != right[0])
{
csymbol = '-';
}
string strret;
strret.assign(lsize + rsize - 1, '0');
strret[0] = csymbol;
int datalen = strret.size();
int ioffset = 0;
for (int lidx = 1; lidx < lsize; lidx++)
{
char cleft = left[lsize - lidx] - '0';
char cstep = 0;
if (cleft == 0)
{
ioffset++;
continue;
}
for (int ridx = 1; ridx < rsize; ridx++)
{
char cret = cleft*(right[rsize - ridx]-'0');
cret += cstep;
cret += (strret[datalen - ioffset - ridx] - '0');
strret[datalen - ioffset - ridx] = (cret % 10 + '0');
cstep = cret / 10;
}
strret[datalen - ioffset - rsize] += cstep;
ioffset++;
}
return strret;
}
std::string BigData::Div(std::string left, std::string right)
{
char lsize = left.size();
char rsize = right.size();
char csymbol = '+';
if (left[0] != right[0])
{
csymbol = '-';
}
if ((lsize < rsize) ||
(lsize == rsize && strcmp(left.c_str() + 1, right.c_str() + 1) < 0))
{
return "0";
}
else
{
if (right == "-1" || right == "+1")
{
left[0] = csymbol;
return left;
}
}
string strret;
strret.append(1, csymbol);
char *pleft = (char*)(left.c_str() + 1);
char *pright = (char*)(right.c_str() + 1);
int datalen = 1;
lsize -= 1;
for (index = 0; index< lsize;)
{
if (*pleft == '0')
{
strret.append(1, '0');
pleft++;
index++;
continue;
}
if (!IsLeftStrBig(pleft, datalen, pright, rsize - 1))
{
strret.append(1, '0');
datalen++;
if (index + datalen > lsize)
{
break;
}
continue;
}
else
{
strret.append(1,SubLoop(pleft, datalen, pright ,rsize - 1));
datalen++;
}
}
return strret;
}
void BigData::INT64ToString()
{
char csymbol = '+';
INT64 tmp = Data;
if (tmp < 0)
{
csymbol = '-';
tmp = 0 - tmp;
}
strData.append(1, csymbol);
while (tmp)
{
strData.append(1,tmp%10 + '0');
tmp /= 10;
}
char *left = (char*)(strData.c_str() + 1);
char *right = (char*)(strData.c_str() + strData.size() - 1);
while (left < right)
{
char ctmp = *left;
*left++ = *right;
*right-- = ctmp;
}
}
bool BigData::IsINT64Overflow()const
{
std::string tmp;
if ('+' == strData[0])
{
tmp = "+9223372036854775807";
}
else
{
tmp = "-9223372036854775808";
}
if ((strData.size() > tmp.size()) ||
((strData.size() == tmp.size())&&(strData > tmp)))
{
return true;
}
return false;
}
bool BigData::IsLeftStrBig(char *pLeft, size_t LSize, char *pRight, size_t RSize)
{
assert(pLeft != NULL && pRight != NULL);
if ((LSize > RSize) ||(LSize == RSize && strncmp(pLeft,pRight,LSize) >= 0))
{
return true;
}
return false;
}
char BigData::SubLoop(char *&pLeft, int& LSize, char *pRight, size_t RSize)
{
assert(pLeft != NULL && pRight != NULL);
char cret = '0';
while (true)
{
if (!IsLeftStrBig(pLeft, LSize, pRight, RSize))
{
break;
}
int ldatalen = LSize - 1;
int rdatalen = RSize - 1;
while (ldatalen >= 0 && rdatalen >= 0)
{
if (pLeft[ldatalen] < pRight[rdatalen])
{
pLeft[ldatalen - 1] -= 1;
pLeft[ldatalen] += 10;
}
pLeft[ldatalen] = pLeft[ldatalen] - pRight[rdatalen] + '0';
ldatalen--;
rdatalen--;
}
while ((*pLeft == '0') && (LSize > 0))
{
pLeft++;
LSize--;
index++;
}
cret++;
}
return cret;
}
std::ostream& operator<<(std::ostream& _cout, const BigData& bigData)
{
if (!bigData.IsINT64Overflow())
{
_cout << bigData.Data;
}
else
{
char* pData = (char*)bigData.strData.c_str();
if (pData[0] == '+')
{
pData++;
}
_cout << pData;
}
return _cout;
}