您好,登錄后才能下訂單哦!
項目背景:
大數運算,顧名思義,就是很大的數值的數進行一系列的運算。
我們知道,在數學中,數值的大小是沒有上限的,但是在計算機中,由于字長的限制,計算機所能表示的范圍是有限的,當我們對比較小的數進行運算時,如:1234+5678,這樣的數值并沒有超出計算機的表示范圍,所以可以運算。但是當我們在實際的應用中進行大量的數據處理時,會發現參與運算的數往往超過計算機的基本數據類型的表示范圍,比如說,在天文學上,如果一個星球距離我們為100萬光年,那么我們將其化簡為公里,或者是米的時候,我們會發現這是一個很大的數。這樣計算機將無法對其進行直接計算。
可能我們認為實際應用中的大數也不過就是幾百位而已,實際上,在某些領域里,甚至可能出現幾百萬位的數據進行運算,這是我們很難想象的。如果沒有計算機,那么計算效率可想而知。
由于編程語言提供的基本數值數據類型表示的數值范圍有限,不能滿足較大規模的高精度數值計算,因此需要利用其他方法實現高精度數值的計算,于是產生了大數運算。本項目實現了大數運算主要的加、減、乘除四種方法。
BigData.h
#ifndef BIG_DATA_H #define BIG_DATA_H #include <string> #define MAX_INT64 (INT64)0x7FFFFFFFFFFFFFFF #define MIN_INT64 (INT64)0x8000000000000000 //如果不強轉,系統會定義為unsigned INT64類型 #define UN_INIT 0xCCCCCCCCCCCCCCCC typedef long long INT64; class BigData { public: BigData(INT64 value); BigData(const char* pData); public: BigData operator+(const BigData& bigdata); BigData operator-(const BigData& bigdata); BigData operator*(const BigData& bigdata); BigData operator/(const BigData& bigdata); protected: 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); protected: bool IsINT64Overflow() const; friend std::ostream& operator<<(std::ostream& _cout, const BigData& bigdata); void INT64ToString(); bool IsLeftStrBig(const char* pLeft, int LSize, const char* pRight, int RSize); char SubLoop(char* pLeft, int LSize, char* pRight, int RSize); protected: INT64 _value; std::string _strData; }; #endif
BigData.cpp
#include "BigData.h" #include <assert.h> BigData::BigData(INT64 value) :_value(value) { INT64ToString(); //將_value中的值保存在_strData中 } BigData::BigData(const char* pData) { //要處理的輸入:"12345678" "234567qwe" "+" " " "0000123456" if (NULL == pData) { assert(false); return; } //處理符號位 char* pStr = (char*)pData; char cSymbol = pData[0]; if ('+' == cSymbol || '-' == cSymbol) pStr++; else if (cSymbol >= '0' && cSymbol <= '9') cSymbol = '+'; else return; //"0000123456" int iDataLen = strlen(pData); if (iDataLen > 1) { while ('0' == *pStr) pStr++; } _strData.resize(strlen(pData)+1); //為_strData分配空間 _strData[0] = cSymbol; //第0位保存符號 //"123456qwe" _value = 0; int iCount = 1; while (*pStr >= '0' && *pStr <= '9') { _value = _value*10 + (*pStr - '0'); _strData[iCount++] = *pStr; pStr++; } _strData.resize(iCount); if (cSymbol == '-') _value = 0 - _value; } bool BigData::IsINT64Overflow() const { std::string temp("+9223372036854775807"); if (_strData[0] == '-') temp = "-9223372036854775808"; if (_strData.size() < temp.size()) return false; else if (_strData.size() == temp.size() && _strData <= temp) return false; return true; } void BigData::INT64ToString() { //處理符號位 char cSymbol = '+'; if (_value < 0) cSymbol = '-'; INT64 temp = _value; while (temp) { if (cSymbol == '+') _strData.append(1, temp%10 + '0'); else _strData.append(1, -(temp%10) + '0'); temp /= 10; } _strData.append(1, cSymbol); std::reverse(_strData.begin(), _strData.end()); } bool BigData::IsLeftStrBig(const char* pLeft, int LSize, const char* pRight, int RSize) { assert(pLeft != NULL && pRight != NULL); if ((LSize > RSize) || (LSize == RSize && strcmp(pLeft, pRight) >= 0)) return true; else return false; } char BigData::SubLoop(char* pLeft, int LSize, char* pRight, int RSize) { assert(pLeft != NULL && pRight != NULL); char cRet = '0'; while (true) { if (!IsLeftStrBig(pLeft, LSize, pRight, RSize)) break; int iLIdx = LSize - 1; int iRIdx = RSize - 1; while (iLIdx >= 0 && iRIdx >= 0) { char ret = pLeft[iLIdx] - '0'; ret -= pRight[iRIdx] - '0'; if (ret < 0) { pLeft[iLIdx - 1] -= 1; ret += 10; } pLeft[iLIdx] = ret + '0'; iLIdx--; iRIdx--; } while (*pLeft == '0' && LSize > 0) { pLeft++; LSize--; } cRet++; } return cRet; } std::ostream& operator<<(std::ostream& _cout, const BigData& bigdata) { if (!bigdata.IsINT64Overflow()) //_value沒有溢出 { _cout<<bigdata._value; } else //_value溢出 { char* pData = (char*)bigdata._strData.c_str(); if ('+' == pData[0]) pData++; _cout<<pData; } return _cout; } BigData BigData::operator+(const BigData& bigdata) { if (!IsINT64Overflow() && !bigdata.IsINT64Overflow()) //兩個數都沒有溢出 { if (_strData[0] != bigdata._strData[0]) //兩個數異號 { return BigData(_value + bigdata._value); } else //兩個數同號 { if ((_value >= 0 && bigdata._value <= MAX_INT64 - _value) || (_value < 0 && bigdata._value >= MIN_INT64 - _value)) //相加后的和沒有溢出 return BigData(_value + bigdata._value); } } //兩個數至少有一個溢出 //相加后的和溢出 if (_strData[0] == bigdata._strData[0]) //同號相加,調用加法 return BigData(Add(_strData, bigdata._strData).c_str()); else //異號相加,調用減法 return BigData(Sub(_strData, bigdata._strData).c_str()); } BigData BigData::operator-(const BigData& bigdata) { if (!IsINT64Overflow() && !bigdata.IsINT64Overflow()) //兩個數都沒有溢出 { if (_strData[0] == bigdata._strData[0])//同號 { return BigData(_value - bigdata._value); } else //異號 { if ((_value >= 0 && MAX_INT64 + bigdata._value >= _value) || (_value < 0 && MIN_INT64 + bigdata._value <= _value)) //結果沒有溢出 return BigData(_value - bigdata._value); } } //至少有一個數溢出或結果溢出 if (_strData[0] != bigdata._strData[0]) //異號相減,調用加法 return BigData(Add(_strData, bigdata._strData).c_str()); else //同號相減,調用減法 return BigData(Sub(_strData, bigdata._strData).c_str()); } BigData BigData::operator*(const BigData& bigdata) { if (!IsINT64Overflow() && !bigdata.IsINT64Overflow()) //都沒有溢出 { if (_value == 0 || bigdata._value == 0) { return BigData((INT64)0); } if (_strData[0] == bigdata._strData[0]) //同號,積為正 { if ((_value > 0 && MAX_INT64/_value >= bigdata._value) || (_value < 0 && MAX_INT64/_value <= bigdata._value)) //積沒有溢出 { return BigData(_value * bigdata._value); } } else //異號,積為負 { if ((_value > 0 && MIN_INT64/_value <= bigdata._value) || (_value < 0 && MIN_INT64/_value >= bigdata._value)) //積沒有溢出 { return BigData(_value * bigdata._value); } } } return BigData(Mul(_strData, bigdata._strData).c_str()); } BigData BigData::operator/(const BigData& bigdata) { //除數不能為0 if ('0' == bigdata._strData[1]) assert(false); // 都沒溢出 if (!IsINT64Overflow() && !bigdata.IsINT64Overflow()) return BigData(_value / bigdata._value); // 至少有一個溢出 //除數 == ±1 if (bigdata._strData == "+1" && bigdata._strData == "-1") { std::string strRet = _strData; if (_strData[0] != bigdata._strData[0]) strRet[0] = '-'; return BigData(strRet.c_str()); } //左 < 右 if ( (_strData.size() < bigdata._strData.size()) || (_strData.size() == bigdata._strData.size() && strcmp(_strData.c_str()+1, bigdata._strData.c_str()+1) < 0) ) return BigData(INT64(0)); //左 == 右 if (strcmp(_strData.c_str()+1, bigdata._strData.c_str()+1) == 0) //左==右 { std::string strRet = "+1"; if (_strData[0] != bigdata._strData[0]) strRet[0] = '-'; else return BigData(strRet.c_str()); } //左 > 右 return BigData(Div(_strData, bigdata._strData).c_str()); } std::string BigData::Add(std::string left, std::string right) { //讓left保存位數大的數 int iLeftSize = left.size(); int iRightSize = right.size(); if (iLeftSize < iRightSize) { std::swap(left, right); std::swap(iLeftSize, iRightSize); } //相加 std::string strRet; strRet.resize(iLeftSize + 1); strRet[0] = left[0]; //符號位 char Step = 0; //進位 for (int iIdx = 1; iIdx < iLeftSize; ++iIdx) { char cRet = left[iLeftSize - iIdx] - '0' + Step; if (iIdx < iRightSize) cRet += right[iRightSize - iIdx] - '0'; strRet[iLeftSize - iIdx + 1] = cRet % 10 + '0'; Step = cRet / 10; } strRet[1] = Step + '0'; return strRet; } std::string BigData::Sub(std::string left, std::string right) { int iLeftSize = left.size(); int iRightSize = right.size(); char cSymbol = left[0]; //差的符號位 if ((iLeftSize < iRightSize) || (iLeftSize == iRightSize && left < right)) { std::swap(left, right); std::swap(iLeftSize, iRightSize); if (cSymbol == '+') cSymbol = '-'; else cSymbol = '+'; } //相減 std::string strRet; //保存差 strRet.resize(left.size()); //先設置和左操作數一樣大的空間 strRet[0] = cSymbol; //符號位 for (int Idx = 1; Idx < iLeftSize; ++Idx) { char cRet = left[iLeftSize - Idx] - '0'; if (Idx < iRightSize) cRet -= (right[iRightSize - Idx] - '0'); if (cRet < 0) //有借位 { left[iLeftSize - Idx - 1] -= 1; cRet += 10; } strRet[iLeftSize - Idx] = cRet + '0'; } return strRet; } std::string BigData::Mul(std::string left, std::string right) { //確定符號位 char cSymbol = '+'; if (left[0] != right[0]) cSymbol = '-'; //使左操作數位數小于右操作數位數 int iLeftSize = left.size(); int iRightSize = right.size(); if (iLeftSize > iRightSize) { std::swap(left, right); std::swap(iLeftSize, iRightSize); } std::string strRet; //strRet.resize(iLeftSize+iRightSize-1); strRet.assign(iLeftSize+iRightSize-1, '0'); strRet[0] = cSymbol; int iRetLen = strRet.size(); int iOffset = 0; //偏移 for (int iLeftIndex = 1; iLeftIndex < iLeftSize; ++iLeftIndex) { char cLeft = left[iLeftSize - iLeftIndex] - '0'; if (cLeft == 0) //當左操作數中有0時,直接左移,不計算 { ++iOffset; continue; } char cStep = 0; for (int iRightIndex = 1; iRightIndex < iRightSize; ++iRightIndex) { char cRet = cLeft*(right[iRightSize - iRightIndex] - '0') + cStep; cRet += strRet[iRetLen - iRightIndex - iOffset] - '0'; strRet[iRetLen - iRightIndex - iOffset] = (cRet%10) + '0'; cStep = cRet/10; } strRet[iRetLen-iRightSize -iOffset] += cStep; ++iOffset; } return strRet; } std::string BigData::Div(std::string left, std::string right) { std::string strRet; //確定符號位 strRet.append(1, '+'); if (left[0] != right[0]) strRet[0] = '-'; char* pLeft = (char*)(left.c_str()+1); char* pRight = (char*)(right.c_str()+1); int iLSize = left.size()-1; //被除數長度 int iDataLen = right.size()-1; //取iDataLen位被除數 int iIdx = 0; //iIdx和pLeft同步走,用來判斷是否走到被除數結尾 while (iIdx < iLSize) { if (*pLeft == '0') { strRet.append(1, '0'); pLeft++; iIdx++; continue; } if (!IsLeftStrBig(pLeft, iDataLen, pRight, right.size()-1)) //取的iDataLen位被除數 < 除數 { strRet.append(1, '0'); iDataLen++; if (iDataLen + iIdx > iLSize) break; } else { //循環相減 strRet.append(1, SubLoop(pLeft, iDataLen, pRight, right.size()-1)); while (*pLeft == '0') { pLeft++; iIdx++; iDataLen--; } iDataLen++; } } return strRet; }
BigDataTest.cpp
#include <iostream> using namespace std; #include "BigData.h" void AddTest() { //BigData b1("12345678"); //BigData b2("12345qwe"); //BigData b3("+"); //BigData b4("00001234"); //BigData b5(" "); //BigData b6("99999999999999999999999999999999999999999999999999999999"); //BigData b7 ("-123213"); //cout<<b1<<endl; //cout<<b2<<endl; //cout<<b3<<endl; //cout<<b4<<endl; //cout<<b5<<endl; //cout<<b6<<endl; //cout<<b7<<endl; //BigData left1(1234); //BigData right1(4321); //cout<<left1+right1<<endl; //BigData left2(9223372036854775807); //BigData right2(3); //cout<<left2+right2<<endl; //BigData left3(-9223372036854775808); //BigData right3(-3); //cout<<left3+right3<<endl; //BigData left3("99999999999999999999999999999999999"); //BigData right3("11111111111111111111111111111111111"); //cout<<left3+right3<<endl; } void SubTest() { //BigData left("1111111111111111111111111111111100"); //BigData right("99"); //cout<<left-right<<endl; //BigData left1("-2222222222222222222222222222222222222222"); //BigData right1("22222"); //cout<<left1+right1<<endl; } void MulTest() { //BigData left("77777777777777777777777777777777777777777777777777777777777"); //BigData right("66"); //cout<<left*right<<endl; //BigData left1("99"); //BigData right1("9999999999999999999999999999999999999999999"); //cout<<left1*right1<<endl; //BigData left2("11111111111111111111111111111111111111111111111111111111111111111"); //BigData right2("-99"); //cout<<left2*right2<<endl; //BigData left3("-8"); //BigData right3("66"); //cout<<left3*right3<<endl; //BigData left4("10001"); //BigData right4("666666666666666666666666666666666666"); //cout<<left4*right4<<endl; } void DivTest() { //BigData left("222222222222222222222222222222222222222222222222"); //BigData right("33"); //cout<<left/right<<endl; //BigData left1("-222222222222222222222222222222222222222222222222"); //BigData right1("33"); //cout<<left1/right1<<endl; //BigData left3("33333333333333333333333333333333333333333333333333333"); //BigData right3("0"); //cout<<left3/right3<<endl; //BigData left4("111"); //BigData right4("222222222222222222222222222222222222222222222222"); //cout<<left4/right4<<endl; //BigData left5("11111111111111111111111111111111111111111111111111"); //BigData right5("-11111111111111111111111111111111111111111111111111"); //cout<<left5/right5<<endl; } void PrintMenu() { cout<<"------------------------------------------------------------------------"<<endl; cout<<"| 大 數 計 算 器 |"<<endl; cout<<"------------------------------------------------------------------------"<<endl; cout<<"請輸入:"; } void Demo() { while (true) { PrintMenu(); string input; cin>>input; if (input == "quit") { break; } if (input.find('+') != -1) { string left = input.substr(0, input.find('+')); string right = input.substr(input.find('+')+1, input.length()-1); BigData bigdata1(left.c_str()); BigData bigdata2(right.c_str()); cout<<"結果: "<<bigdata1+bigdata2<<endl; continue; } if (input.find('-') != -1) { string left = input.substr(0, input.find('-')); string right = input.substr(input.find('-')+1, input.length()-1); BigData bigdata1(left.c_str()); BigData bigdata2(right.c_str()); cout<<"結果: "<<bigdata1-bigdata2<<endl; continue; } if (input.find('*') != -1) { string left = input.substr(0, input.find('*')); string right = input.substr(input.find('*')+1, input.length()-1); BigData bigdata1(left.c_str()); BigData bigdata2(right.c_str()); cout<<"結果: "<<bigdata1*bigdata2<<endl; continue; } if (input.find('/') != -1) { string left = input.substr(0, input.find('/')); string right = input.substr(input.find('/')+1, input.length()-1); BigData bigdata1(left.c_str()); BigData bigdata2(right.c_str()); cout<<"結果: "<<bigdata1/bigdata2<<endl; continue; } } } int main() { //AddTest(); //SubTest(); //MulTest(); //DivTest(); Demo(); return 0; }
下面是一個簡單的測試:
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。