Chương 4. LẬP TRÌNH HỢP NGỮ ARM CƠ BẢN
4.4.1. Hệ thống số và bảng mã
Khái niệm
Hệ đếm là một tập các ký hiệu (bảng chữ số) để biểu diễn các số và xác định giá trị của các biểu diễn số. Hệ đếm được chia thành hai loại là hệ đếm theo vị trí và hệ đếm không theo vị trí. Hệ đếm theo vị trí là hệ đếm mà trong đó giá trị số lượng của chữ số còn phụ thuộc vào vị trí của nó đứng trong con số cụ thể. Hệ đếm không theo vị trí là hệ đếm mà trong đó giá trị số lượng của chữ số không phụ thuộc vào vị trí của nó đứng trong con số. Ví dụ, hệ thập phân là hệ đếm theo vị trí và hệ đếm La Mã là một hệ đếm không theo vị trí.
Cơ số của một hệ đếm là số lượng ký tự phân biệt được sử dụng trong một hệ đếm. Các hệ thống số đếm được phân biệt với nhau bằng một cơ số K của hệ đếm đó. Mỗi ký tự biểu diễn một chữ số và giá trị của một chữ số thuộc đoạn [0, B-1].
Ngoài hệ đếm thập phân với B = 10, trong máy tính còn sử dụng một số hệ đếm khác như hệ đếm nhị phân với B = 2, hệ đếm bát phân với B = 8 và hệ đếm thập lục phân với B = 16. Quan hệ giữa các chữ số trong các hệ đếm này được mô tả trong Bảng 4.10. Cơ số và các chữ số trong các hệ đếm này được tổng hợp như sau:
Hệ nhị phân: B = 2, gồm các chữ số 0, 1
Hệ nhị phân: B = 10, gồm các chữ số 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Hệ nhị phân: B = 2, gồm các chữ số 0, 1, 2, 3, 4, 5, 6, 7
Hệ nhị phân: B = 2, gồm các chữ số 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F với A = 10, B = 11, C = 12, D = 13, E = 14, F = 15.
159
Bảng 4.10. Quan hệ giữa các chữ số trong các hệ đếm Thập phân
(DEC) Nhị phân (BIN) Bát phân (OCT)
Thập lục phân (HEX)
0 0000 0 0
1 0001 1 1
2 0010 2 2
3 0011 3 3
4 0100 4 4
5 0101 5 5
6 0110 6 6
7 0111 7 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
Chuyển đổi số
Chuyển đổi số trong hệ cơ số B sang hệ thập phân
Giả sử một số A trong hệ cơ số B được biểu diễn như trong công thức (4.1); giá trị của số trong hệ thập phân sẽ được tính như trong công thức (4.2).
A(B) = (am-1..a0).(a-1a-2..a-n) (4.1) A(10) = am-1×Bm-1 + am-2×Bm-2 + … + a0×B0 + a-1×B-1 + … + a-n×B-n
= ∑ 𝑎𝑖× 𝑏𝑖
𝑚−1
𝑖=−𝑛
(4.2)
Ví dụ 4.24 – Chuyển đổi số Với B = 10 (hệ thập phân):
1999,95(10) = 1×103 + 9×102 + 9×101 + 9×100 + 9×10-1 + 5×10-2
Với B = 16 (hệ thập lục phân):
3FF(16) = 3×162 + 15×161 + 15×160 = 1023(10)
160
Với B = 2 (hệ nhị phân):
1101(2) = 1×23 + 1×22 + 0×21 + 1×20 = 13(10)
Chuyển đổi số trong hệ thập phần 10 sang hệ cơ số B
Để chuyển đổi một số từ cơ số 10 sang cơ số B (B = 2, 8, 16), với phần nguyên ta lấy số trong cơ số10 chia liên tiếp cho B đến khi thương số bằng không thì dừng lại. Kết quả chuyển đổi có được trong hệ đếm cơ số B là tập hợp các số dư của phép chia được viết theo thứ tự ngược lại, nghĩa là số dư đầu tiên có trọng số nhỏ nhất. Với phần thập phân ta nhân liên tiếp với B và tách phần nguyên, đến khi phần thập phân bằng 0 hoặc sau một số bước nhất định (với số thập phân vô hạn);
kết quả phần thập phân trong hệ cơ số B là chuỗi các phần nguyên được sắp xếp thuận, nghĩa là phần nguyên đầu tiên có trọng số lớn nhất.
Ví dụ 4.25 – Chuyển 13 từ hệ 10 sang hệ 2
Hình 4.13: Minh họa chuyển từ số hệ 10 sang hệ 2 Chuyển đổi số từ hệ nhị phân sang hệ cơ số 2K
Số nhị phân được chuyển đổi sang số hệ cơ số 2K theo hai bước: Bước 1 - nhóm các số nhị phân thành từng bộ K bit theo chiều từ phải sang trái với các số đứng trước dấu chấm thập phân và theo chiều từ trái sang phải với các số đứng sau dấu chấm thập phân; Bước 2 - thay các bộ K bit nhị phân thành số tương ứng trong hệ cơ số 2K.
Ví dụ 4.26: Chuyển số nhị phân 1100101010112 về số hệ 16 (24)
Đầu tiên chia số nhị phân thành nhóm 4 bit 11002 = C16 và 10102 = A16, 10112 = B16. Tiếp tục kết hợp 3 số này lại thành một số trong hệ 16 là CAB16. Do đó:
1100101010112 = CAB16
161
Chuyển đổi số từ hệ cơ số 2K sang hệ nhị phân
Số hệ cơ số 2K được chuyển sang số nhị phân theo hai bước: Bước 1 – thay mỗi số trong số hệ cơ số 2K thành bộ 4 bit nhị phân, nếu không đủ K bit thì thêm các bit 0 đứng trước; Bước 2 - thay các bộ K bit nhị phân cho các số trong số hệ cơ số K sẽ được số nhị phân tương ứng.
Ví dụ 4.27: Chuyển số hệ thập lục phân 63F về số nhị phân
Đầu tiên chia từng số trong số hệ 16 ra và chuyển về số nhị phân 616 = 01102 và 316 = 00112, F16 = 11112. Sau đó kết hợp 3 số này lại thành 1 là 0110001111112. Do đó:
63F16 = 0110001111112
Hình 4.14: Minh họa chuyển đổi số giữa hệ 2 và 2K
b) Bảng mã
Mã hóa là gán một ký hiệu cho một đối tượng để thuận tiện cho việc thực hiện một yêu cầu cụ thể nào đó. Một cách toán học, mã hóa là một ánh xạ 1 - 1 từ một tập hợp nguồn vào một tập hợp khác gọi là tập hợp đích.
Hình 4.15: Minh họa ánh xạ 1-1 giữa bộ ký tự và bảng mã
Tập hợp nguồn có thể là tập hợp các số, các ký tự, dấu, các lệnh dùng trong truyền dữ liệu, v.v. và tập hợp đích thường là tập hợp chứa các tổ hợp thứ tự của các số nhị phân.
Một tổ hợp các số nhị phân tương ứng với một số được gọi là từ mã. Tập hợp các từ mã được tạo ra theo một qui luật cho ta một bộ mã. Việc chọn một bộ mã tùy vào mục đích sử dụng.
162
Bảng mã ASCII
ASCII (American Standard Code for Information Interchange) là bộ ký tự và bộ mã ký tự dựa trên bảng chữ cái La Tinh được dùng trong tiếng Anh hiện đại và các ngôn ngữ Tây Âu khác, thường được dùng để hiển thị văn bản trong máy tính và các thiết bị thông tin khác. Mã ASCII cũng được dùng bởi các thiết bị điều khiển làm việc với văn bản.
ASCII chính xác là mã 7-bit, tức là nó dùng kiểu bit biểu diễn với 7 số nhị phân (giá trị thập phân từ 0 đến 127) để biểu diễn thông tin về ký tự. Vào lúc ASCII được giới thiệu, nhiều máy tính dùng nhóm 8-bit (byte hoặc, chuyên biệt hơn, bộ tám) làm đơn vị thông tin nhỏ nhất; bit thứ tám thường được dùng bit chẵn- lẻ (parity) để kiểm tra lỗi trên các đường thông tin hoặc kiểm tra chức năng đặc hiệu theo thiết bị. Các máy không dùng chẵn-lẻ thường thiết lập bit thứ tám là 0 nhưng một số thiết bị như máy PRIME chạy PRIMOS thiết lập bit thứ tám là một. ASCII được công bố làm tiêu chuẩn lần đầu vào năm 1963 bởi Hiệp hội tiêu chuẩn Hoa Kỳ (American Standards Association, ASA), sau này đổi thành ANSI. Có nhiều biến thể của ASCII, hiện tại phổ biến nhất là ANSI X3.4-1986, cũng được tiêu chuẩn hoá bởi Hiệp hội nhà sản xuất máy tính châu Âu (European Computer Manufacturers Association) ECMA-6, ISO/IEC 646:1991 Phiên bản tham khảo quốc tế, ITU- T Khuyến cáo T.50 (09/92), và RFC 20 (Request for Comments). Nó được dùng trong Unicode, một thay thế có thể xảy ra của nó, như là 128 ký tự 'thấp nhất'.
ASCII được xem là tiêu chuẩn phần mềm thành công nhất từng được công bố từ trước tới nay.
- Các ký tự từ 0 đến 32 theo hệ thập phân không thể in ra màn hình. Các ký tự đó chỉ có thể in được trong môi trường dos gồm một số hình như trái tim, mặt cười, hình tam giác, v.v. Một số ký tự đặc biệt khi in ra màn hình sẽ thực hiện lệnh như: kêu tiếng bip với ký tự BEL, xuống hàng với ký tự LF, v.v.
- Trong bảng mã ASCII chuẩn có 128 ký tự. Trong bảng mã ASCII mở rộng có 256 ký tự bao gồm cả 128 ký tự trong mã ASCII chuẩn. Các ký tự sau là các phép toán, các chữ có dấu và các ký tự để trang trí.
163
Hình 4.16: Bảng mã ASCII 7 bit
Hình 4.17: Bảng mã ASCII 8 bit
164
Bảng mã Unicode
Unicode (hay gọi là mã thống nhất) là bộ mã chuẩn quốc tế được thiết kế để dùng làm bộ mã duy nhất cho tất cả các ngôn ngữ khác nhau trên thế giới, kể cả các ngôn ngữ sử dụng ký tự tượng hình phức tạp như tiếng Trung Quốc, tiếng Thái,.v.v.
Vì những điểm ưu việt đó, Unicode đã và đang từng bước thay thế các bộ mã truyền thống, kể cả bộ mã tiêu chuẩn ISO 8859.
Các chương trình 8-bit chỉ nhận biết các ký tự 8 bit, và không thể dùng nhiều hơn 256 điểm mã nếu không có những cách giải quyết đặc biệt. Do đó cần phải đề ra nhiều cơ chế để dùng Unicode tùy thuộc vào khả năng lưu trữ, sự tương thích với chương trình nguồn và sự tương tác với các hệ thống khác.
UTF-32
Cách đơn giản nhất để lưu trữ tất cả các mã Unicode của nhiều ngôn ngữ khác nhau là sử dụng 32 bit cho mỗi ký tự. Cách mã hóa này được Unicode gọi là UTF-32 và ISO/IEC 10646 gọi là UCS-4. Vấn đề chính của cách này là sự tiêu tốn không gian lưu trữ gấp 4 lần so với trước kia, do đó nó ít được dùng trong các vật nhớ ngoài (như đĩa, băng). Tuy nhiên, nó rất đơn giản, nên một số chương trình sẽ sử dụng mã hóa 32 bit bên trong khi xử lý Unicode.
UTF-16
UTF-16 là một cách mã hóa dùng Unicode 20 bit. Các ký tự trong BMP được diễn tả bằng cách dùng giá trị 16-bit của code point trong Unicode CCS. Có hai cách biểu diễn giá trị 16 bit là Big Endian và Litle Endian. Big Endian có nghĩa là cho Most Significant Byte đi trước, tức là nằm bên trái – do đó ta có UTF-16BE.
Còn Little Endian thì ngược lại, tức là Least Significant Byte đi trước – do đó ta có UTF-16LE. Thí dụ, giá trị 16-bit của con số Hex1234 được viết là Hex12 Hex34 trong Big Endian và Hex34 Hex12 trong Little Endian.
Những ký hiệu không nằm trong BMP được biểu diễn bằng cách dùng surrogate pair (cặp thay thế). Code points có giá trị từ U+D800 đến U+DFFF được dành riêng ra để dùng cho mục đích này. Trước hết, một code point có 20 bit được phân ra làm hai nhóm 10 bit. Nhóm Most Significant 10 bit được ánh xạ vào một giá trị 10 bit nằm trong khoảng từ u+D800 đến u+DBFF. Nhóm Least Significant 10 bit được map vào một giá trị 10 bit nằm trong khoảng từ U+DC00 đến U+DFFF. Theo cách đó UTF-16 có thể biểu diễn được những ký hiệu Unicode có 20 bit.
165
Hình 4.18: Bảng mã Unicode
UTF-8
UTF-8 được thiết kế để tương thích với chuẩn ASCII. UTF-8 có thể sử dụng từ một (cho những ký tự trong ASCII) cho đến 6 byte để biểu diễn một ký tự. Chính vì tương thích với ASCII, UTF-8 rất có lợi thế khi được sử dụng để bổ sung hỗ trợ Unicode cho các phần mềm có sẵn. Thêm vào đó, các nhà phát triển phần mềm vẫn có thể sử dụng các hàm thư viện có sẵn của ngôn ngữ lập trình C để so sánh và xếp thứ tự. Ngược lại, để hỗ trợ các cách mã hóa 16 bit hay 32 bit như ở trên, một số lớn phần mềm buộc phải viết lại do đó tốn rất nhiều công sức. Một điểm mạnh nữa của UTF-8 là với các văn bản chỉ có một số ít các ký tự ngoài ASCII, hay thậm chí cho các ngôn ngữ dùng bảng chữ cái Latin như tiếng Việt, tiếng Pháp, tiếng Tây Ban Nha, v.v.; cách mã hóa kiểu này tiết kiệm được nhiều không gian lưu trữ.
166
UTF-8 được thiết kế đảm bảo không có chuỗi byte của ký tự nào lại nằm trong một chuỗi của ký tự khác dài hơn. Điều này khiến cho việc tìm kiếm ký tự theo byte trong một văn bản là rất dễ dàng. Mặc dù để thực hiện điều này đòi hỏi phải có độ dư (văn bản sẽ dài thêm) nhưng những ưu điểm mà nó mang lại vẫn nhiều hơn. Việc nén dữ liệu không phải là mục đích hướng tới của Unicode và việc này cần được tiến hành một cách độc lập.
Các quy định chính xác của UTF-8 như sau (các số bắt đầu bằng 0x là các số biểu diễn trong hệ thập lục phân)
- Các ký tự có giá trị nhỏ hơn 0x80, sử dụng 1 byte có cùng giá trị.
- Các ký tự có giá trị nhỏ hơn 0x800, sử dụng 2 byte: byte thứ nhất có giá trị 0xC0 cộng với 5 bit từ thứ 7 tới 11; byte thứ hai có giá trị 0x80 cộng với các bit từ thứ 1 tới thứ 6.
- Các ký tự có giá trị nhỏ hơn 0x10000, sử dụng 3 byte: byte thứ nhất có giá trị 0xE0 cộng với 4 bit từ thứ 13 tới 16; byte thứ hai có giá trị 0x80 cộng với 6 bit từ thứ 7 tới 12; byte thứ ba có giá trị 0x80 cộng với 6 bit từ thứ 1 tới thứ 6.
- Các ký tự có giá trị nhỏ hơn 0x200000, sử dụng 4 byte: byte thứ nhất có giá trị 0xF0 cộng với 3 bit từ thứ 19 tới 21; byte thứ hai có giá trị 0x80 cộng với 6 bit từ thứ 13 tới 18; byte thứ ba có giá trị 0x80 cộng với 6 bit từ thứ 7 tới thứ 12; byte thứ tư có giá trị 0x80 cộng với 6 bit từ thứ 1 tới thứ 6.
Hiện nay, các giá trị khác ngoài các giá trị trên đều chưa được sử dụng. Tuy nhiên, các chuỗi ký tự dài tới 6 byte có thể được dùng trong tương lai.
- Chuỗi 5 byte sẽ lưu trữ được mã ký tự chứa đến 26 bit: byte thứ nhất có giá trị 0xF8 cộng với 2 bit thứ 25 và 26, các byte tiếp theo lưu giá trị 0x80 cộng với 6 bit có ý nghĩa tiếp theo.
- Chuỗi 6 byte sẽ lưu trữ được mã ký tự chứa đến 31 bit: byte thứ nhất có giá trị 0xFC cộng với bit thứ 31, các byte tiếp theo lưu giá trị 0x80 cộng với 6 bit có ý nghĩa tiếp theo.
Mã BCD
Trực tiếp liên quan đến mạch số (bao gồm các hệ thống sử dụng số) là các số nhị phân nên mọi thông tin dữ liệu dù là số lượng, các chữ, các dấu, các mệnh lệnh sau cùng cũng phải ở dạng nhị phân thì mạch số mới hiểu ra và xử lý được. Do đó phải có quy định cách thức mà các số nhị phân được dùng để biểu thị các dữ liệu khác nhau, kết quả là có nhiều mã số (gọi tắt là mã) được dùng. Trước tiên mã số thập phân thông dụng nhất là mã BCD (Binary Coded Decimal: mã số thập phân
167
được mã hóa theo nhị phân). Sự chuyển đổi thập phân sang BCD và ngược lại gọi là mã hoá và sự lặp mã. Các số thập phân từ 0 đến 9 bởi số nhị phân 4 bit có giá trị như trong Bảng 4.11.
Bảng 4.11. Mã BCD của các chữ số thập phân
Chữ số thập phân Mã BCD
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
Chuyển đổi số thập phân sang mã BCD và ngược lại
Mã BCD phải được viết đủ 4 bit và sự tương ứng chỉ được áp dụng cho số thập phân từ 0 đến 9, nên số nhị phân từ 1010 (= 1010) đến 1111 (= 1510) của số nhị phân 4 bit không phải là mã BCD.
Ví dụ 4.28 – Chuyển đổi các số thập phân sang mã BCD và ngược lại Ðổi 48910 sang mã BCD:
Đổi 53710 sang mã BCD:
168
Đổi 00110100100101012 (BCD) sang số thập phân: