1. 程式人生 > >專案:大數的運算

專案:大數的運算

專案背景:資料的範圍超過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; }