Giáo trình Toán rời rạc
Trang 13 Biểu diễn số nguyên trong máy tính.
Trong máy tính mọi dữ liệu đều được lưu trữ bằng các tín hiệu nhị phân Mô hình toán học tương ứng cho cách lưu trữ đó là số học hệ đếm nhị phân Trong hệ đếm này các dữ liệu được biểu diễn bằng một dãy các số 0 và 1 Hơn nữa tài nguyên của máy tính là hữu hạn, các thanh ghi của bộ xử lí hay chiều dài mỗi đơn vị bộ nhớ là hữu hạn, vì vậy ta chỉ xét đến cách biểu diễn số bằng các thanh ghi có chiều dài hữu hạn mà thôi Mặt khác với cùng một biểu diễn nhị phân, các cách xử lí khác nhau đối với biểu diễn này sẽ cho ý nghĩa dữ liệu khác nhau Ví dụ: Trong máy tính biểu diễn 0100 0001 có thể là số thập phân 65 hay là kí tự ‘A’
tuỳ theo cách xử lí đối với biểu diễn này Từ đó ta có khái niệm “Kiểu dữ liệu – Data type”:
Một kiểu dữ liệu là một cách biểu diễn dữ liệu trong máy tính đi kèm với phương thức mà máy tính xử lí cách biểu diễn đó.
Để dễ dàng cho việc lập luận, sau đây ta giả sử dữ liệu được biểu diễn bằng một thanh ghi 4 bit trong một máy tính giả định
Kiểu số nguyên không dấu:
Trước tiên ta xem xét cách biểu diễn số nguyên trong hệ thập phân (Decimal system) Trong hệ thống này ta dùng 10 kí hiệu 0,1,2,3,4,5,6,7,8,9 và cách ghi theo thứ tự các chữ số để biểu diễn giá trị số đó Ví dụ:
= 7.104 + 5.103 + 6.102+ 8.101+ 9.100
Tổng quát ta có:
0 1 2 3 2 n 1 n
n a a a a a a
n 0 i
i
i.10
a trong đó: i=0 n : ai
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9
Với cùng nguyên tắc biểu diễn đó, trong hệ nhị phân (Binary system) ta chỉ dùng 2 kí hiệu 0,1 để biểu diễn số nguyên như sau:
0 1 2 3 2 n 1 n
n a a a a a a
n 0 i
i
i.2
a ) dec trong đó: i=0 n : ai 0 , 1 Vậy trong hệ này, ta có:
101110bin =1.25 + 0.24 + 1.23 + 1.22 + 1.21 + 0.20
dec = (32+0+8+4+2+0)dec=46dec.
Khác với biểu diễn số nguyên trong toán học, trong máy tính ta chỉ có thể dùng các thanh ghi với độ dài hữu hạn để biểu diễn số nên phạm vi số nguyên biểu diễn được là hữu hạn Chẳng hạn với thanh ghi 4 bit ta chỉ có thể biểu diễn được các số:
Một cách tổng quát với n bit thì có thể biểu diễn 2n số nguyên không dấu trong phạm vi từ số 0 đến 2n-1 dec
Trang 2 Kiểu số nguyên có dấu:
Chúng ta biết rằng các phép toán cơ bản +, - ,* , div đối với số nguyên trong số học đều có chung một tính chất hết sức quan trọng là chúng đều “đóng kín” đối với các phép toán đó
Nghĩa là với hai số nguyên a và b bất kì ta đều có a+b, a-b, a.b, a div b đều là các số nguyên.
Với cách biểu diễn số nguyên không dấu trong máy tính như trên tính “đóng kín” không còn bảo toàn được nữa, chẳng hạn:
- Tràn số : 7dec+10dec=0111bin+1010bin= ? bin (Tràn số Không thể biểu diễn được với 4 bit)
- Không có cách biểu diễn: 7 dec – 10 dec = ? (Số âm)
Vấn đề tràn số không thể giải quyết được trừ khi phải mở rộng độ dài thanh ghi Chẳng hạn, vì
215 –1 = 32767 < 60032 < 216 –1 = 65535 nên muốn biểu diễn số 60032dec ít nhất chiều dài của thanh ghi phải là 16 bit Nếu không mở rộng thanh ghi (nghĩa là chuyển sang một kiểu dữ liệu khác) kết quả tính toán có thể đem lại nhiều bất ngờ Sử dụng lại ví dụ trên ta thấy phép cộng:
+
cho kết quả của phép cộng là: 0001 (Không đúng!)
Về vấn đề số âm :
Để khảo sát số âm trước hết chúng ta khảo sát phép trừ Sử dụng cách trừ như thông thường với phép trừ thực hiện lần lượt từ cột bên phải qua ta thấy rằng khi ta trừ 1 cho 0 ta được 1, trừ
1 cho 1 ta được 0 còn khi trừ 0 cho 1 ta cần “mượn” 1 từ cột kế cận bên trái là cột mà quá trình tính toán chưa xét tới Việc mượn 1 từ cột kế bên trái này có thể gây ra mượn dây chuyền từ cột này qua các cột kế tiếp về phía bên trái
Các ví dụ sau đây cho ta thấy quá trình đó đã lan truyền như thế nào:
Số phải nhớ đem từ cột bên phải qua
Số này không thuộc thanh ghi
Trang 3quả Kết
trừ Số
trừ bị
Số
trái cột bên
từ
Mượn
0 1 0
1 1 0
1 0 1 1
1 1 0
1 0 0
0 0 1
1 1
1 1 0
1 1 0
0 1 1
1 1
Một mặt thực hiện phép toán trừ như vậy gây ra rất nhiều bất tiện Mặt khác khi phép trừ cho một kết quả âm buộc ta phải định nghĩa một kiểu dữ liệu có thể biểu diễn được số nguyên âm
Ta có thể biểu diễn số âm bằng cách dùng 1 bit tận cùng bên trái của thanh ghi làm bit dấu Theo qui ước nếu bit này bằng 0 thì đây là số dương và nếu bit này bằng 1 thì đây là số âm Ví dụ 0101bin là số +5 còn 1111bin là số –7 Tuy nhiên khi đó thực hiện phép trừ giữa hai số “đại số” A và B đòi hỏi một qui tắc trừ khá phức tạp vì cùng lúc phải xét đến dấu của A, B và độ lớn tương đối giữa A và B chưa kể đến việc phải thiết kế một mạch điện tử riêng biệt dùng để thực hiện phép trừ Câu hỏi đặt ra là có thể nào chỉ cần thiết kế một mạch điện tử dùng được cho cả hai phép toán cộng và trừ Câu trả lời là có thể
Nhưng trước hết ta hãy quan sát ví dụ sau đây trong hệ thập phân, trong đó ta đã thay việc thực hiện quá trình làm toán trừ bằng một quá trình “cộng” tương đương:
9
0
1
9
4
3
8
5
4
được thay bằng
9 0 1
9 0 1 1
1
0 5 6
8 5 4
Ta thấy rằng, thay vì trừ cho 349 ta đã cộng 458 với 650 là số bù 9 của số 349, rồi lại cộng với
1 để được kết quả 1109 Kết quả này bỏ đi số 1 tận cùng bên trái sẽ được 109 là kết quả của phép trừ Kết quả này chắc đúng vì ta có đẳng thức:
y - x = y+(10k – x) – 10k =y+[ (10k –1) –x] + 1 – 10k Số hạng 10k – 1 luôn luôn có dạng 99 9 vì vậy phép trừ [ (10k –1) –x] =[99 9 – x] luôn luôn dễ thực hiện bằng cách lấy số bù 9 của từng số hạng biểu diễn x mà không phải “mượn” gì cả! Còn việc bỏ đi số hạng cuối cùng chẳng qua là lấy kết quả sau khi cộng với số bù 10 trừ đi cho
10k Việc khử đi vị trí “dư” này trong máy tính tương đương với việc tràn số ở bit tận cùng bên trái
Từ nhận xét trên ta có thể nói số bù 10: (651) chính là số âm (-349) với điều kiện khi cộng với (651) phải khử đi bit cuối cùng về bên trái
Và cũng từ nhận xét trên ta có thể định nghĩa số có dấu x như sau: Cho một số nguyên có biểu
diễn nhị phân x, số có dấu của x, kí hiệu (-x), chính là số bù 2 của x (ie: 2n – x) Để tính được số bù 2 của x chỉ cần tính số bù 1 của x rồi cộng thêm 1
Sau khi đã bỏ số 1 tận cùng bên trái
Trang 4Ví dụ: x = 5dec = 0101bin
Khi đó ta có: (-x) = 1011bin
Thử lại: 0101
+ 1011
1 0000
Bảng sau đây cho thấy quan hệ giữa các số bù 2 khi dùng 4 bit để biểu diễn số nguyên:
Kiểu
dữ
liệu
có dấu
Kiểu dữ liệu
Đối chiếu trong bảng trên ta thấy cùng dùng 4 bit để biểu diễn số thì kiểu dữ liệu số nguyên không dấu có phạm vi biểu diễn từ 0 đến 15 trong khi kiểu dữ liệu số nguyên có dấu có phạm
vi biểu diễn từ -7 đến +8 Cùng một biểu diễn 1100 có thể là +12 nhưng cũng có thể là (-4) tuỳ theo kiểu dữ liệu được quan niệm eg: 1010 + 0010 = 1100 có thể quan niệm là:
10 + 2 =12 (Kiểu số nguyên không dấu) hoặc: -6 +2 = -4 (Kiểu số nguyên có dấu)
Mặc dù kích thước lưu trữ dữ liệu như nhau nhưng cách xử lí dữ liệu với mỗi kiểu dữ liệu là
Số 1 này bị tràn khỏi thanh ghi
Trang 5 Cộng/Trừ số nguyên với số bù 2:
Khi biểu diễn số nguyên dưới dạng số bù 2 chúng ta có thể thực hiện các phép toán cộng và trừ như bình thường Ví dụ:
5dec – 3dec = 0101bin + 1101bin = 0010bin= +2dec
-5dec + 3dec = 1011bin + 0011bin = 1110bin= -2dec
-5dec - 2dec = 1011bin + 1110bin = 1001bin = -7dec
5dec + 4dec = 0101bin + 0100bin = 1001bin = -7dec
Dòng cuối cùng cho kết quả sai vì vượt quá phạm vi biểu diễn (từ -7 đến +8)
4 Biểu diễn số thực trong máy tính:
Có thể hiện thực số thực trong máy tính bằng một trong hai cách :
Biểu diễn theo kiểu dấu chấm tĩnh (fixed point representation):
Giả sử ta dùng một thanh ghi 16 bit để biểu diễn số thực như sau:
16 bit
0 1 1 1 0 1 0 1 1 1 1 1 0 0 1 1
6 bit
(Biểu diễn theo kiểu dấu chấm tĩnh trong bộ nhớ số + 111010111.110011)
Với qui ước như trong hình trên thì số thực dương lớn nhất và nhỏ nhất có thể biểu diễn được là:
(Maximum) 111111111.111111bin = (29-1).(1-2 - 6)dec
= 511.984375dec
(Minimum) 000000000.000001bin = 2-6 = 0.015625dec
Với cách hiện thực này ta gặp phải mấy vấn đề sau:
i) Không thể biểu diễn số thực khác 0 có giá trị tuyệt đối nhỏ hơn 0.015625
ii) Không thể biểu diễn số thực có giá trị tuyệt đối lớn hơn 511.984375
iii) Mật độ biểu diễn số thực: Giữa hai số thực bất kì x và y (x y) luôn tồn tại một số
thực khác (eg: (x+y)/2) cho dù x có gần y đến thế nào đi nữa, ie: số số thực tồn tại giữa x và y
là vô hạn Giữa hai số thực 0 và 511.984375 là vô hạn các số thực có giá trị trung gian, nhưng theo cách biểu diễn trên giữa số 0 và số 511.984375 chỉ có thể hiện thực đúng 215 = 65535 số thực không âm khác nhau Nói cách khác độ chính xác của số được biểu diễn bị ảnh hưởng nghiêm trọng!
Trang 6Biểu diễn theo kiểu dấu chấm động (floating point representation):
Trong ba vấn nạn trên thì vấn nạn cuối cùng không thể giải quyết được vì thuộc bản chất hữu hạn của biểu diễn số trong máy tính (và chỉ có thể bỏ qua bằng cách chấp nhận khả năng làm tròn số mà thôi!) Hai vấn nạn đầu tiên liên quan đến phạm vi biểu diễn số có thể giải quyết được phần nào bằng một trong hai cách:
a) Tăng kích thước thanh ghi: Biện pháp này không đem lại nhiều hiệu quả Không cải thiện được bao nhiêu phạm vi biểu diễn số
b) Nếu tách vấn đề độ chính xác ra khỏi bài toán biểu diễn số thì theo kí pháp khoa học (scientific notation) quen thuộc mỗi số thực n đều có thể viết dưới dạng:
n = f x 10e
trong đó f là phân số (fraction) hoặc là phần định trị (mantissa) còn e là số nguyên (âm hay dương) gọi là phần mũ (exponent).
Ví dụ: -3.14 = (-0.314) x 101
0.00001 = 0.001x10-2 = 0.1 x 10-4
1941 = 0.194100 x 104
Ta nhận thấy rằng bằng cách di động dấu chấm thập phân đồng thời thay đổi phần mũ bao giờ cũng có thể (chuẩn hoá) làm cho phần định trị, về giá trị tuyệt đối, nhỏ hơn hẳn 1 và lớn hơn hay bằng 0.1 (Vì vậy có tên biểu diễn theo dấu chấm động – floating point representation) Khi đó số lượng chữ số có trong phần định trị quyết định độ chính xác còn số lượng chữ số có trong phần mũ quyết định phạm vi biểu diễn số
Trong hệ đếm nhị phân ta cũng có cách biểu diễn hoàn toàn tương tự:
Số nhị phân: (1011.0101bin) x 2 7 có thể viết lại thành (0.10110101bin) x 211 Phần định trị là 0.10110101bin và phần mũ là 1011bin
Vì vậy có thể chọn cách biểu diễn bên trong máy tính như sau:
Dấu chấm nhị phân giả định Bit dấu của phần định trị Bit dấu của phần mũ
(Biểu diễn của số thực: 0.10110101 E +001011 Số 0 đầu tiên của phần định trị không cần phải được biểu diễn trong thanh ghi)
0 1 0 1 1 0 1 0 1 0 0 0 1 0 1 1
Trang 7(Maximum) 0.1111 1111 E 0 111111 = (1 –2-8)x(22 1)dec 263
dec
(Minimum) 0.1000 0000 E 1 111111 = (2-1)x(2 - (26 1
))dec 2-64
dec
Độ chính xác và phạm vi biểu diễn số thực đã tăng lên rất nhiều so với cách biểu diễn theo dấu chấm tĩnh1 Dĩ nhiên cái giá phải trả ở đây là sự phức tạp về tính toán sẽ tăng lên so với biểu diễn bằng dấu chấm tĩnh
Các phép toán số học với kiểu biểu diễn bằng dấu chấm động:
Phép cộng: Để thực hiện được phép cộng hai số thực biểu diễn theo dấu chấm động trước
tiên cần làm cho phần mũ của hai số giống nhau
Ví dụ:
Cộng x = 0.111010010E0101010 với y = 0.110101101E0100101 Hiệu hai phần mũ của x và y là:101010 – 100101 = 000101 = 5dec Vậy x > y.
Ta cần hiệu chỉnh y bằng cách dồn phần định trị của y 5 bước về bên phải (shift right) và tăng phần mũ của y cho khớp với phần mũ của x.
x = 0.1 1 1 0 1 0 0 1 0 E 0101010
y = 0.0 0 0 0 0 1 1 0 1 E 0101010 x+y = 0.1 1 1 0 1 1 1 1 1 E 0101010
Ví dụ:
x = 0.1 1 0 1 1 0 1 1 1 E 0110110
y = 0.1 1 1 0 1 1 0 1 1 E 0110110 x+y = 1.1 1 0 0 1 0 0 1 0 E 0110110
= 0.1 1 1 0 0 1 0 0 1 E 0110111 Kết quả ở dòng thứ ba có phần định trị lớn hơn 1 nên cần phải chuẩn hoá để được dạng biểu diễn đúng như trong dòng thứ tư
Phép trừ: Phép trừ được thực hiện bằng cách sử dụng số bù 2
Ví dụ:
x = 0.101010101E0001010
y = 0.100010110E0000110 Tìm x-y ?
Vì 0001010 – 0000110 = 0000100 (= 4dec) nên x > y Ta cần hiệu chỉnh y trước khi cộng
x với phần bù 2 của y.
= 0.000010001E0001010
1 Các thảo luận đầy đủ hơn về biểu diễn số thực theo kiểu dấu chấm động cũng như tiêu chuẩn công
nghiệp IEEE 754 về dấu chấm động có thể tìm đọc trong:Cấu trúc máy tính nâng cao – VN-GUIDE – NXB Thống
Trang 8Phần bù 2 của y là:
(-y) = 0.111101111E0001010
x = 0.101010101E0001010
+(-y) = 0.111101111E0001010
Kết quả: x-y = 1.101000100E0001010
= 0.110100010E0001011
Phép nhân: Thực hiện phép nhân bằng cách nhân hai phần định trị và cộng hai số mũ Sau
khi thực hiện xong thì chuẩn hoá phần định trị và điều chỉnh số mũ
Ví dụ:
x = 0.110101010E0010110
y = 0.110000000E0000101
x x y = 0.100111111E0011011
Ví dụ:
x = 0.101011001E01101101
y = 0.101000000E01111100
x x y = 0.110101111 E11101001 (Tràn số)
(Kết quả cuối cùng bị sai vì vượt quá giới hạn biểu diễn của phần mũ)
Phép chia: Thực hiện bằng cách chia phần định trị của x cho y Trừ phần định trị của x cho y
Ví dụ:
(x/y) = 0.110000000E0010000