數字IC-00數制和編碼


數制和編碼

Since the final exam is upcoming, efforts should be paid to the review of this Application and Design of Digital Logic (ADDL) course. There have been several topics on number system and encoding systems that are of great detail. This paper aims to give a brief introduction to those two systems. Firstly in the encoding system, binary, octal, decimal, hexadecimal systems will be introduced, with their presentation way and their transformation methods. Especially, there will also be topics on the binary system's arithmetic, covering addiction, 1st compliment, 2nd compliment and related. For the encoding system of numbers, the most commonly used ones will be included. The following will be an introduction to several character encoding systems. However, this paper will not cover digital image encoding, digital video encoding, or the encoding systems in digital communication. Information Science and Encoding could be the following topic of this paper.

1 數制

1.1 數制

常用的數制包括有十進制, 二進制, 八進制以及十六進制, 對應情況如下.

Decimal Binary Octal Hexadecimal
00 0000 00 0
01 0001 01 1
02 0010 02 2
03 0011 03 3
04 0100 04 4
05 0101 05 5
06 0110 06 6
07 0111 07 7
08 1000 10 8
09 1001 11 9
10 1010 12 A
11 1011 13 B
12 1100 14 C
13 1101 15 D
14 1110 16 E
15 1111 17 F

編程中, 為了表明使用的數制, 一般給數字加前綴.

Decimal Binary Octal Hexadecimal
Verilog 8'd65 8'b0100_0001 8'o0101 8'h41
C 65 0b1000001 0101 0x41
Python 65 0b1000001 0o101 0x41

1.2 二進制的MSB和LSB

二進制是計算機最常用的數制, 因為它可以允許以\(0\)\(1\)表示出所有數字.

當一個數字用二進制表示時, 我們稱其

  • 最左端(權最大)的那一位為Most Significant Bit(MSB),
  • 最右端(權最小)的那一位為Least Significant Bit(LSB).

1.3 數制之間的相互轉換

這里對數制轉換的介紹順序為, N -> 10, 10 ->2, 2-> N, 10->N.

1.3.1 N -> 10

\(N\)進制轉為十進制, 使用公式

\[Decimal = \sum k_i N^i \]

即可.

1.3.2 10 -> 2

十進制轉換為二進制, 十進制數的整數部分和小數部分的轉換方法是不同的.

  • 整數部分: 通過將十進制數不斷除以\(2\)獲得每一次的余數(\(0\) or \(1\)), 最后得到的余數為整數的最高位.
  • 小數部分: 通過將十進制數不斷乘以\(2\)獲得每一次的整數(0 or 1), 最后得到的整數為小數的最高位.

例子: \(18.8125\)

對整數部分處理, 獲得的余數序列為\(01001\), 故整數部分為\(10010\);

對小數部分處理, 獲得的整數序列為\(1101\), 故小數部分為\(1101\);

所以\(18.8125\)的二進制表示為\(10010.1101\).

注: 整數部分高位是指左邊的位; 小數部分的高位指的右邊的位.

1.3.3 2 -> N

這里的\(N\)進制僅僅指\(2^i\)進制, 因為數字系統中最常用的還是\(2^i\)進制.

  • 二進制轉化為八進制: 將二進制數從低位開始, 每三位分為一組, 轉變為八進制
  • 二進制轉為十六進制: 將二進制數從低位開始, 每四位分為一組, 轉為十六進制

1.3.4 10 -> N

十進制轉換為\(N\)進制, 可以先十進制轉為\(2\)進制, 再\(2\)\(N\).

1.3.5 編程中的實現

這里不進行Verilog數制轉換的討論.

// C
// src: https://blog.csdn.net/weixin_44184990/article/details/105019311
// 使用棧進行進制轉化,N是非負十進制整數,B是要轉化的進制數; 用char原因: 十六進制存在ABC等字符
void conversionBase(int N, int B) 
{
	if(N == 0 || B < 0) 
    {
		return;
	}
    
	char stack[128];//用數組來模擬棧
	int top = 0;
	
	if (B <= 10)//比如二進制,八進制的做法 
    {	                                    
		while (N) 
        {
			stack[top++] = (N % B) + '0';//'0',可將int類型轉化為字符類型
			N /= B;
		}
	} 
    else 
    {
		while (N) 
        {
			if (N % B > 9) 
            {
				stack[top++] = (N % B) - 10 + 'A';//'A',可將int類型轉換為字符類型
			} 
            else 
            {
				stack[top++] = (N % B) + '0';
			}
			N /= B;
		}
	}
	//從棧頂開始逐個輸出字符
	for (int i = top - 1 ; i >= 0; i--) { 
		printf("%c",stack[i]);
	}
}
# Python
# number = 233, 
int (0xe9) # 233
hex (233) # 0xe9
oct (0xe9) # 0o351
bin (0o351) # 0b11101001

1.4 二進制的算術運算

1.4.1 加法運算

二進制的加法運算類似於十進制的, 逢\(2\)\(1\)即可.

1.4.2 乘法與除法運算

二進制的乘法運算是不斷將被乘數(或\(0\))左移\(1\)位然后再相加得到.

二進制的除法運算是不斷將被除數(或\(0\))右移\(1\)位然后再相減得到.

相比於十進制, 區別就在於, 十進制的乘除, 在二進制下, 形式為左移和右移.

1.4.3 固定位數的加法運算

數字邏輯一般限定了數字的位數, 位數固定后的加法需要考慮溢出的情況, 我們用進位輸出(carry-out)位來表示. 只有作加法的兩個數字發生了溢出, 我們才令carry-out位為\(1\).

如果固定位數為\(1\), 則我們稱其為半加器. 一個半加器只考慮把兩個數字加起來, 輸入為加數\(a\)\(b\), 輸出為它們的和\(s\), 以及進位輸出\(carry-out\).

Tab. 半加器的真值表
a b co s
0 0 0 0
0 1 0 1
1 0 0 1
1 1 1 0

全加器相比於半加器, 考慮的是, 作為加法計算中的一個單元.

於是它的輸入中, 還有來自上一位的carry-out, 為了分別, 把上一位的carry-out, 在這一位稱為carry-in, 中文叫做進位輸入.

Tab. 全加器的真值表
ci a b co s
0 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 1 1 1 0
1 0 0 0 1
1 0 1 1 0
1 1 0 1 0
1 1 1 1 1

1.4.4 反碼與補碼運算

提出補碼是為了將減法運算轉換為加法運算, 以下為相關的定義:

原碼: 在數字前加一位符號位, 其中\(0\)代表為正, \(1\)代表為負.

反碼, 1st complement: 原碼為正時, 其反碼為自身; 原碼為負時, 其反碼為符號位外的每一位取反.

補碼, 2nd complement: 原碼為正時, 其補碼為自身; 原碼為負時, 其補碼為反碼加一.

補碼通過將負數納入表示范圍, 可以通過加一個數的負數來代替減法.

原碼表示的數字要進行加減法, 首先轉為補碼表示下的加法, 然后直接二進制相加, 得到的結果就是補碼表示的和.

注意補碼表示下, 同符號整數的和如果超過位寬, 則會發生溢出.

手算中, 這種情況表現為, 負數加負數為正數, 正數加正數為正數, 但正數加負數絕對不會溢出;

用數字邏輯進行判斷, 則看符號位的carry-in和carry-out, 如果它倆相同, 則不發生溢出, 如果它倆不同, 則溢出.

這點可以對照Tab. 全加器的真值表, a和b代表原來兩個數的符號, 當ci != co時, 出現正加正為負, 負加負為正的情況.

1.5 數據在存儲/ 傳輸中的大小端模式

1.5.1 大小端模式概念

Ref: https://www.cnblogs.com/lingyejun/p/8312838.html

可以把一個二進制數字看作數據, 數據在存儲和傳輸中的基本單位為字節.

一個字節包含\(8\)個位, 如果傳輸的數字用8位以內的二進制數字就可以表示出來, 則不需要考慮大小端. 而如果這個數字需要用超過\(8\)個位的二進制數字表示, 則需要考慮大小端.

比如我們的數字是\(0x12345678\), 要存儲/ 傳輸這個數字, 我們需要\(4\)個字節(, \(16\)進制每個數用\(4\)位二進制數字表示, 一個字節有\(8\)位). 其中\(0x12\)是高位字節, \(0x78\)是低位字節.

  • 大端模式 Big-Endian

數字的高位字節放在內存的高位地址端, 數字的低位字節放在內存的低位地址端.

  • 小端模式 Little-Endian

數字的高位字節放在內存的低位地址端, 數字的低位字節放在內存的高位地址端.

注意大小端強調的是字節在內存中的順序, 而MSB, LSB強調的是一個二進制數字某位的權值.

1.5.2 兩種模式對比

大端模式比較符合人的習慣, 且如果是補碼形式, 符號位存放在低地址, 數值計算判斷正負, 作比較時快.

