c++之大數 實現加減法
阿新 • • 發佈:2019-01-02
剛開始我見到網上的視訊教程裡有關於大數的實現,他是使用的連結串列來儲存數值,我開始嘗試也使用連結串列,但是失敗了,我又試著使用陣列來實現,經過兩天的奮戰,終於把這個類實現了,但遺憾的是隻實現了加減法,因為自己的知識有限,未能實現乘法除法運算,如果有大神知道如何實現,小弟我感激不盡。
直接上程式碼
#ifndef BIGNUMBER_H #define BIGNUMBER_H #include <iostream> #include <string> class BigNumber { public: BigNumber(); BigNumber(std::string s_16); BigNumber(const BigNumber &number); /************************************************************************/ /* 改變數值的操作 */ /************************************************************************/ void setMaxValue(); void setMinValue(); BigNumber& operator++();//字首過載 const BigNumber operator++(int);//字尾過載 BigNumber& operator--();//字首過載 const BigNumber operator--(int);//字尾過載 const BigNumber& operator=(const BigNumber &number); const BigNumber& operator+=(const BigNumber &number); const BigNumber& operator-=(const BigNumber &number); /************************************************************************/ /* 基本運算操作 */ /************************************************************************/ const BigNumber operator+(const BigNumber &number); const BigNumber operator-(const BigNumber &number); const BigNumber operator*(const BigNumber &number);//————————未完成 const BigNumber operator/(const BigNumber &number);//————————未完成 /************************************************************************/ /* 大小比較操作 */ /************************************************************************/ bool operator>(const BigNumber &number); bool operator<(const BigNumber &number); bool operator==(const BigNumber &number); bool operator<=(const BigNumber &number); bool operator>=(const BigNumber &number); /************************************************************************/ /* 輸出操作 */ /************************************************************************/ friend std::ostream& operator<<(std::ostream &os, BigNumber &number); friend std::istream& operator>>(std::istream &is, BigNumber &number); const static unsigned int MaxValue = 0xFFFFFFFF;//一個無符號整數的最大值 const static unsigned int MinValue = 0x00000000;//一個無符號整數的最小值 const static unsigned int Size = 100;//儲存區大小 private: unsigned int data[Size];//儲存區 void _add(unsigned int data[], unsigned int posion);//進位操作 void _sub(unsigned int data[], unsigned int posion);//借位操作 unsigned char toBit4(char c);//字元轉數值 char fromBit4(unsigned char c);//數值轉字元 void set_Bit16(std::string s_16); std::string get_Bit16(); }; #endif
#include "BigNumber.h" /************************************************************************/ /* 預設建構函式,初始數值為0 */ /************************************************************************/ BigNumber::BigNumber() { setMinValue(); } /************************************************************************/ /* 以一個16進製表示的字串初始化大數 */ /************************************************************************/ BigNumber::BigNumber(std::string s_16) { this->set_Bit16(s_16); } /************************************************************************/ /* 拷貝建構函式 */ /************************************************************************/ BigNumber::BigNumber(const BigNumber &number) { for (unsigned int index = 0; index < BigNumber::Size; index++) { this->data[index] = number.data[index]; } } /************************************************************************/ /* 進位操作實際上是一個自加的過程,如果低位的數值自加後會溢位,則將 */ /* 高一位的數也自加,否則就直接將當前數值自加後退出 */ /************************************************************************/ void BigNumber::_add(unsigned int data[], unsigned int posion) { if (this->data[posion] == 0xFFFFFFFF)//如果當前位的值為最大值 { if (posion == Size - 1)//如果到達最高位,則直接進行自加,不再進位 { this->data[posion]++; return; } _add(data, posion + 1);//通過將高位自加來表示進位 this->data[posion]++; } else//若不是最大值則進行自加 { this->data[posion]++; } } /************************************************************************/ /* 借位操作實際上是一個自減的過程,如果低位的數值自減後會溢位,則將 */ /* 高一位的數也自減,否則就直接將當前數值自減後退出 */ /************************************************************************/ void BigNumber::_sub(unsigned int data[], unsigned int posion) { if (this->data[posion] == 0x00000000)//如果當前位的值為最小值 { if (posion == BigNumber::Size - 1)//如果到達最高位,則直接進行自減,不再借位 { this->data[posion]--; return; } _sub(data, posion + 1);//通過將高位自減來表示借位 this->data[posion]--; } else//若不是最小值則進行自減 { this->data[posion]--; } } /************************************************************************/ /* 將一個16進製表示的字元轉為數值 */ /************************************************************************/ unsigned char BigNumber::toBit4(char c) { if (c <= '9'&&c >= '0') { return c - '0'; } else if (c <= 'F'&&c >= 'A') { return c - 'A' + 10; } else if (c <= 'f'&&c >= 'a') { return c - 'a' + 10; } else { return 0xf0; } } /************************************************************************/ /* 將一個0~15之內的數值轉為16進製表示的字元 */ /************************************************************************/ char BigNumber::fromBit4(unsigned char n) { if (n <= 9 && n >= 0) { return n + '0'; } if (n<=15&&n>=10) { return n + 'A' - 10; } return '\0'; } /************************************************************************/ /* 將數值轉為一個16進製表示的字串,並返回該字串 */ /************************************************************************/ std::string BigNumber::get_Bit16() { unsigned int index1 = BigNumber::Size - 1; while (this->data[index1] == 0) //指向最高有效位 { if (index1 == 0) { break; } index1--; } std::string s_16; for (unsigned int i = index1 +1 ; i > 0;i--) { unsigned char bit7, bit6, bit5, bit4, bit3, bit2, bit1, bit0; unsigned int temp = this->data[i - 1];//取出一個32位 /* 從高到低得到每一個4bit */ bit7 = (temp >> 28) & 0xf; bit6 = (temp >> 24) & 0xf; bit5 = (temp >> 20) & 0xf; bit4 = (temp >> 16) & 0xf; bit3 = (temp >> 12) & 0xf; bit2 = (temp >> 8) & 0xf; bit1 = (temp >> 4) & 0xf; bit0 = temp & 0xf; s_16 += fromBit4(bit7); s_16 += fromBit4(bit6); s_16 += fromBit4(bit5); s_16 += fromBit4(bit4); s_16 += fromBit4(bit3); s_16 += fromBit4(bit2); s_16 += fromBit4(bit1); s_16 += fromBit4(bit0); } return s_16; } /************************************************************************/ /* 接受一個16進位制數的字串,將其存入轉為BigNumber */ /************************************************************************/ void BigNumber::set_Bit16(std::string s_16) { this->setMinValue();//置零 unsigned int size = s_16.size();//補位,不夠32位則高位補零 if (size % 8 == 7) { s_16 = "0" + s_16; } else if (size % 8 == 6) { s_16 = "00" + s_16; } else if (size % 8 == 5) { s_16 = "000" + s_16; } else if (size % 8 == 4) { s_16 = "0000" + s_16; } else if (size % 8 == 3) { s_16 = "00000" + s_16; } else if (size % 8 == 2) { s_16 = "000000" + s_16; } else if (size % 8 == 1) { s_16 = "0000000" + s_16; } /************************************************************************/ /* 一次取8個字元,將其轉為32位無符號整數存入 */ /************************************************************************/ for (unsigned int i = 0; i < s_16.size() / 8; ++i) { std::string c4 = s_16.substr(8 * i, 8 * i + 8); unsigned int bit7, bit6, bit5, bit4, bit3, bit2, bit1, bit0; bit7 = toBit4(c4[0]); bit6 = toBit4(c4[1]); bit5 = toBit4(c4[2]); bit4 = toBit4(c4[3]); bit3 = toBit4(c4[4]); bit2 = toBit4(c4[5]); bit1 = toBit4(c4[6]); bit0 = toBit4(c4[7]); this->data[s_16.size() / 8 - i - 1] |= bit7; this->data[s_16.size() / 8 - i - 1] <<= 4; this->data[s_16.size() / 8 - i - 1] |= bit6; this->data[s_16.size() / 8 - i - 1] <<= 4; this->data[s_16.size() / 8 - i - 1] |= bit5; this->data[s_16.size() / 8 - i - 1] <<= 4; this->data[s_16.size() / 8 - i - 1] |= bit4; this->data[s_16.size() / 8 - i - 1] <<= 4; this->data[s_16.size() / 8 - i - 1] |= bit3; this->data[s_16.size() / 8 - i - 1] <<= 4; this->data[s_16.size() / 8 - i - 1] |= bit2; this->data[s_16.size() / 8 - i - 1] <<= 4; this->data[s_16.size() / 8 - i - 1] |= bit1; this->data[s_16.size() / 8 - i - 1] <<= 4; this->data[s_16.size() / 8 - i - 1] |= bit0; } } /************************************************************************/ /* 設定數值為最小值 */ /************************************************************************/ void BigNumber::setMaxValue() { for (unsigned int index = 0; index < BigNumber::Size; index++) { data[index] = 0xFFFFFFFF; } } /************************************************************************/ /* 設定數值為最大值 */ /************************************************************************/ void BigNumber::setMinValue() { for (unsigned int index = 0; index < BigNumber::Size; index++) { data[index] = 0x00000000; } } const BigNumber& BigNumber::operator=(const BigNumber &number) { for (unsigned int index = 0; index < BigNumber::Size; index++) { this->data[index] = number.data[index]; } return *this; } const BigNumber& BigNumber::operator+=(const BigNumber &number) { *this = *this + number; return *this; } const BigNumber& BigNumber::operator-=(const BigNumber &number) { *this = *this - number; return *this; } BigNumber& BigNumber::operator++()//字首過載,返回自加之後的值 { _add(this->data, 0); return *this; } const BigNumber BigNumber::operator++(int)//字尾過載,返回自加之前的值 { BigNumber n = *this; _add(this->data, 0); return n; } BigNumber& BigNumber::operator--()//字首過載,返回自減之後的值 { _sub(this->data, 0); return *this; } const BigNumber BigNumber::operator--(int)//字尾過載,返回自減之前的值 { BigNumber n = *this; _sub(this->data, 0); return n; } /******************************************************************************/ /* 加法操作並不會改變兩個運算元本身的值,所以這裡儲存第一個加數的值到變數n */ /* 中,並將最終的和儲存到變數n中,返回變數n的值 */ /******************************************************************************/ const BigNumber BigNumber::operator+(const BigNumber &number) { BigNumber n = *this; for (unsigned int index = 0; index < BigNumber::Size - 1; ++index) { if (BigNumber::MaxValue - this->data[index] < number.data[index])//如果需要進位則執行進位操作 { n._add(n.data, index + 1); } n.data[index] = n.data[index] + number.data[index];//執行加法 } n.data[BigNumber::Size - 1] = n.data[BigNumber::Size - 1] + number.data[BigNumber::Size - 1];//最高位不用進行進位 return n; } /******************************************************************************/ /* 減法操作並不會改變兩個運算元本身的值,所以這裡儲存被減數的值到 變數n中 */ /* 並將最終的差儲存到變數n中,返回變數n的值 */ /******************************************************************************/ const BigNumber BigNumber::operator - (const BigNumber &number) { BigNumber n=*this; for (unsigned int index = 0; index < BigNumber::Size - 1; ++index) { if (n.data[index] < number.data[index])//如果不夠減,就執行借位操作 { n._sub(n.data, index + 1);//借位 } n.data[index] = n.data[index] - number.data[index];//執行減法 } n.data[BigNumber::Size - 1] = n.data[BigNumber::Size - 1] - number.data[BigNumber::Size - 1];//最高位不需要借位 return n; } /************************************************************************/ /* 比較大小操作 */ /************************************************************************/ bool BigNumber::operator>(const BigNumber &number) { unsigned int index1 = BigNumber::Size - 1;//分別指向最大下標 unsigned int index2 = BigNumber::Size - 1; while (this->data[index1] == 0) //指向最高有效位 { if (index1 == 0) { break; } index1--; } while (number.data[index2] == 0) //指向最高有效位 { if (index2 == 0) { break; } index2--; } if (index1 > index2) { return true; } else if (index1 <index2) { return false; } else//當最高有效位的儲存區下標相同時,比較儲存區內的數值 { if (this->data[index1] > number.data[index2]) { return true; } else { return false; } } } bool BigNumber::operator<(const BigNumber &number) { unsigned int index1 = BigNumber::Size - 1;//分別指向最大下標 unsigned int index2 = BigNumber::Size - 1; while (this->data[index1] == 0) //指向最高有效位 { if (index1 == 0) { break; } index1--; } while (number.data[index2] == 0) //指向最高有效位 { if (index2 == 0) { break; } index2--; } if (index1 < index2) { return true; } else if (index1 > index2) { return false; } else//當最高有效位的儲存區下標相同時,比較儲存區內的數值 { if (this->data[index1] < number.data[index2]) { return true; } else { return false; } } } bool BigNumber::operator == (const BigNumber &number) { for (unsigned int index = 0; index < BigNumber::Size; index++) { if (this->data[index] != number.data[index])//只要遇到儲存的數值不一樣就返回false { return false; } } return true; } bool BigNumber::operator <= (const BigNumber &number) { if (*this < number || *this == number) { return true; } return false; } bool BigNumber::operator >= (const BigNumber &number) { if (*this > number || *this == number) { return true; } return false; } /************************************************************************/ /* 過載輸出操作,輸出一個16進位制的字串,以0x開頭 */ /************************************************************************/ std::ostream& operator<<(std::ostream &os, BigNumber &number) { std::string s_16; s_16 = number.get_Bit16(); os << "0x" << s_16; return os; } /************************************************************************/ /* 過載輸入操作,接收一個16進位制的字串,不需要0x開頭 */ /************************************************************************/ std::istream& operator>>(std::istream &is, BigNumber &number) { std::string s_16; is >> s_16; number.set_Bit16(s_16); return is; }
我本來不想使用c++的string來實現資料的輸出操作,但發現c++的iostream不能格式化輸出資料,所以就暫時使用string來實現資料的顯示。在實現類的過程中我也學到了很多知識。
理解了友元函式,友元函式只是在標頭檔案中宣告,友元函式並不是類的成員函式,但賦予了友元函式訪問類中私有成員的權利,以便多個類實現資料的共享(為了方便使用)
如何更好的以c++的風格過載,以及字首++和字尾++的區別,瞭解到為什麼字首++要比字尾++的效率要高,因為字首++返回的是物件的引用,而後綴++返回的是物件的值。
如果有時間,我會繼續查閱資料來實現大數的乘法和除法。這裡貼出我想要實現的大數的記憶體模型