一文攻破BCD碼轉換與各進位轉換

  • 2019 年 10 月 6 日
  • 筆記

一文攻破BCD碼轉換與各進位轉換

0.導語

最近做的項目中時刻看到時間戳用BCD[xx]來定義,那麼針對這種定義,究竟代表什麼意思,如何來使用呢,本節來闡述BCD碼與其他進位轉換以及在筆試當中,會碰到進位轉換問題,放在C/C++中,又究竟如何操作,本文來逐個攻破!

1.BCD碼

BCD碼(Binary-Coded Decimal‎)亦稱二進碼十進數或二-十進位程式碼。

用4位二進位數來表示1位十進位數中的0~9這10個數碼。

是一種二進位的數字編碼形式,用二進位編碼的十進位程式碼。

BCD碼這種編碼形式利用了四個位元來儲存一個十進位的數碼,使二進位和十進位之間的轉換得以快捷的進行。

這種編碼技巧最常用於會計系統的設計里,因為會計制度經常需要對很長的數字串作準確的計算。相對於一般的浮點式記數法,採用BCD碼,既可保存數值的精確度,又可免去使電腦作浮點運算時所耗費的時間。

此外,對於其他需要高精確度的計算,BCD編碼亦很常用。

BCD碼的運算規則:BCD碼是十進位數,而運算器對數據做加減運算時,都是按二進位運算規則進行處理的。這樣,當將 BCD碼傳送給運算器進行運算時,其結果需要修正。

修正的規則:當兩個BCD碼相加,如果和等於或小於 1001(即十進位數9),不需要修正;如果相加之和在 1010 到1111(即十六進位數 0AH~0FH)之間,則需加 6 進行修正;如果相加時,本位產生了進位,也需加 6 進行修正。

這樣做的原因是,機器按二進位相加,所以 4 位二進位數相加時,是按「逢十六進一」的原則進行運算的,而實質上是 2 個十進位數相加,應該按「逢十進一」的原則相加,16 與10相差 6,所以當和超過 9或有進位時,都要加 6 進行修正。

上述學習自:https://blog.csdn.net/morixinguan/article/details/50682650

BCD碼與任意進位數的轉換實現如下:

舉個例子:比如0x2A—–>二進位表示為:0010 1010 -> BCD 二進位碼 0100 0010 對應的十進位為66 十六進位42 字元為B。

/**   * 任意進位轉BCD   * @param src   * @return   */  unsigned char BcdFromHex(const BYTE &src) {    unsigned char temp;      temp = ((src / 10) << 4) + (src % 10);      return temp;  }  /**   * BCD轉任意進位   * @param src   * @return   */  unsigned char HexFromBcd(const BYTE &src) {    unsigned char temp;      temp = (src >> 4)*10 + (src & 0x0f);    return temp;  }

2.進位之間轉換

十六進位是逢16進1,八進位是逢8進1,其他進位依次類推,就不多闡述。

2.1 十進位轉任意進位

思路兩個,分為遞歸與非遞歸實現。

遞歸實現:假設十進位轉n進位,那麼就讓十進位數不斷除以n,最終餘數為0,遞歸終止,不斷彈出棧即可。

/**   * 十進位轉任意進位 遞歸法   * @param vec   * @param m   * @param b   */  void DecConvertOther(vector<char> &vec, int m, int b) {      // 餘數為0 遞歸結束,開始返回棧      if(!m)          return;      int yushu;      DecConvertOther(vec, m / b, b);      yushu = m % b;      if (yushu < 10) {          //小於10直接輸出          vec.push_back(yushu + '0');      }      else {          //大於10轉換成字元輸出          vec.push_back(yushu+55+'0');      }  }

非遞歸實現:每次得到的餘數插入頭部即可。

/**   * 十進位轉任意進位 非遞歸法   * @param vec   * @param m   * @param b   */  void DecConvertOther1(vector<char> &vec, int m, int b) {      int yushu=0;      do {         yushu=m%b;         vec.insert(vec.begin(),yushu+'0');         m = m/b;      }while (m!=0);  }

2.2 任意進位轉十進位

只需要判斷任意進位的高位是否是數字,是否在A-F或a-f之間,然後高位乘以進位再加上最低位。

/**   * 任意進位轉十進位   * @param a   * @param b   * @return   */  int OtherConvertDec(char a[], int b) {      int len, i, num;      int sum = 0;      len = strlen(a);                    //求得字元串長度      for (i = 0; i < len; i++) {          if (a[i] >= '0' && a[i] <= '9')              num = a[i] - '0';          else if (a[i] >= 'A' && a[i] <= 'F')              num = a[i] - 'A' + 10;          else if (a[i] >= 'a' && a[i] <= 'f')              num = a[i] - 'a' + 10;          sum = sum * b + num;      }      return sum;  }

2.3 C/C++進位轉換

在C/C++中沒有像Python中的int(),hex()這樣的函數,可以將十進位轉換為十六進位,但是有另外一些函數可以完成此類工作。

C實現

使用C語言來完成這個任務,將十進位數轉換為十六進位數時使用sprinf(),而將十六進位數轉換為十進位數時使用strtol()

int de=19;  char ch[10];  // 方法1  // 十進位轉十六進位  sprintf(ch,"%X",de);  cout<<ch<<endl;  // 十六進位轉十進位  de=strtol(ch,NULL,16);  cout<<de<<endl;

C++實現

// 十進位轉十六進位  stringstream ss;  ss<<hex<<de;  string s = ss.str();  cout<<s<<endl;  // 十六進位轉十進位  int raw;  ss>>hex>>raw;  cout<<raw<<endl;

3.總結

本節學習了BCD碼與其他進位的轉化以及十進位轉其他進位、其他進位轉十進位實現等,在項目開發中BCD碼使用非常廣,後面來仔細說明,歡迎訂閱公眾號光城。