進制之間的轉換html
1、談談幾個庫函數ios
函數算法 |
原型函數 |
功能測試 |
參考spa |
atoiunix |
int atoi(const char* nptr);code |
把字符串換化成整型數htm |
百度百科blog |
itoa |
char* itoa(int value, char* string, int radix); |
將整型數轉換爲radix進制數的字符串形式 |
|
atol |
long atol(const char* nptr); |
把字符串轉換成長整型數 |
|
atof |
double atof(const char* nptr); |
把字符串轉換成浮點數 |
|
strtod |
double strtod(const char* nptr, char** endptr); |
把字符串轉換成浮點數 |
|
strtol |
long int strtol(const char* nptr, char** endptr, int base); |
將nptr字符串根據base轉換成長整型數 |
|
strtoul |
unsigned long strtoul(const char* nptr, char** endptr, int base); |
將字符串轉換成無符號長整型數 |
以上函數,atoi是將字符串轉換爲整形數,itoa是根據radix的值將整形數按照radix轉換爲字符串,atol是將字符串轉換爲long型數,atof是將字符串轉換爲double型數,strtod是將字符串轉換爲浮點型,strtol是將字符串根據base轉換爲long型數,strtoul是將字符串根據base轉換爲unsigned long型數。
itoa是從int到字符串,radix是針對字符串來講的;
strtol、strtoul是從字符串到long、unsigned long的,base一樣是相對於字符串來講的。
2、數值的表示形式
在程序中具體的數值類型有int、long int、unsigned long int、float、double等等類型,對應地其表達形式能夠有字符串來表示,上面列舉的函數其實質就是來實現數值類型和字符串之間的相互轉換。
咱們這裏針對數值的表示形式統一採用字符串的形式,程序內部的實現固然仍是用具體的數值類型。
3、實現一個最基本的轉換——十進制到二進制的轉換
十進制到二進制的轉換,咱們的入參都是採用字符串的,因此十進制數是用字符串的形式表示,一樣出參咱們一樣是用字符串的形式來表達。以後咱們每一個轉換函數其入參和出參都是字符串類型。
若是利用上面的函數itoa來求解該問題,那麼入參須是int型的數,具體的調用形式以下:
itoa(value, bin_arry, 2);
十進制轉換爲二進制的方法就是除二取餘法,好比一十進制數20,咱們採用除二取餘法計算的過程爲:
步驟 |
被除數 |
除數 |
商 |
餘數 |
1 |
20 |
2 |
10 |
0 |
2 |
10 |
2 |
5 |
0 |
3 |
5 |
2 |
2 |
1 |
4 |
2 |
2 |
1 |
0 |
5 |
1 |
2 |
0 |
1 |
6 |
0 |
2 |
0 |
0 |
7 |
0 |
2 |
0 |
0 |
… |
… |
… |
… |
… |
計算過程終止的條件便是:被除數==0,最終的二進制字符串爲餘數的倒置,即:
10100
對於字符串的十進制數,咱們能夠採用atoi函數求解,這裏咱們實現一個本身的版本。
具體的程序以下:
// 十進制轉二進制——除二取餘法 long DecimalFromStringToLong(const string& decimal) { long ret = 0; for (auto i = 0; i != decimal.size(); ++i) { ret = ret * 10 + decimal[i] - '0'; } return ret; } string DecimalToBinary(const string& decimal, string& binary) { binary.clear(); long dec = DecimalFromStringToLong(decimal); while (dec != 0) { binary += dec % 2 + '0'; dec /= 2; } reverse(binary.begin(), binary.end()); return binary; }
這裏咱們還給出一種遞歸實現:
// 除二取餘法求解十進制轉二進制——遞歸實現 long DecimalFromStringToLong(const string& decimal) { long ret = 0; for (auto i = 0; i != decimal.size(); ++i) { ret = ret * 10 + decimal[i] - '0'; } return ret; } string DecimalFromLongToString(long dec) { string ret; while (dec != 0) { char ch = dec % 10 + '0'; ret = ch + ret; dec /= 10; } return ret; } string _DecimalToBinaryRecursion(const string& decimal, string& binary) { long dec = DecimalFromStringToLong(decimal); if (dec != 0) { char ch = dec % 2 + '0'; return _DecimalToBinaryRecursion(DecimalFromLongToString(dec / 2), binary) + ch; } else { return binary; } } string DecimalToBinaryRecursion(const string& decimal, string& binary) { binary.clear(); return _DecimalToBinaryRecursion(decimal, binary); }
4、M進制到N進制的轉換
前面從十進制到二進制轉換,咱們利用了除二取餘法,下面咱們嘗試從M進制到N進制進行轉換。其原理是,先計算待轉換M進制數的值,而後根據除N取餘法獲得轉換後的N進制數。
這種方法實質上是利用十進制數在中間作中介,先將M進制數轉換爲10進制數,而後由10進制數根據除N取餘法獲得N進制數。
// M進制到N進制的轉換 // M進制數轉換爲10進制的long long MSystemFromStringToLong(const string& decimal, int m, map<char, long>& msys) { long ret = 0; for (auto i = 0; i != decimal.size(); ++i) { ret = ret * m + msys[decimal[i]]; } return ret; } // 10進制long轉換爲M進制數 string MSystemFromLongToString(long dec, int m, map<long, char>& msys) { string ret; while (dec != 0) { char ch = msys[dec % m]; ret = ch + ret; dec /= m; } return ret; } // M進制到N進制之間的轉換 string MSystemToNSystem(const string& mnumber, string& nnumber, int m, int n, map<char, long>& msys, map<long, char>& nsys) { nnumber.clear(); long tmp = MSystemFromStringToLong(mnumber, m, msys); nnumber = MSystemFromLongToString(tmp, n, nsys); return nnumber; }
咱們對M進制、N進制定義了其各自字符對應於10進制的值,根據預約義的字符-值系統獲得M進制的10進制數,而後對10進制數採用除N取餘法獲得N進制數。
5、一些特殊進制之間的轉換
以上M進制轉換爲N進制,咱們是在中間處理過程藉助了10進製做爲中介。可是一些特殊進制數能夠不用藉助10進制數來作中介,而是直接進行轉換。例如,二進制與八進制之間的轉換,3個二進制位至關於1個八進制位,1個八進制位至關於3個二進制位,其關係以下:
二進制 |
八進制 |
000 |
0 |
001 |
1 |
010 |
2 |
011 |
3 |
100 |
4 |
101 |
5 |
110 |
6 |
111 |
7 |
一樣,二進制數與十六進制數之間的轉換也是如此,一個十六進制位對應於4個二進制位。但有必定須要注意,二進制與八進制、十六進制之間的轉換須要從低位到高位進行,不能從高位到低位。
另外,八進制和十六進制之間的轉換不能直接按位組裝,能夠藉助10進製做爲中介,抑或藉助於二進制數做爲中介進行轉換。
6、阿拉伯數字技術法的討論
在這裏無論咱們討論的哪一種進制,其計數法都是採用的阿拉伯數字計數法。注意,這裏咱們所說的是阿拉伯數字計數法,而非阿拉伯數字,阿拉伯數字是十進制數,咱們這裏的M進制基數形式是藉助於阿拉伯數字計數法,可是進制絕對不只僅是十。
除了阿拉伯數字計數法外,還有不少其餘的,好比羅馬數字計數法、英文計數、漢語基數、大寫漢字級數等等。關於不一樣計數法之間的轉換不是咱們這裏所討論的,咱們這裏討論的是基於阿拉伯數字計數法的不一樣進制之間的相互轉換。
7、考慮小數的狀況
對於整數的轉換,咱們採用的是除M取餘法。對於小數的進制轉換咱們有以下方法:
待轉換M進制小數:
ABC.EFG
咱們首先將其分割爲兩部分:ABC和EFG
針對ABC,咱們仍是按照以前的整數轉換方法進行整數的轉換,轉換爲N進制整數。關於整數與小數之間爲何能分割是由於小數一定小於1,因此轉換爲N進制的結果小數部分依然對應於小數部分,整數部分依然對應於整數部分。
而後對EFG進行小數部分之間的轉換,咱們首先將EFG轉換爲10進制的小數,而後對10進制的小數轉換爲N進制的小數,最後將N進制的整數和小數進行拼接,即得轉換後的N進制數。
轉換ABC.EFG |
|
分割整數部分和小數部分 |
|
整數部分 |
小數部分 |
ABC |
EFG |
各位依次乘以M,獲得10進制整數 |
各位依次除以M,獲得10進制小數 |
對10進制小數,依次除以N,獲得N進制整數 |
對10進制小數,依次乘以N,獲得N進制小數 |
將N進制的整數和小數進行拼接,即得轉換後的N進制數 |
從上表咱們能夠看出對於整數部分的轉換,咱們是先乘後除,這裏的除便是除N取餘法。對於小數部分的轉換,咱們是先除後乘,這裏的乘是指乘N取整法。
具體轉換程序以下:
// 包含小數的不一樣進制之間的轉換 // M進制數轉換爲10進制的long long MSystemFromStringToLong(const string& decimal, int m, map<char, long>& msys) { long ret = 0; for (auto i = 0; i != decimal.size(); ++i) { ret = ret * m + msys[decimal[i]]; } return ret; } // 10進制long轉換爲M進制數 string MSystemFromLongToString(long dec, int m, map<long, char>& msys) { string ret; while (dec != 0) { char ch = msys[dec % m]; ret = ch + ret; dec /= m; } return ret; } // M進制到N進制的轉換 string MSystemToNSystem(const string& mnumber, string& nnumber, int m, int n, map<char, long>& msys, map<long, char>& nsys) { nnumber.clear(); long tmp = MSystemFromStringToLong(mnumber, m, msys); nnumber = MSystemFromLongToString(tmp, n, nsys); return nnumber; } // M進制小數數轉換爲10進制的double小數 double MSystemFromStringToLongDot(const string& decimal, int m, map<char, long>& msys) { double ret = 0; for (int i = decimal.size() - 1; i >= 0; --i) { ret = ret / m + 1.0 * msys[decimal[i]] / m; } return ret; } // 10進制double小數轉換爲M進制小數 string MSystemFromLongToStringDot(double dec, int m, map<long, char>& msys) { string ret; int counter = 0; while (dec != 0 && counter++ < 10) // 最多支持10個小數位,不會無限循環下去 { char ch = msys[dec * m]; ret = ret + ch; dec = dec * m - (long)(dec * m); } return ret; } // 包含小數部分的M進制到N進制的轉換 string MSystemToNSystemDot(const string& mnumber, string& nnumber, int m, int n, map<char, long>& msys, map<long, char>& nsys) { nnumber.clear(); double tmp = MSystemFromStringToLongDot(mnumber, m, msys); nnumber = MSystemFromLongToStringDot(tmp, n, nsys); return nnumber; } string MSystemToNSystemIntAndFrac(const string& mnumber, string& nnumber, int m, int n, map<char, long>& msys, map<long, char>& nsys) { nnumber.clear(); string m_int, m_frac; string n_int, n_frac; auto pos = mnumber.find('.'); m_int = mnumber.substr(0, pos - 0); m_frac = mnumber.substr(pos + 1); MSystemToNSystem(m_int, n_int, m, n, msys, nsys); MSystemToNSystemDot(m_frac, n_frac, m, n, msys, nsys); nnumber = (n_int.empty() ? string("0") : n_int) + (n_frac.empty() ? string("") : (string(".") + n_frac)); return nnumber; }
因爲某些進製表現能力的欠缺,在作小數部分轉換時可能會致使無限轉換,因此咱們規定了小數位數最大爲10。好比十進制0.3轉換爲二進制小數位:0.0100110011,其實後面還有不少位,由二進制小數0.0100110011轉換爲十進制小數位:0.2998046875。
8、關於進制之間轉換的遞歸實現
在前面十進制轉換爲二進制部分中,咱們談論了非遞歸實現和遞歸實現,一樣地M進制到N進制的轉換一樣能夠採用遞歸實現,這裏咱們再也不作贅述,具體作法能夠參考十進制轉二進制的遞歸算法。有關遞歸的思想請參見《遞歸的討論》。
9、總結
本文初衷主要是想討論不一樣進制之間的任意相互轉換。咱們首先討論了C/C++庫函數對這方面的支持,而後談論了數值的表現形式,並用非遞歸和遞歸方法實現了十進制數轉二進制數,進而實現了M進制到N進制的轉換,以後咱們又談論了一些關於數值的計數方法,明確咱們本文所涉及的是阿拉伯數字計數法下的不一樣進制之間的相互轉換,而非對不一樣計數法之間轉換的討論,進而對含有小數部分的不一樣進制之間的轉換進行了討論,針對含有小數部分的作法,咱們是先對其進行分割,對分割出的整數部分依然採用除N取餘法進行求解,對於小數部分的轉換,咱們採用乘N取整法進行轉換。最後咱們對遞歸實現進制間轉換就好了進一步的說明。
附:進制轉換程序及測試代碼(詳見註釋)
#include <iostream> #include <string> #include <map> #include <algorithm> using namespace std; long DecimalFromStringToLong(const string& decimal) { long ret = 0; for (auto i = 0; i != decimal.size(); ++i) { ret = ret * 10 + decimal[i] - '0'; } return ret; } string DecimalFromLongToString(long dec) { string ret; while (dec != 0) { char ch = dec % 10 + '0'; ret = ch + ret; dec /= 10; } return ret; } string DecimalToBinary(const string& decimal, string& binary) { binary.clear(); long dec = DecimalFromStringToLong(decimal); while (dec != 0) { char ch = dec % 2 + '0'; binary = ch + binary; dec /= 2; } return binary; } string _DecimalToBinaryRecursion(const string& decimal, string& binary) { long dec = DecimalFromStringToLong(decimal); if (dec != 0) { char ch = dec % 2 + '0'; return _DecimalToBinaryRecursion(DecimalFromLongToString(dec / 2), binary) + ch; } else { return binary; } } string DecimalToBinaryRecursion(const string& decimal, string& binary) { binary.clear(); return _DecimalToBinaryRecursion(decimal, binary); } // M進制數轉換爲10進制的long long MSystemFromStringToLong(const string& decimal, int m, map<char, long>& msys) { long ret = 0; for (auto i = 0; i != decimal.size(); ++i) { ret = ret * m + msys[decimal[i]]; } return ret; } // 10進制long轉換爲M進制數 string MSystemFromLongToString(long dec, int m, map<long, char>& msys) { string ret; while (dec != 0) { char ch = msys[dec % m]; ret = ch + ret; dec /= m; } return ret; } // M進制到N進制的轉換 string MSystemToNSystem(const string& mnumber, string& nnumber, int m, int n, map<char, long>& msys, map<long, char>& nsys) { nnumber.clear(); long tmp = MSystemFromStringToLong(mnumber, m, msys); nnumber = MSystemFromLongToString(tmp, n, nsys); return nnumber; } // M進制小數數轉換爲10進制的double小數 double MSystemFromStringToLongDot(const string& decimal, int m, map<char, long>& msys) { double ret = 0; for (int i = decimal.size() - 1; i >= 0; --i) { ret = ret / m + 1.0 * msys[decimal[i]] / m; } return ret; } // 10進制double小數轉換爲M進制小數 string MSystemFromLongToStringDot(double dec, int m, map<long, char>& msys) { string ret; int counter = 0; while (dec != 0 && counter++ < 10) // 最多支持10個小數位,不會無限循環下去 { char ch = msys[dec * m]; ret = ret + ch; dec = dec * m - (long)(dec * m); } return ret; } // 包含小數部分的M進制到N進制的轉換 string MSystemToNSystemDot(const string& mnumber, string& nnumber, int m, int n, map<char, long>& msys, map<long, char>& nsys) { nnumber.clear(); double tmp = MSystemFromStringToLongDot(mnumber, m, msys); nnumber = MSystemFromLongToStringDot(tmp, n, nsys); return nnumber; } string MSystemToNSystemIntAndFrac(const string& mnumber, string& nnumber, int m, int n, map<char, long>& msys, map<long, char>& nsys) { nnumber.clear(); string m_int, m_frac; string n_int, n_frac; auto pos = mnumber.find('.'); m_int = mnumber.substr(0, pos - 0); m_frac = mnumber.substr(pos + 1); MSystemToNSystem(m_int, n_int, m, n, msys, nsys); MSystemToNSystemDot(m_frac, n_frac, m, n, msys, nsys); nnumber = (n_int.empty() ? string("0") : n_int) + (n_frac.empty() ? string("") : (string(".") + n_frac)); return nnumber; } int main() { string binary; cout << DecimalToBinary("20", binary) << endl; cout << DecimalToBinaryRecursion("20", binary) << endl; map<char, long> msys; map<long, char> msys_2; for (int i = 0; i < 10; ++i) { msys[i + '0'] = i; msys_2[i] = i + '0'; } map<long, char> nsys; map<char, long> nsys_2; for (char ch = 'A'; ch < 'Z' + 1; ++ch) { nsys[ch-'A'] = ch; nsys_2[ch] = ch - 'A'; } string nnumber; cout << MSystemToNSystem("28", nnumber, 10, 26, msys, nsys) << endl; cout << MSystemToNSystem("BC", nnumber, 26, 10, nsys_2, msys_2) << endl; cout << MSystemToNSystem("288", nnumber, 10, 10, msys, msys_2) << endl; cout << MSystemToNSystem("BCZ", nnumber, 26, 26, nsys_2, nsys) << endl; map<long, char> bsys; map<char, long> bsys_2; for (char ch = '0'; ch < '2'; ++ch) { bsys[ch - '0'] = ch; bsys_2[ch] = ch - '0'; } cout << MSystemToNSystemIntAndFrac("1.5", nnumber, 10, 2, msys, bsys) << endl; cout << MSystemToNSystemIntAndFrac("1.1", nnumber, 2, 10, bsys_2, msys_2) << endl; cout << MSystemToNSystemIntAndFrac("0.3", nnumber, 10, 2, msys, bsys) << endl; cout << MSystemToNSystemIntAndFrac("0.0100110011", nnumber, 2, 10, bsys_2, msys_2) << endl; cout << MSystemToNSystemIntAndFrac("20.55", nnumber, 10, 26, msys, nsys) << endl; cout << MSystemToNSystemIntAndFrac("U.OHUUUUUUUU", nnumber, 26, 10, nsys_2, msys_2) << endl; return 0; }