大數運算的實現方法主要有以下幾種:
1) 用字符串表示大數。將大數用十進制字符數組表示,然後按照“豎式計算”的思想進行計算。這種方法比較容易理解,但是計算效率比較低。
2) 將大數看成二進制流進行處理。使用各種位運算和邏輯操作來實現打算的運算。該方法設計複雜,可讀性較差,而且難以調試。
3) 將大數表示成一個n進制數組。n的取值越大,數組的大小越小,這樣可以縮短運算的時間及空間複雜度,提高算法的效率。在32位系統中,n可以取2^32,這時每一位的取值範圍是0~0xffffffff。
下面就針對第1)種方法進行描述與實現:
1、構造函數
1>定義全局變量:
typedef long long INT64; //對long long進行重命名
const INT64 INVALID = 0xcccccccccccccccc; //隨機值
const INT64 MAX = 9223372036854775807; //最大值(0x7FFFFFFFFFFFFFFF)
const INT64 MIN = -9223372036854775808; //最小值(0x8000000000000000)
2>定義類的成員變量
class BigData
{
private:
string _pData;
INT64 _value;
};
3>判斷數據溢出函數
bool IsOverFlow()//判斷數據是否溢出
{
//先求當前字符串的長度
int len = _pData.size();
//與INT64的最大值與最小值的長度作比較,如果大於MAX和MIN的長度,說明溢出
if (len > 21)//"+9223372036854775807\0" "-9223372036854775808\0"(21位)
{
return true;
}
else if (len < 21)//如果大於MAX和MIN的長度,說明溢出
{
return false;
}
else//如果等於MAX和MIN的長度,則需要繼續判斷
{
if (_pData[0] == '+' && strcmp(_pData.c_str(),"+9223372036854775807")>0)
return true;
if (_pData[0] == '-' && strcmp(_pData.c_str(),"-9223372036854775808")>0)
return true;
return false;
}
}
4>無參的構造函數
BigData()//無參構造函數
:_pData("")
,_value(INVALID)
{}
5>給一個不溢出的整數作爲參數的構造函數
BigData(INT64 value)//給一個整數串的構造函數(注意要保證MIN<value<MAX,否則會出錯)
{
if(value==0)
{
_pData.resize(3);
_pData[0] = '+';//默認0是正的
_pData[1] = '0';
_pData[2] = '\0';
return;
}
_value = value;
char count = 0;//統計所給整數的位數
INT64 tmp = value;//給出臨時變量tmp做計算
//統計所給整數有多少位
while(tmp)
{
++count;
tmp /= 10;
}
_pData.resize(count+2);//給符號和'\0'多開闢倆個字節
//確認符號
if (value > 0)
_pData[0] = '+';
else
_pData[0] = '-';
//從後向前給字符數組賦值
tmp = value;
if (tmp < 0)
tmp = 0 - tmp;//如果tmp是負數,將其改爲正數
for (int i = count; i > 0; --i)
{
char c = tmp%10 + '0';//取最低位
_pData[i] = c;
tmp /= 10;
}
}
6>字符串做參數的構造參數(需考慮異常情況)
BigData(const char* s)//用字符串構造大數的構造函數
:_value(0)
{
int len = strlen(s);//求所給字符串的長度
_pData.resize(len+2,0);//爲符號位和'\0'多開闢兩個空間
char sign = '+';//默認符號爲正
char* str = (char*)s;//用一個字符串指向s
size_t size = 0;//記錄實際有效的字符串個數
//跳過前面的'0'和' '(比如"00003526727" " 6767867")
while(*str == '0' || *str == ' ')
++str;
//預防"000000" 和 " "
if (*str == '\0')
{
_value = 0;
_pData[0] = sign;//默認0爲正
_pData[1] = '0';
_pData.resize(3);//'+' '0' '\0'
return;
}
//確認符號
if (str[0] == '-' || str[0] == '+')
{
sign = *str++;
}
//預防"+000006458" "- 648"
while(*str == '0' || *str == ' ')
++str;
//預防"+000000" 和 "- "
if (*str == '\0')
{
_value = 0;
_pData[0] = sign;
_pData[1] = '0';
_pData.resize(3);
return;
}
//從第1位開始賦值,第0位放符號位
for (int i = 1; i <= len; ++i)
{
//只有遇到數字字符才向字符數組和_value中賦值
if(*str >= '0' && *str <= '9')
{
_value = _value*10 + (*str - '0');
_pData[i] = *str;
++size;
str++;
}
else
{
if(i == 1)//處理"abc2654738"
_pData[i] = '0';
break;
}
}
_pData[0] = sign;//將0號位置賦值爲符號位
_pData.resize(size+2);//重置大小
//確定_value的符號
if (sign == '-')
_value = 0 - _value;
}
7>構造函數的測試代碼及結果
測試代碼:
void Test1() //構造函數的測試
{
cout<<BigData()<<endl;
cout<<BigData(25643787278947)<<endl;
cout<<BigData("123456789\0")<<endl;
cout<<BigData(" +000123456789")<<endl;
cout<<BigData("000+0000")<<endl;
cout<<BigData("000- 123456789")<<endl;
cout<<BigData("000+000abc123456789")<<endl;
cout<<BigData("000-000123456789abc123456789")<<endl;
}
運行結果:
2、加法函數
1>加法函數的整體邏輯
2>加法重載:operator+
BigData operator+(BigData& bd)
{
BigData* l = this;//左操作數
BigData* r = &bd;//右操作數
int lSize = l->_pData.size();
int rSize = r->_pData.size();
//將較長的數放於左操作數
if (lSize < rSize)
{
swap(l,r);
swap(lSize,rSize);
}
//如果兩個數據長度一樣,就將(除符號)大的數放於左操作數
if (lSize == rSize)
{
if (strcmp(l->_pData.c_str()+1,r->_pData.c_str()+1) < 0)
{
swap(l,r);
swap(lSize,rSize);
}
}
//兩個數據同號(結果與數據符號相同)
if (l->_pData[0] == r->_pData[0])
{
//兩個數據至少有一個溢出了
if (l->IsOverFlow() || r->IsOverFlow())
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
//兩個數據都沒溢出,但結果有可能溢出
else
{
//同號正溢出:結果溢出了 5 - 2 < 4
if (l->_pData[0] == '+' && MAX - l->_value < r->_value)
{
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
}
//同號負溢出:結果溢出了 -5 - (-3) > -3
else if (l->_pData[0] == '-' && MIN - l->_value > r->_value)
{
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
}
//兩個數據都沒有溢出,和也沒有溢出
else
{
//直接相加兩個數據,然後構造臨時對象返回
return BigData(l->_value+r->_value);
}
}
}
//兩個數據異號(結果的符號爲數據較大的數據的符號,即左操作數)
else
{
//兩個數據都沒溢出,結果肯定沒溢出
if (!l->IsOverFlow() && !r->IsOverFlow())
{
//直接相加兩個數據,然後構造臨時對象返回
return BigData(l->_value+r->_value);
}
//兩個數據至少有一個溢出了
else
{
return BigData(l->SUB(r->_pData).c_str());//如果有溢出,調用字符串相減函數
}
}
}
3>自擬字符串加法:ADD()
char step = 0;//進位
char cRet = 0;
for (int i = 2; i < lSize; ++i)
{
//右操作數的位數還沒加完,左+右+進位
if (rSize-i > 0)
{
cRet = _pData[lSize-i] - '0' + s[rSize-i] -'0'+ step;
}
//右操作數加完後,左+進位
else
{
cRet = _pData[lSize-i] - '0' + step;
}
step = cRet/10;
cRet = cRet%10;
ret[lSize+1-i] = cRet + '0';
}
ret[0] = _pData[0]; //確定符號位
ret[1] = step+'0'; //保存最後一個進位
return ret;
}
4>加法函數的測試用例
(異號測試)
//BigData bd1("-9999");
//BigData bd2("+1234567");
//cout<<bd1 + bd2<<endl;//異號都沒溢出----結果沒溢出
//BigData bd3("-99999999999999999999999999999999999999");
//BigData bd4("+11111111111111111111111111111111111111");
//cout<<bd3 + bd4<<endl;//異號都溢出了----結果溢出
//BigData bd5("-9999999999999999999999999999999");
//BigData bd6("1000");
//cout<<bd5 + bd6<<endl;//異號負數溢出----結果負溢出
//BigData bd7("-1000");
//BigData bd8("+9999999999999999999999999999999");
//cout<<bd7 + bd8<<endl;//異號正數溢出----結果正溢出
//BigData bd9(" -1111111111111111111111111111111");
//BigData bd10("+9999999999999999999999999999999");
//cout<<bd9 + bd10<<endl;//異號正數溢出----結果正溢出
}
5>運行結果
同號:
異號:
3、減法函數
1>減法函數的整體邏輯
2>減法重載:operator-
BigData operator-(BigData& bd)
{
BigData* l = this;//左操作數
BigData* r = &bd;//右操作數
int lSize = l->_pData.size();
int rSize = r->_pData.size();
//將較長的數放於左操作數
if (lSize < rSize)
{
swap(l,r);
swap(lSize,rSize);
}
//如果兩個數據長度一樣,就將(除符號)大的數放於左操作數
if (lSize == rSize)
{
if (strcmp(l->_pData.c_str()+1,r->_pData.c_str()+1) < 0)
{
swap(l,r);
swap(lSize,rSize);
}
}
//兩個數據同號
if (l->_pData[0] == r->_pData[0])
{
//兩個數據都沒溢出,結果肯定也沒溢出
if (!l->IsOverFlow() && !r->IsOverFlow())
{
//直接相減兩個數據,然後構造臨時對象返回
return BigData(l->_value - r->_value);
}
//兩個數據至少有一個溢出了,調用字符串相減函數
else
{
return BigData(l->SUB(r->_pData).c_str());
}
}
//兩個數據異號
else
{
//兩個數據至少有一個溢出了,直接調用字符串相加函數
if (l->IsOverFlow() || r->IsOverFlow())
{
return BigData(l->ADD(r->_pData).c_str());
}
//兩個數據都沒有溢出,結果有可能溢出也有可能不溢出
else
{
//異號正溢出:結果溢出了 5 - 2 < 4
if (l->_pData[0] == '+' && MAX - l->_value < r->_value)
{
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
}
//異號負溢出:結果溢出了 -5 - (-3) > -3
else if (l->_pData[0] == '-' && MIN - l->_value > r->_value)
{
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
}
//兩個數據都沒有溢出,和也沒有溢出
else
{
//直接相減兩個數據,然後構造臨時對象返回
return BigData(l->_value-r->_value);
}
}
}
}
3>自擬字符串減法:SUB()
string SUB(string& s)//字符串減法
{
int lSize = _pData.size();
int rSize = s.size();
string ret;//定義返回值
ret.resize(lSize+1);//99999-(-99)=100098(位數最多爲左操作數+1個)
char step = 0;//借位
char cRet = 0;
for (int i = 2; i < lSize; ++i)
{
//右操作數的位數還沒減完,左-右-借位
if (rSize-i > 0)
{
cRet = (_pData[lSize-i]-'0') - (s[rSize-i]-'0') - step;
step = 0;
}
//右操作數減完後,左-借位
else
{
cRet = _pData[lSize-i] - '0' - step;
step = 0;
}
if(cRet < 0)//不夠減就進行借位
{
cRet += 10;//當前0位+10
step = 1;//向前面借一位
}
ret[lSize+1-i] = cRet + '0';
}
ret[0] = _pData[0]; //確定符號位
ret[1] = step+'0'; //保存最後一個借位
return ret;
}
4>減法函數的測試用例
void Test3()//減法測試
{
////(同號測試)
//BigData bd1("+999999999");
//BigData bd2("+1234567");
//cout<<bd1 - bd2<<endl;//同號都沒溢出----結果沒溢出
//BigData bd3("99999999999999999999999999999999999999");
//BigData bd4("11111111111111111111111111111111111111");
//cout<<bd3 - bd4<<endl;//同號都溢出了----結果溢出
//BigData bd5("777777777777777777777777777");
//BigData bd6("1000");
//cout<<bd5 - bd6<<endl;//同號正數溢出----結果沒溢出
//BigData bd7("-1000");
//BigData bd8("-88888888888888888888888888888888");
//cout<<bd7 + bd8<<endl;//同號負數溢出----結果溢出
//(異號測試)
BigData bd1("-9999");
BigData bd2("+1234567");
cout<<bd1 - bd2<<endl;//異號都沒溢出----結果沒溢出
BigData bd3("-99999999999999999999999999999999999999");
BigData bd4("+11111111111111111111111111111111111111");
cout<<bd3 - bd4<<endl;//異號都溢出了----結果溢出
BigData bd5("-9999999999999999999999999999999");
BigData bd6("1000");
cout<<bd5 - bd6<<endl;//異號負數溢出----結果負溢出
BigData bd7("-1000");
BigData bd8("+9999999999999999999999999999999");
cout<<bd7 - bd8<<endl;//異號正數溢出----結果正溢出
BigData bd9(" -1111111111111111111111111111111");
BigData bd10("+9999999999999999999999999999999");
cout<<bd9 - bd10<<endl;//異號都溢出了----結果溢出
}
5>運行結果
同號:
異號:
4、乘法函數
1>乘法函數的整體邏輯
2>重載乘法:operator*
BigData operator*(BigData& bd)
{
BigData* l = this;//左操作數
BigData* r = &bd;//右操作數
int lSize = l->_pData.size();
int rSize = r->_pData.size();
//將較長的數放於左操作數
if (lSize < rSize)
{
swap(l,r);
swap(lSize,rSize);
}
//兩個數據同號,運算結果符號爲正
if (l->_pData[0] == r->_pData[0])
{
//至少有一個數據溢出,調用字符串乘法函數
if (l->IsOverFlow() || r->IsOverFlow())
{
return BigData(l->MUL(r->_pData).c_str());
}
//兩個數據都沒溢出,結果可能溢出也可能不溢出
else
{
//正溢出:結果溢出了 5 / 2 < 4
if (MAX / l->_value < r->_value)
{
return BigData(l->MUL(r->_pData).c_str());//如果有溢出,調用字符串相乘函數
}
//兩個數據都沒有溢出,積也沒有溢出
else
{
//直接相乘兩個數據,然後構造臨時對象返回
return BigData(l->_value*r->_value);
}
}
}
//兩個數據異號,運算結果爲負
else
{
//至少有一個數據溢出,調用字符串乘法函數
if (l->IsOverFlow() || r->IsOverFlow())
{
return BigData(l->MUL(r->_pData).c_str());
}
//兩個數據都沒溢出,結果可能溢出也可能不溢出
else
{
//負溢出:結果溢出了 -5 / (-3) > 3
if (MIN / l->_value > r->_value)
{
return BigData(l->MUL(r->_pData).c_str());//如果有溢出,調用字符串相乘函數
}
//兩個數據都沒有溢出,和也沒有溢出
else
{
//直接相乘兩個數據,然後構造臨時對象返回
return BigData(l->_value*r->_value);
}
}
}
}
3>自擬字符串乘法:MUL()
string MUL(string& s)
{
int lSize = _pData.size();
int rSize = s.size();
string ret;//定義返回值
//結果最多爲lSize+rSize-2位 "+9999\0" * "+99\0" = "+989901\0"
ret.resize(lSize+rSize-2);
char step = 0;//進位
char count = 0;//錯位
char cRet = 0;
for (int i = 2; i < rSize; ++i)//右操作數比較短,應放於外層循環
{
step = 0;
for (int j = 2; j < lSize; ++j)//左操作數比較長,應放在內層循環
{
cRet = (s[rSize-i]-'0') * (_pData[lSize-j]-'0') + step;
if(count > 0)
cRet += ret[lSize+rSize-2-j-count] - '0';
step = cRet/10;
cRet %= 10;
ret[lSize+rSize-2-j-count] = cRet + '0';
}
count++;//每次向前錯一位
ret[rSize-1-count] += step + '0';//保存最後一個進位
}
//確定結果的符號:同號爲正,異號爲負
if (_pData[0] == s[0])
ret[0] = '+';
else
ret[0] = '-';
return ret;
}
4>乘法的測試用例
void Test4()//乘法測試
{
//(同號測試)
BigData bd1("+999999999");
BigData bd2("+111111");
cout<<bd1 * bd2<<endl;//同號都沒溢出----結果沒溢出
BigData bd3("-99999999999999999999999999999999999999");
BigData bd4("-11111111111111111111111111111111111111");
cout<<bd3 * bd4<<endl;//同號都溢出了----結果溢出
BigData bd5("9999999999999");
BigData bd6("9999999999999");
cout<<bd5 * bd6<<endl;//同號都沒溢出----結果正溢出
//異號測試
BigData bd7("-1000");
BigData bd8("7654321");
cout<<bd7 * bd8<<endl;//異號都沒溢出----結果沒溢出
BigData bd9("-9999999999999999999999999999");
BigData bd10("+1000000000");
cout<<bd9 * bd10<<endl;//異號溢出了----結果負溢出
BigData bd11("9999999999999");
BigData bd12("-9999999999999");
cout<<bd11 * bd12<<endl;//同號都沒溢出----結果負溢出
}
5>運行結果
5、除法函數
1>除法函數的整體邏輯
2>重載除法:operator/
BigData operator/(BigData& bd)
{
if(strcmp(bd._pData.c_str()+1,"0")==0)//防止除數爲0
assert(false);
int lSize = _pData.size();
int rSize = bd._pData.size();
//左操作數小於右操作數或者被除數爲0,結果爲0
if (lSize < rSize || strcmp(_pData.c_str()+1,"0")==0)
return BigData((INT64)0);
//兩個數據絕對值相等,結果爲1或-1
else if (lSize == rSize && strcmp(_pData.c_str()+1,bd._pData.c_str()+1)==0)
{
if(_pData[0] != bd._pData[0])
return BigData((INT64)-1);
else
return BigData((INT64)1);
}
//右操作數爲+1或-1,結果爲 +左操作數 或 -左操作數
else if (rSize == 3 && bd._pData[1] == '1')
{
if(bd._pData[0] == '+')
{
return BigData(_pData.c_str());
}
else
{
string tmp = _pData;
tmp[0] = '-';
return BigData(tmp.c_str());
}
}
else
{
//至少有一個數據溢出
if (IsOverFlow() || bd.IsOverFlow())
{
return BigData(DIV(bd._pData).c_str());
}
//兩個數據都沒溢出,結果也沒溢出
else
{
return BigData(_value/bd._value);
}
}
}
3>自擬字符串除法:DIV()
string DIV(string& s)
{
int lSize = _pData.size();
int rSize = s.size();
string ret;//定義返回值
//結果最多爲lSize位 "+9999\0" * "+1\0" = "+9999\0"
ret.reserve(lSize);
string sleft(_pData.c_str(),rSize-1);//被除數
string sright(s.c_str(),rSize-1);//除數
int index = rSize-1;
while(index < lSize)
{
//不夠除
while (sleft.size()==sright.size() && strcmp(sleft.c_str(),sright.c_str())<0)
{
sleft += _pData[index++];//借位
ret.push_back('0');
if (index > lSize)
break;
}
//夠除
int count = 0;
while(sleft.size()>sright.size() ||\
(sleft.size()==sright.size()&&strcmp(sleft.c_str(),sright.c_str())>0))
{
BigData tmp(sleft.c_str());
sleft = tmp.SUB(BigData(sright.c_str())._pData);
++count;
sleft = BigData(sleft.c_str())._pData;//去掉多餘的0
sleft = string(sleft.c_str(),sleft.size()-1);//去掉後面的'\0'
}
ret.push_back(count+'0');
sleft += _pData[index++];//借位
}
//確定結果的符號:同號爲正,異號爲負
if (_pData[0] == s[0])
ret[0] = '+';
else
ret[0] = '-';
return ret;
}
4>除法函數的測試用例
void Test5()//測試除法
{
BigData bd1("+999999999");
BigData bd2("+11111111111111");
cout<<bd1 / bd2<<endl;//左操作數小於有操作數----結果爲0
BigData bd3("0");
BigData bd4("-11111111111111111");
cout<<bd3 / bd4<<endl;//左操作數--是0--結果爲0
BigData bd5("9999999999999");
BigData bd6("9999999999999");
cout<<bd5 / bd6<<endl;//同號且絕對值相等----結果爲1
BigData bd7("-9999999999999");
BigData bd8("9999999999999");
cout<<bd7 / bd8<<endl;//異號且絕對值相等----結果爲-1
BigData bd9("-9999999999999999999999999999");
BigData bd10("+1");
cout<<bd9 / bd10<<endl;//右操作數爲1---結果爲左操作數
BigData bd11("9999999999999");
BigData bd12("-1");
cout<<bd11 / bd12<<endl;//右操作數爲-1---結果爲 -左操作數
BigData bd13("-9999999999999999999999999999");
BigData bd14("+100000000");
cout<<bd13 / bd14<<endl;//異號且至少有一個溢出
BigData bd15("9999999999999");
BigData bd16("100000");
cout<<bd15 / bd16<<endl;//同號且都沒有溢出
}
5>運行結果
6、完整代碼
算法實現:
#pragma once
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
typedef long long INT64; //對long long進行重命名
const INT64 INVALID = 0xcccccccccccccccc; //隨機值
const INT64 MAX = 9223372036854775807; //最大值(0x7FFFFFFFFFFFFFFF)
const INT64 MIN = -9223372036854775808; //最小值(0x8000000000000000)
class BigData
{
public:
friend ostream& operator<<(ostream& _cout,const BigData& bd);
BigData()//無參構造函數
:_pData("")
,_value(INVALID)
{}
BigData(INT64 value)//給一個整數串的構造函數(注意要保證MIN<value<MAX,否則會出錯)
{
if(value==0)
{
_pData.resize(3);
_pData[0] = '+';//默認0是正的
_pData[1] = '0';
_pData[2] = '\0';
return;
}
_value = value;
char count = 0;//統計所給整數的位數
INT64 tmp = value;//給出臨時變量tmp做計算
//統計所給整數有多少位
while(tmp)
{
++count;
tmp /= 10;
}
_pData.resize(count+2);//給符號和'\0'多開闢倆個字節
//確認符號
if (value > 0)
_pData[0] = '+';
else
_pData[0] = '-';
//從後向前給字符數組賦值
tmp = value;
if (tmp < 0)
tmp = 0 - tmp;//如果tmp是負數,將其改爲正數
for (int i = count; i > 0; --i)
{
char c = tmp%10 + '0';//取最低位
_pData[i] = c;
tmp /= 10;
}
}
BigData(const char* s)//用字符串構造大數的構造函數
:_value(0)
{
int len = strlen(s);//求所給字符串的長度
_pData.resize(len+2,0);//爲符號位和'\0'多開闢兩個空間
char sign = '+';//默認符號爲正
char* str = (char*)s;//用一個字符串指向s
size_t size = 0;//記錄實際有效的字符串個數
//跳過前面的'0'和' '(比如"00003526727" " 6767867")
while(*str == '0' || *str == ' ')
++str;
//預防"000000" 和 " "
if (*str == '\0')
{
_value = 0;
_pData[0] = sign;//默認0爲正
_pData[1] = '0';
_pData.resize(3);//'+' '0' '\0'
return;
}
//確認符號
if (str[0] == '-' || str[0] == '+')
{
sign = *str++;
}
//預防"+000006458" "- 648"
while(*str == '0' || *str == ' ')
++str;
//預防"+000000" 和 "- "
if (*str == '\0')
{
_value = 0;
_pData[0] = sign;
_pData[1] = '0';
_pData.resize(3);
return;
}
//從第1位開始賦值,第0位放符號位
for (int i = 1; i <= len; ++i)
{
//只有遇到數字字符才向字符數組和_value中賦值
if(*str >= '0' && *str <= '9')
{
_value = _value*10 + (*str - '0');
_pData[i] = *str;
++size;
str++;
}
else
{
if(i == 1)//處理"abc2654738"
_pData[i] = '0';
break;
}
}
_pData[0] = sign;//將0號位置賦值爲符號位
_pData.resize(size+2);//重置大小
//確定_value的符號
if (sign == '-')
_value = 0 - _value;
}
BigData operator+(BigData& bd)
{
BigData* l = this;//左操作數
BigData* r = &bd;//右操作數
int lSize = l->_pData.size();
int rSize = r->_pData.size();
//將較長的數放於左操作數
if (lSize < rSize)
{
swap(l,r);
swap(lSize,rSize);
}
//如果兩個數據長度一樣,就將(除符號)大的數放於左操作數
if (lSize == rSize)
{
if (strcmp(l->_pData.c_str()+1,r->_pData.c_str()+1) < 0)
{
swap(l,r);
swap(lSize,rSize);
}
}
//兩個數據同號(結果與數據符號相同)
if (l->_pData[0] == r->_pData[0])
{
//兩個數據至少有一個溢出了
if (l->IsOverFlow() || r->IsOverFlow())
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
//兩個數據都沒溢出,但結果有可能溢出
else
{
//同號正溢出:結果溢出了 5 - 2 < 4
if (l->_pData[0] == '+' && MAX - l->_value < r->_value)
{
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
}
//同號負溢出:結果溢出了 -5 - (-3) > -3
else if (l->_pData[0] == '-' && MIN - l->_value > r->_value)
{
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
}
//兩個數據都沒有溢出,和也沒有溢出
else
{
//直接相加兩個數據,然後構造臨時對象返回
return BigData(l->_value+r->_value);
}
}
}
//兩個數據異號(結果的符號爲數據較大的數據的符號,即左操作數)
else
{
//兩個數據都沒溢出,結果肯定沒溢出
if (!l->IsOverFlow() && !r->IsOverFlow())
{
//直接相加兩個數據,然後構造臨時對象返回
return BigData(l->_value+r->_value);
}
//兩個數據至少有一個溢出了
else
{
return BigData(l->SUB(r->_pData).c_str());//如果有溢出,調用字符串相減函數
}
}
}
BigData operator-(BigData& bd)
{
BigData* l = this;//左操作數
BigData* r = &bd;//右操作數
int lSize = l->_pData.size();
int rSize = r->_pData.size();
//將較長的數放於左操作數
if (lSize < rSize)
{
swap(l,r);
swap(lSize,rSize);
}
//如果兩個數據長度一樣,就將(除符號)大的數放於左操作數
if (lSize == rSize)
{
if (strcmp(l->_pData.c_str()+1,r->_pData.c_str()+1) < 0)
{
swap(l,r);
swap(lSize,rSize);
}
}
//兩個數據同號
if (l->_pData[0] == r->_pData[0])
{
//兩個數據都沒溢出,結果肯定也沒溢出
if (!l->IsOverFlow() && !r->IsOverFlow())
{
//直接相減兩個數據,然後構造臨時對象返回
return BigData(l->_value - r->_value);
}
//兩個數據至少有一個溢出了,調用字符串相減函數
else
{
return BigData(l->SUB(r->_pData).c_str());
}
}
//兩個數據異號
else
{
//兩個數據至少有一個溢出了,直接調用字符串相加函數
if (l->IsOverFlow() || r->IsOverFlow())
{
return BigData(l->ADD(r->_pData).c_str());
}
//兩個數據都沒有溢出,結果有可能溢出也有可能不溢出
else
{
//異號正溢出:結果溢出了 5 - 2 < 4
if (l->_pData[0] == '+' && MAX - l->_value < r->_value)
{
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
}
//異號負溢出:結果溢出了 -5 - (-3) > -3
else if (l->_pData[0] == '-' && MIN - l->_value > r->_value)
{
return BigData(l->ADD(r->_pData).c_str());//如果有溢出,調用字符串相加函數
}
//兩個數據都沒有溢出,和也沒有溢出
else
{
//直接相減兩個數據,然後構造臨時對象返回
return BigData(l->_value-r->_value);
}
}
}
}
BigData operator*(BigData& bd)
{
BigData* l = this;//左操作數
BigData* r = &bd;//右操作數
int lSize = l->_pData.size();
int rSize = r->_pData.size();
//將較長的數放於左操作數
if (lSize < rSize)
{
swap(l,r);
swap(lSize,rSize);
}
//兩個數據同號,運算結果符號爲正
if (l->_pData[0] == r->_pData[0])
{
//至少有一個數據溢出,調用字符串乘法函數
if (l->IsOverFlow() || r->IsOverFlow())
{
return BigData(l->MUL(r->_pData).c_str());
}
//兩個數據都沒溢出,結果可能溢出也可能不溢出
else
{
//正溢出:結果溢出了 5 / 2 < 4
if (MAX / l->_value < r->_value)
{
return BigData(l->MUL(r->_pData).c_str());//如果有溢出,調用字符串相乘函數
}
//兩個數據都沒有溢出,積也沒有溢出
else
{
//直接相乘兩個數據,然後構造臨時對象返回
return BigData(l->_value*r->_value);
}
}
}
//兩個數據異號,運算結果爲負
else
{
//至少有一個數據溢出,調用字符串乘法函數
if (l->IsOverFlow() || r->IsOverFlow())
{
return BigData(l->MUL(r->_pData).c_str());
}
//兩個數據都沒溢出,結果可能溢出也可能不溢出
else
{
//負溢出:結果溢出了 -5 / (-3) > 3
if (MIN / l->_value > r->_value)
{
return BigData(l->MUL(r->_pData).c_str());//如果有溢出,調用字符串相乘函數
}
//兩個數據都沒有溢出,和也沒有溢出
else
{
//直接相乘兩個數據,然後構造臨時對象返回
return BigData(l->_value*r->_value);
}
}
}
}
BigData operator/(BigData& bd)
{
if(strcmp(bd._pData.c_str()+1,"0")==0)//防止除數爲0
assert(false);
int lSize = _pData.size();
int rSize = bd._pData.size();
//左操作數小於右操作數或者被除數爲0,結果爲0
if (lSize < rSize || strcmp(_pData.c_str()+1,"0")==0)
return BigData((INT64)0);
//兩個數據絕對值相等,結果爲1或-1
else if (lSize == rSize && strcmp(_pData.c_str()+1,bd._pData.c_str()+1)==0)
{
if(_pData[0] != bd._pData[0])
return BigData((INT64)-1);
else
return BigData((INT64)1);
}
//右操作數爲+1或-1,結果爲 +左操作數 或 -左操作數
else if (rSize == 3 && bd._pData[1] == '1')
{
if(bd._pData[0] == '+')
{
return BigData(_pData.c_str());
}
else
{
string tmp = _pData;
tmp[0] = '-';
return BigData(tmp.c_str());
}
}
else
{
//至少有一個數據溢出
if (IsOverFlow() || bd.IsOverFlow())
{
return BigData(DIV(bd._pData).c_str());
}
//兩個數據都沒溢出,結果也沒溢出
else
{
return BigData(_value/bd._value);
}
}
}
protected:
bool IsOverFlow()//判斷數據是否溢出
{
//先求當前字符串的長度
int len = _pData.size();
//與INT64的最大值與最小值的長度作比較,如果大於MAX和MIN的長度,說明溢出
if (len > 21)//"+9223372036854775807\0" "-9223372036854775808\0"(21位)
{
return true;
}
else if (len < 21)//如果大於MAX和MIN的長度,說明溢出
{
return false;
}
else//如果等於MAX和MIN的長度,則需要繼續判斷
{
if (_pData[0] == '+' && strcmp(_pData.c_str(),"+9223372036854775807")>0)
return true;
if (_pData[0] == '-' && strcmp(_pData.c_str(),"-9223372036854775808")>0)
return true;
return false;
}
}
string ADD(string& s)//字符串加法
{
int lSize = _pData.size();
int rSize = s.size();
string ret;//定義返回值
ret.resize(lSize+1);//99999+99=100098(位數最多爲左操作數+1)
char step = 0;//進位
char cRet = 0;
for (int i = 2; i < lSize; ++i)
{
//右操作數的位數還沒加完,左+右+進位
if (rSize-i > 0)
{
cRet = _pData[lSize-i] - '0' + s[rSize-i] -'0'+ step;
}
//右操作數加完後,左+進位
else
{
cRet = _pData[lSize-i] - '0' + step;
}
step = cRet/10;
cRet = cRet%10;
ret[lSize+1-i] = cRet + '0';
}
ret[0] = _pData[0]; //確定符號位
ret[1] = step+'0'; //保存最後一個進位
return ret;
}
string SUB(string& s)//字符串減法
{
int lSize = _pData.size();
int rSize = s.size();
string ret;//定義返回值
ret.resize(lSize+1);//99999-(-99)=100098(位數最多爲左操作數+1個)
char step = 0;//借位
char cRet = 0;
for (int i = 2; i < lSize; ++i)
{
//右操作數的位數還沒減完,左-右-借位
if (rSize-i > 0)
{
cRet = (_pData[lSize-i]-'0') - (s[rSize-i]-'0') - step;
step = 0;
}
//右操作數減完後,左-借位
else
{
cRet = _pData[lSize-i] - '0' - step;
step = 0;
}
if(cRet < 0)//不夠減就進行借位
{
cRet += 10;//當前0位+10
step = 1;//向前面借一位
}
ret[lSize+1-i] = cRet + '0';
}
ret[0] = _pData[0]; //確定符號位
ret[1] = step+'0'; //保存最後一個借位
return ret;
}
string MUL(string& s)
{
int lSize = _pData.size();
int rSize = s.size();
string ret;//定義返回值
//結果最多爲lSize+rSize-2位 "+9999\0" * "+99\0" = "+989901\0"
ret.resize(lSize+rSize-2);
char step = 0;//進位
char count = 0;//錯位
char cRet = 0;
for (int i = 2; i < rSize; ++i)//右操作數比較短,應放於外層循環
{
step = 0;
for (int j = 2; j < lSize; ++j)//左操作數比較長,應放在內層循環
{
cRet = (s[rSize-i]-'0') * (_pData[lSize-j]-'0') + step;
if(count > 0)
cRet += ret[lSize+rSize-2-j-count] - '0';
step = cRet/10;
cRet %= 10;
ret[lSize+rSize-2-j-count] = cRet + '0';
}
count++;//每次向前錯一位
ret[rSize-1-count] += step + '0';//保存最後一個進位
}
//確定結果的符號:同號爲正,異號爲負
if (_pData[0] == s[0])
ret[0] = '+';
else
ret[0] = '-';
return ret;
}
string DIV(string& s)
{
int lSize = _pData.size();
int rSize = s.size();
string ret;//定義返回值
//結果最多爲lSize位 "+9999\0" * "+1\0" = "+9999\0"
ret.reserve(lSize);
string sleft(_pData.c_str(),rSize-1);//被除數
string sright(s.c_str(),rSize-1);//除數
int index = rSize-1;
while(index < lSize)
{
//不夠除
while (sleft.size()==sright.size() && strcmp(sleft.c_str(),sright.c_str())<0)
{
sleft += _pData[index++];//借位
ret.push_back('0');
if (index > lSize)
break;
}
//夠除
int count = 0;
while(sleft.size()>sright.size() ||\
(sleft.size()==sright.size()&&strcmp(sleft.c_str(),sright.c_str())>0))
{
BigData tmp(sleft.c_str());
sleft = tmp.SUB(BigData(sright.c_str())._pData);
++count;
sleft = BigData(sleft.c_str())._pData;//去掉多餘的0
sleft = string(sleft.c_str(),sleft.size()-1);//去掉後面的'\0'
}
ret.push_back(count+'0');
sleft += _pData[index++];//借位
}
//確定結果的符號:同號爲正,異號爲負
if (_pData[0] == s[0])
ret[0] = '+';
else
ret[0] = '-';
return ret;
}
private:
string _pData;
INT64 _value;
};
ostream& operator<<(ostream& _cout,const BigData& bd)
{
_cout<<bd._pData.c_str();
return _cout;
}
測試用例:
#include <iostream>
#include "BigData.h"
using namespace std;
void Test1() //構造函數的測試
{
cout<<BigData()<<endl;
cout<<BigData(25643787278947)<<endl;
cout<<BigData("123456789\0")<<endl;
cout<<BigData(" +000123456789")<<endl;
cout<<BigData("000+0000")<<endl;
cout<<BigData("000- 123456789")<<endl;
cout<<BigData("000+000abc123456789")<<endl;
cout<<BigData("000-000123456789abc123456789")<<endl;
}
void Test2()//加法測試
{
////(同號測試)
//BigData bd1("9999");
//BigData bd2("+1234567");
//cout<<bd1 + bd2<<endl;//同號都沒溢出----結果沒溢出
//BigData bd3("99999999999999999999999999999999999999");
//BigData bd4("99999999999999999999999999999999999999");
//cout<<bd3 + bd4<<endl;//同號都溢出了----結果溢出
//BigData bd5("9223372036854775807");
//BigData bd6("100");
//cout<<bd5 + bd6<<endl;//同號都沒溢出----結果正溢出
//BigData bd7("-9223372036854775808");
//BigData bd8("-100");
//cout<<bd7 + bd8<<endl;//同號都沒溢出----結果負溢出
//(異號測試)
BigData bd1("-9999");
BigData bd2("+1234567");
cout<<bd1 + bd2<<endl;//異號都沒溢出----結果沒溢出
BigData bd3("-99999999999999999999999999999999999999");
BigData bd4("+11111111111111111111111111111111111111");
cout<<bd3 + bd4<<endl;//異號都溢出了----結果溢出
BigData bd5("-9999999999999999999999999999999");
BigData bd6("1000");
cout<<bd5 + bd6<<endl;//異號負數溢出----結果負溢出
BigData bd7("-1000");
BigData bd8("+9999999999999999999999999999999");
cout<<bd7 + bd8<<endl;//異號正數溢出----結果正溢出
BigData bd9(" -1111111111111111111111111111111");
BigData bd10("+9999999999999999999999999999999");
cout<<bd9 + bd10<<endl;//異號正數溢出----結果正溢出
}
void Test3()//減法測試
{
////(同號測試)
//BigData bd1("+999999999");
//BigData bd2("+1234567");
//cout<<bd1 - bd2<<endl;//同號都沒溢出----結果沒溢出
//BigData bd3("99999999999999999999999999999999999999");
//BigData bd4("11111111111111111111111111111111111111");
//cout<<bd3 - bd4<<endl;//同號都溢出了----結果溢出
//BigData bd5("777777777777777777777777777");
//BigData bd6("1000");
//cout<<bd5 - bd6<<endl;//同號正數溢出----結果沒溢出
//BigData bd7("-1000");
//BigData bd8("-88888888888888888888888888888888");
//cout<<bd7 + bd8<<endl;//同號負數溢出----結果溢出
//(異號測試)
BigData bd1("-9999");
BigData bd2("+1234567");
cout<<bd1 - bd2<<endl;//異號都沒溢出----結果沒溢出
BigData bd3("-99999999999999999999999999999999999999");
BigData bd4("+11111111111111111111111111111111111111");
cout<<bd3 - bd4<<endl;//異號都溢出了----結果溢出
BigData bd5("-9999999999999999999999999999999");
BigData bd6("1000");
cout<<bd5 - bd6<<endl;//異號負數溢出----結果負溢出
BigData bd7("-1000");
BigData bd8("+9999999999999999999999999999999");
cout<<bd7 - bd8<<endl;//異號正數溢出----結果正溢出
BigData bd9(" -1111111111111111111111111111111");
BigData bd10("+9999999999999999999999999999999");
cout<<bd9 - bd10<<endl;//異號都溢出了----結果溢出
}
void Test4()//乘法測試
{
//(同號測試)
BigData bd1("+999999999");
BigData bd2("+111111");
cout<<bd1 * bd2<<endl;//同號都沒溢出----結果沒溢出
BigData bd3("-99999999999999999999999999999999999999");
BigData bd4("-11111111111111111111111111111111111111");
cout<<bd3 * bd4<<endl;//同號都溢出了----結果溢出
BigData bd5("9999999999999");
BigData bd6("9999999999999");
cout<<bd5 * bd6<<endl;//同號都沒溢出----結果正溢出
//異號測試
BigData bd7("-1000");
BigData bd8("7654321");
cout<<bd7 * bd8<<endl;//異號都沒溢出----結果沒溢出
BigData bd9("-9999999999999999999999999999");
BigData bd10("+1000000000");
cout<<bd9 * bd10<<endl;//異號溢出了----結果負溢出
BigData bd11("9999999999999");
BigData bd12("-9999999999999");
cout<<bd11 * bd12<<endl;//同號都沒溢出----結果負溢出
}
void Test5()//測試除法
{
BigData bd1("+999999999");
BigData bd2("+11111111111111");
cout<<bd1 / bd2<<endl;//左操作數小於有操作數----結果爲0
BigData bd3("0");
BigData bd4("-11111111111111111");
cout<<bd3 / bd4<<endl;//左操作數--是0--結果爲0
BigData bd5("9999999999999");
BigData bd6("9999999999999");
cout<<bd5 / bd6<<endl;//同號且絕對值相等----結果爲1
BigData bd7("-9999999999999");
BigData bd8("9999999999999");
cout<<bd7 / bd8<<endl;//異號且絕對值相等----結果爲-1
BigData bd9("-9999999999999999999999999999");
BigData bd10("+1");
cout<<bd9 / bd10<<endl;//右操作數爲1---結果爲左操作數
BigData bd11("9999999999999");
BigData bd12("-1");
cout<<bd11 / bd12<<endl;//右操作數爲-1---結果爲 -左操作數
BigData bd13("-9999999999999999999999999999");
BigData bd14("+100000000");
cout<<bd13 / bd14<<endl;//異號且至少有一個溢出
BigData bd15("9999999999999");
BigData bd16("100000");
cout<<bd15 / bd16<<endl;//同號且都沒有溢出
}
int main()
{
//Test1();
//Test2();
//Test3();
//Test4();
Test5();
system("pause");
return 0;
}