Số âm trong Python nhị phân

Trong phần trước về biểu diễn và thao tác nhị phân, chúng ta chỉ thảo luận về số nguyên dương và số không. Số âm làm phức tạp mọi thứ một chút

Biểu diễn số nguyên âm

Chúng ta nên biểu diễn -1 ở dạng nhị phân như thế nào?

Dấu và độ lớn. Có vẻ như là một ý tưởng tốt vào thời điểm đó

Một cách tiếp cận đơn giản là đặt trước một chữ số nhị phân làm bit dấu. Ví dụ: trong số nguyên 8 bit, 10000001 có thể biểu thị -1 và 10000101 có thể biểu thị -5
Đó gọi là biểu diễn dấu và độ lớn. Nó đơn giản, nhưng nó có một số vấn đề

Trong biểu diễn dấu và độ lớn, chúng tôi kết thúc bằng 00000000 cho số không dương và 10000000 cho số không âm. Nhưng… thực sự, số 0 âm? . Và nó làm

Từ quan điểm của một nhà thiết kế máy tính, việc biểu diễn dấu và độ lớn làm tăng thêm rất nhiều sự phức tạp cho mạch điện cần thiết cho số học. Hãy xem xét điều đó bằng cách nào đó khi chúng ta thêm \[00000001_2\] [1] và \[10000001_2\] [-1] chúng ta sẽ nhận được \[00000000_2\] [0]. Mạch cộng các số nguyên dương sẽ không làm được điều đó, vì vậy mạch có mục đích đặc biệt cho số học trên các số âm sẽ được yêu cầu. Các nhà thiết kế chip ghét điều đó

Một đại diện mà các nhà thiết kế chip có thể hài lòng với việc thêm ít phức tạp nhất có thể vào mạch CPU. Việc cộng một số âm với một số dương hoặc một số âm với một số âm sẽ hoạt động giống hệt như cộng hai số dương. Điều này đưa chúng ta đến ký hiệu bổ sung của hai

phần bù của hai. Một cách tốt hơn

Biểu diễn cho các số âm thực sự được sử dụng trong hầu hết các máy tính kỹ thuật số hiện đại là phần bù của hai. Trong ký hiệu này, biểu diễn 8 bit của -1 là 11111111 và biểu diễn 8 bit của 1 tất nhiên là 00000001. Nếu chúng ta thêm chúng, chúng ta sẽ “mang một” đến chữ số thứ 9 [không tồn tại], nơi nó bị mất và chúng ta nhận được 00000000. Phép cộng và phép trừ có thể thực hiện theo cách thông thường, không có trường hợp đặc biệt nào đối với số âm

Bản chất của biểu diễn bù hai là, trong khi giá trị của chữ số \[p\] thường là \[2^p\], thì giá trị của chữ số ngoài cùng bên trái là \[-2^p\]

Trong số nguyên có dấu 8 bit, bit 7 đại diện cho \[-[2^7]\] hoặc -128. Do đó, số 8 bit có dấu 10000110 là \[-[2^7] + 2^2 + 2^1\] = -128 + 4 + 2 = -122

Chúng tôi đã nói ở trên rằng đại diện 8 bit của -1 sẽ là 11111111. Chúng ta có thể thấy rằng điều này là do bit ngoài cùng bên trái [vẫn được gọi là bit dấu] đại diện cho -128 và các bit còn lại đại diện cho 127, do đó, chúng cùng nhau đại diện cho -1

Kiểm tra việc hiểu của bạn

Nếu 11111111 là -1, biểu diễn của -2 là gì?

Phạm vi giá trị nào có thể được biểu thị bằng một số nguyên 8 bit bằng cách sử dụng ký hiệu bổ sung của hai?

Python 'bin' nói dối về số âm

Nếu bạn dựa vào hàm bin của Python để kiểm tra biểu diễn nhị phân của số nguyên, bạn sẽ gặp sự cố. Hàm bin của Python sử dụng ký hiệu dấu và độ lớn, không phải phần bù hai, để biểu thị một số nguyên âm dưới dạng một chuỗi gồm các ký tự 01. Bằng cách này, hàm bin của Python luôn có thể tạo ra một chuỗi bắt đầu bằng ký tự 1, ngoại trừ giá trị nhị phân 0. Nó không cần hiển thị các số 0 đứng đầu trên một số nguyên dương và nó không cần hiển thị một chuỗi dài các ký tự 1 cho một số nguyên âm nhỏ