小端模式做強制類型轉換時, 直接取低地址, 低地址上的是低字節, 符合一般的邏輯.

1.5.3 不同CPU架構的大小端模式

不同的CPU架構下數字的存儲大小端模式是不同的, 在做移植, 或者通信的時候, 需要考慮大小端的問題.

CPU架構 模式
PowerPC Big-Endian
IBM Big-Endian
Intel x86 Little-Endian
ARM 默認Little-Endian
TCP/IP網絡字節順序 Big-Endian

1.5.4 C語言對大小端進行檢驗

ref: https://zhuanlan.zhihu.com/p/144718837

在C語言中, 令一字節(byte)為8位(bit), 則從左至右地給這\(8\)位編號為\(7\sim0\), 則MSB即為第7位, LSB即為第0位.

1.5.4.1 聯合體union的方式

C語言中, union數據所占內存空間為其最大成員所占的空間. 對union內部成員的存取都是相對於基地址偏移量為0開始的. 這里定義兩種類型進行讀取, 來判斷大小端存儲方式.

// src: https://zhuanlan.zhihu.com/p/144718837
#include <stdio.h>
int main()
{
    union
    {
        int a;  // 4 bytes
        char b; // 1 byte
    } data;
  
    data.a = 1; //占4 bytes, 十六進制可表示為 0x 00 00 00 01
    
    if(1 == data.b)
    { 
      printf("Little_Endian\n"); // 如果走該case, 說明a的低字節存到了聯合體的低位, 即為小端. 
    } 
    else 
    {
      printf("Big_Endian\n");
    }
    
   return 0;
}

1.5.4.2 單字符變量char的方式

// src: https://zhuanlan.zhihu.com/p/144718837
#include <stdio.h>
int main()
{
    int a = 1; // 占4 bytes, 十六進制可表示為 0x 00 00 00 01
    
    // b相當於取了a的低地址部分 
    char *b = (char *)&a; // 占1 byte
    
    if (1 == *b) 
    {
        printf("Little_Endian!\n"); // 如果走該case, 說明a的低字節取到了b, 屬於小端模式
    } 
    else 
    {
        printf("Big_Endian!\n");
    }
    
    return 0;
}

1.6 浮點數的表達與計算

[這里先留坑, 復習時間不夠了]

  • 之前提到的都是整數,
  • 這里為什么需要有浮點數
  • 浮點數的表示
  • 浮點運算單位FLOPS 和 其它單位的關系??
  • 高性能計算中對浮點的處理 (數值分析???, AICS內容???)

浮點處理單元 vs. 數字信號處理器

1.7 數值計算中的誤差

2 編碼

2.1 數字的編碼

編碼就是用\(0\)\(1\)來表示各種各樣的東西, 這里先從對數字的編碼開始.

與之前的二進制更多的計算用途不同, 這里側重點在於方便表示.

2.1.1 十進制數字的編碼

這里的編碼需要考慮的東西不多, 主要有三種, 包括

  • 恆權: 每一位的權重固定;

  • 自反: \(0\)位和\(9\)位, \(1\)位和\(8\)位, \(2\)位和\(7\)位...的編碼為, 逐位相互取反.

十進制 BCD/ 8421碼 5421碼 2421碼 3-excess碼
0 0000 0000 0000 0011
1 0001 0010 0001 0100
2 0010 0010 0010 0101
3 0011 0011 0011 0110
4 0100 0100 0100 0111
5 0101 1000 1011 1000
6 0110 1001 1100 1001
7 0111 1010 1101 1010
8 1000 1011 1110 1011
9 1001 1100 1111 1100

BCD/ 8421碼是恆權碼.

5421碼是恆權碼, 能夠用高權重位表示時用高權重位表示.

2421碼屬於自反碼, 這點可以用於記憶編碼方式. 所以, "5 用 1011 表示, 而不是 0101".

3-excess碼是給BCD/ 8421碼加0011得到的, 這樣做加法時, 十進制表示時有進位, 碼上也會有進位, 得到的是8421碼表示和; 當沒有進位時, 要把和減去6. 余三碼也屬於自反碼.

2.1.2 格雷碼

  • 循環: \(0\)位和\(2^{n-1}\)位相鄰.
  • 反射: 若以最高位\(0\)\(1\)的交界為軸, 低位的代碼是軸對稱的.

格雷碼不屬於十進制的編碼, 它具有循環和反射的特性. 但格雷碼最大的特點在於, 連續的碼字之間只有一個位不同, 這使得它在模數轉換, 信號傳輸等場景中, 具有可靠性. 且只有一位的變化, 能夠避免過渡噪聲, 且避免產生尖峰電流.

