Trong toán học, các số âm (bất kể thuộc hệ cơ số nào) đều được biểu diễn bằng cách thông thường là đặt trước số dương tương ứng một dấu "−" (trừ). Ví dụ: với hệ thập phân, số nguyên âm năm được biểu diễn là −5. Tuy nhiên, trong máy tính, khi mọi ký hiệu, con số,... đều được biểu diễn dưới hệ nhị phân thông qua hai chữ số 0 và 1 thì mọi chuyện lại trở nên phức tạp hơn.
Có nhiều cách được sử dụng để biểu diễn số âm trong máy tính. Bài này chỉ giới thiệu bốn phương pháp chủ yếu nhất, đó là: phương pháp dấu lượng (sign-and-magnitude), bù 1, bù 2 và số quá N (excess-N).
Các máy tính hiện nay hầu hết đều sử dụng phương pháp biểu diễn số bù 2. Tuy nhiên, trong vài tình huống, các phương pháp khác vẫn có thể được sử dụng.
Phương pháp dấu lượng dùng bit cực trái làm bit dấu (sign bit) – tức đại diện cho dấu của số – theo quy ước: nếu bit dấu là 1 thì số là số âm (1 tương đương với dấu "-"), ngược lại, nếu nó là 0 thì số là số dương (0 tương đương với dấu "+"). Các bit còn lại được dùng để biểu diễn độ lớn của số (hay giá trị tuyệt đối – absolute value – của số).
Để biểu diễn một số âm về dạng nhị phân có dấu với mẩu K bit là lấy số cần biểu diễn cộng thêm 2K-1 sau đó biểu diễn chúng ở hệ nhị phân
Theo phương pháp này, một byte 8 bit sẽ có 7 bit (trừ đi bit dấu) được dùng để biểu diễn cho các số có giá trị từ 0000000 (010) đến 1111111 (12710). Khi sử dụng bit dấu, ý nghĩa của 7 bit trên sẽ thay đổi, và ta có thể biểu diễn các số từ −12710 đến +12710. Trong phương pháp dấu lượng, số 0 có thể được biểu diễn ở hai dạng, đó là 00000000 (+0) và 10000000 (−0).
Ví dụ: giả sử mẫu 8 bit, khi sử dụng phương pháp dấu lượng, số 510 được biểu diễn sang hệ nhị phân là: 0000 0101, còn số −5 là 1000 0101.
So sánh với cách biểu diễn số âm mà ta thường sử dụng, ta thấy phương pháp dấu lượng có nhiều điểm tương đồng. Trong hệ thập phân, khi muốn biểu diễn số có dấu, ta đặt dấu cần biểu diễn ngay trước giá trị tuyệt đối của số. Phương pháp dấu lượng cũng đặt dấu ngay trước giá trị tuyệt đối của số, chỉ có khác ở chỗ thay dấu "+" bằng "0" và "−" bằng "1". Có lẽ vì sự tương đồng này, một vài máy tính thế hệ đầu tiên (như IBM 7090) đã sử dụng phương pháp dấu lượng khi biểu diễn số âm.
Phương pháp bù 1 biểu diễn số âm theo cách sau:
Như vậy, phương pháp bù 1 hoàn toàn giống như phương pháp dấu lượng, duy chỉ khác ở cách biểu diễn độ lớn của số.
Ví dụ: dạng bù 1 của 00101011 (43) là 11010100(−43) (xem bài chính về bù 1 để biết cách biểu diễn số thập phân sang nhị phân bằng phương pháp bù 1).
Giống phương pháp dấu lượng, một byte 8 bit áp dụng phương pháp bù 1 cũng có thể biểu diễn các số từ −12710 đến +12710 (chú ý: đã mất đi một bit dùng làm bit dấu). Bù 1 cũng có hai dạng biểu diễn cho số 0, bao gồm: 00000000 (+0) và 11111111 (−0) (mẫu 8 bit).
Khi thực hiện phép cộng giữa hai số biểu diễn theo phương pháp bù 1, ta cũng thực hiện theo quy tắc cộng nhị phân thông thường, tuy nhiên, sau khi đã thực hiện xong, nếu còn phát sinh bit nhớ thì phải tiếp tục cộng bit nhớ này vào kết quả vừa thu được. Về vấn đề này, xin xem thêm ở bài chính về bù 1.
Phương pháp biểu diễn số bù 1 được sử dụng rộng rãi trong các thế hệ máy tính cũ, điển hình là các dòng máy PDP-1 và UNIVAC 1100/2200.
Trong phương pháp bù 2, các số âm được biểu diễn giống như phương pháp bù 1, tuy nhiên, phải cộng thêm 1 vào kết quả (ở hệ nhị phân).
Ví dụ: số −510 được biểu diễn sang hệ nhị phân (xét mẫu 8 bit) sử dụng phương pháp bù 1 là 11111010. Để biểu diễn theo phương pháp bù 2, ta cộng thêm 1 vào số nhị phân ở bù 1, tức cộng 1 cho 11111010: 11111010 + 1 = 11111011. Vậy 11111011 là biểu diễn bằng bù 2 của −510 trong máy tính.
Phương pháp biểu diễn số bù 2 ra đời khi người ta gặp vấn đề với hai phương pháp dấu lượng và bù 1, đó là:
Với phương pháp bù 2, số 0 chỉ có một cách biểu diễn duy nhất là 00000000 (mẫu 8 bit). Việc đổi dấu một số – kể cả từ âm sang dương hay từ dương sang âm – đều được thực hiện theo cùng một cách, đó là: đảo tất cả các bit rồi cộng thêm một vào kết quả. Việc thực hiện phép cộng với số biểu diễn theo phương pháp bù 2 được thực hiện hoàn toàn giống như cộng hai số nhị phân bình thường, tuy nhiên, khi phát sinh bit nhớ ở bit dấu, ta có thể bỏ nó đi. Về vấn đề này, xin xem thêm ở bài chính về bù 2.
Với mẫu 8 bit, phương pháp bù 2 có thể biểu diễn tốt các số nguyên có giá trị từ −12810 đến +12710 (so với từ −12710 đến +12710 theo phương pháp dấu lượng và bù 1) do được lợi từ việc tiết kiệm được một cách biểu diễn số 0 (không phân biệt giữa −0 và +0).
Phương pháp biểu diễn số quá N – còn được gọi là biểu diễn số dịch (biased representation) – sử dụng một số nguyên N cho trước làm giá trị dịch ("dịch" hiểu nôm na theo nghĩa "sự dịch chuyển" hay "sự thiên lệch"). Theo phương pháp này, một giá trị thập phân (tức giá trị cần biểu diễn) sẽ được biểu diễn bằng dạng nhị phân của một số dương nào đó sao cho, giá trị của số dương này lớn hơn giá trị cần biểu diễn N đơn vị.
Ví dụ: giả sử cần biểu diễn giá trị 210 theo số quá 5 (mẫu 8 bit):
Vậy 210 sẽ được biểu diễn bằng dạng nhị phân của 7: 00000111.
Theo ví dụ trên, ta sẽ có bảng sau:
Số thập phân cần biểu diễn | Giá trị thập phân của số quá 5 | Do đó, số thập phân sẽ được biểu diễn thành |
---|---|---|
−5 | 0 | 00000000 |
−4 | 1 | 00000001 |
−3 | 2 | 00000010 |
−2 | 3 | 00000011 |
−1 | 4 | 00000100 |
0 | 5 | 00000101 |
1 | 6 | 00000110 |
2 | 7 | 00000111 |
3 | 8 | 00001000 |
4 | 9 | 00001001 |
5 | 10 | 00001010 |
6 | 11 | 00001011 |
7 | 12 | 00001100 |
8 | 13 | 00001101 |
9 | 14 | 00001110 |
10 | 15 | 00001111 |
Ta thấy, 0 được biểu diễn bằng nhị phân của 5, và −5 được biểu diễn bằng nhị phân của 0. Tổng quát, 0 được biểu diễn bằng nhị phân của N, còn −N được biểu diễn bằng mẫu có tất cả các bit đều là 0.
Phương pháp này ngày nay còn được sử dụng rộng rãi để biểu diễn các số chấm động (floating point number), tiêu biểu là chuẩn số chấm động IEEE. Theo chuẩn này, các số chấm động có độ chính xác đơn (single-precision) 32 bit (như kiểu float
của Java) có phần mũ (chính là số lượng ký số của phần nằm sau dấu chấm thập phân) được biểu diễn bằng số quá 127 với mẫu 8 bit, và các số chấm động có độ chính xác đôi (double-precision) 64 bit (như kiểu double
của Java) có phần mũ biểu diễn bằng số quá 1023 với mẫu 11 bit.