>>> bin[-1]
'-0b1'
>>> bin[-2]
'-0b10'

Điều này thường thuận tiện, đặc biệt khi xem xét biểu diễn bên trong thực của âm trong Python có khả năng bắt đầu với ít nhất 31 bit 1. Tuy nhiên, nó có thể gây hiểu lầm khi bạn đang cố gắng suy luận cẩn thận về biểu diễn thực tế của các số âm.

mở rộng dấu hiệu

Lưu ý rằng khi chúng ta mô tả biểu diễn của một số nhị phân âm, chúng ta cần cho biết có bao nhiêu bit trong biểu diễn. Biểu diễn của -1 dưới dạng số nguyên có dấu 8 bit là 11111111, nhưng biểu diễn của -1 dưới dạng số nguyên có dấu 16 bit là 1111111111111111. Tôi không muốn nhập biểu diễn của -1 dưới dạng số nguyên có dấu 32 bit hoặc dưới dạng số nguyên có dấu 64 bit, nhưng bạn có thể đoán nó trông như thế nào

Giả sử chúng ta có số nguyên có dấu 3 bit. Khi đó 101 đại diện cho \[-2^2 + 2^0\] = -4 + 1 = -3. Giả sử tôi muốn lưu trữ cùng một giá trị này trong một số nguyên có chữ ký 5 bit. Giá trị mới sẽ trở thành 11101, nghĩa là -16 + 8 + 4 + 1 = -3

Bạn có thể thấy mô hình. Nếu chúng ta muốn lưu trữ một giá trị n-bit đã ký trong trường m-bit lớn hơn, chúng ta phải thêm 1 chữ số vào bên trái. Tổng quát hơn, những gì chúng ta đệm bằng là bit dấu. Do đó, số âm 3 bit 101 được đệm vào số âm 5 bit 11101, trong khi số dương 3 bit 011 được đệm vào số dương 5 bit 00011

Điều này được gọi là mở rộng dấu hiệu

Nếu chúng ta đi theo cách khác, chúng ta chỉ cần cắt các bit ở bên trái, cho dù chúng là 0 hay 1. Nếu các bit chúng tôi cắt bỏ không giống nhau và giống với bit dấu còn lại, thì số đó không vừa với trường nhỏ hơn

Đóng gói và trích xuất các trường bit

Khi chúng ta đóng gói nhiều giá trị vào một số nguyên, chúng ta phải cẩn thận xác định xem giá trị đó có được hiểu là số nguyên có dấu trong đó bit ngoài cùng bên trái là bit dấu, biểu thị lũy thừa âm 2 hay một số nguyên không dấu trong đó tất cả các

Giả sử chúng ta sử dụng bốn bit, bit 0. 3, để đại diện cho một số nguyên. Chúng tôi có thể coi trường đó là một số nguyên không dấu có thể nằm trong khoảng từ 0 đến 15 hoặc chúng tôi có thể coi nó là một số nguyên có dấu có thể nằm trong khoảng từ -8 đến 7. Nếu chúng ta coi nó là một số nguyên không dấu, thì việc tạo mặt nạ và dịch chuyển có thể hoạt động chính xác như được mô tả trong chương trước, nhưng chúng ta không thể biểu diễn các giá trị âm. Nếu coi nó là số nguyên có dấu thì khi giải nén ta phải thêm bước mở rộng có dấu

Để đóng gói một giá trị đã ký vào một trường, chúng ta không cần phải làm bất cứ điều gì đặc biệt ngoại trừ đảm bảo che dấu giá trị để cắt bỏ bất kỳ bit 1 thừa nào ở bên trái. Ví dụ: nếu chúng tôi muốn lưu trữ giá trị 3 bit có dấu x trong bit 3. 5 của

x_masked = x & 0b111
x_shifted = x_masked 

Chủ Đề