一位 二位 三位 四位
0 00 000 0000
1 01 001 0001
11 011 0011
10 010 0010
110 0110
111 0111
101 0101
111 0111
1111
...
  • BCD轉格雷碼

最高位不變, 從最高位開始從左到右每兩位取異或.

  • 格雷碼轉BCD

最高位不變, 從最高位開始從左到右解異或.

異或: 相同取0, 不同取1.

// CPP, Gray Code 和 BCS Code 的相互轉換
// src: https://blog.csdn.net/xiayufeng520/article/details/116752570
#include <iostream>
#include <math.h>
 
int bcd2gray(int bcd) 
{
	return bcd ^ (bcd >> 1);
}
 
int gray2bcd(int gray) 
{
	int bcd = 0x0;
	int size = log2(gray);
 
	bcd |= (1 << size);
	for ( int i = size; i > 0; i--) 
    {
		bcd |= (((bcd >> i) & 0x01) ^ ((gray >> (i - 1)) & 0x01)) << (i-1);
	}
 
	return bcd;
}
 
int main() 
{
	int gray_code = 0x16;
	int bcd_code = 0x16;
	std::cout << bcd2gray(bcd_code) << std::endl;
	std::cout << gray2bcd(gray_code) << std::endl;
 
	return 0x0;
}

2.1.3 檢錯碼和糾錯碼

錯誤 | 轉儲和傳輸過程中, 因噪聲干擾, 粒子幅射. 介質缺損等, 碼元可能出錯\(0\to1\)\(1\to0\)的情況.

一般出現單錯的概率較大.

2.1.3.1 檢錯碼(Error-Detecting Code)_奇偶校驗碼

\(n+1\)位來檢驗\(n\)位編碼的單錯: 碼的前\(n\)位為信息位, 在末尾增加\(1\)個校驗位.

  • 奇校驗碼odd-parity code: 增加一位, 使得整個\(n+1\)位中\(1\)的個數是奇數個
  • 偶校驗碼even-parity code: 增加一位, 使得整個\(n+1\)位中\(1\)的個數是偶數個

作用: 用於檢奇數位錯, 不能糾錯.

2.1.3.2 糾錯碼(Error-Correcting Code_漢明碼

漢明碼是糾錯碼.

其它很多種類的碼詳見數字通信原理, 或者是信息論與編碼等內容.

2.2 字符編碼

Ref: https://www.runoob.com/w3cnote/charset-encoding.html (這里就secondary citation吧)

2.2.1 字符集和字符編碼

  • 字符集Charset

一個系統所支持的所有抽象字符的集合.

  • 字符編碼Character Encoding

一套將字符逐個對應數字碼的規則.

2.2.2 常見字符集和常用編碼

  • ASCII字符集和編碼

American Standard Code for Information Interchange, 美國信息交換標准代碼.

ASCII字符集主要包括控制字符(回車鍵, 退格, 換行鍵等); 可顯示字符(英文大小寫字符, 阿拉伯數字和西文符號)

ASCII編碼使用\(7\)位表示一個字符, 共\(128\)個字符. 為了表示更多的歐洲常用字符, 擴展至\(8\)位, \(127\)位后的符號合稱為EASCII. 此時共\(256\)個字符.

2.2.2.1 GBXXX字符集和編碼

首先出現GB2312編碼, 籠括了大部分常用漢字. 微軟擴充其為GBK編碼. 后來國內進一步擴充至GB 18030-2005.

2.2.2.2 Big5字符集和編碼

使用繁體中文(正體中文)社區中最常用的電腦漢字字符集標准, 也是編碼方式.

2.2.2.3 Unicode字符集和UTF-X編碼

Unicode是一個囊括世界所有字符的字符集. 對於Unicode, 有三種編碼方案, 分別為UTF-32, UTF-16和UTF-8.

  • UTF-32對每個字符使用\(4\)字節進行編碼.

  • UTF-16對每個字符使用\(2\)字節進行編碼, 囊括了UTF-32前\(16\)位常用的字符, 后\(16\)位的字符使用"詭異的方式"實現.

  • UTF-8對每個字符使用變長(\(1\sim4\))字節進行編碼, 其中第\(1\)字節與ASCII兼容. 互聯網工程工作小組(IETF)要求所有互聯網協議都必須支持UTF-8編碼. 但只使用\(1\)字節時,


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM