Toán tử Swift Bitwise và Bit Shift (Có Ví dụ)

Trong hướng dẫn này, bạn sẽ tìm hiểu về các thao tác bitwise khác nhau trong Swift. Chúng được sử dụng để tính toán mức bit trong một biểu thức.

Một bit được sử dụng để biểu thị một chữ số nhị phân. Một chữ số nhị phân có thể có hai giá trị có thể là 0 hoặc 1. Là một lập trình viên cấp độ mới bắt đầu, bạn không cần phải làm việc với các phép toán ở cấp độ bit.

Làm việc với các kiểu dữ liệu nguyên thủy như: integer, float, boolean, string, v.v. là đủ. Bạn có thể cần phải làm việc ở cấp độ bit khi bạn đang xử lý lập trình cấp thấp.

Swift cung cấp một tập hợp các toán tử phong phú, ngoài các toán tử cơ bản, để thao tác các bit. Các toán tử này tương tự như các toán tử logic, ngoại trừ chúng hoạt động trên các biểu diễn nhị phân của dữ liệu (bit).

Toán tử bitwise là toán tử được sử dụng để thay đổi các bit riêng lẻ của một toán hạng. Toán hạng là một biến hoặc hằng số trong đó phép toán được thực hiện.

Tất cả các toán tử bitwise có sẵn trong nhanh chóng được liệt kê dưới đây:

1. Không phải toán tử Bitwise

Nó được biểu diễn bằng dấu ngã ~và có thể được áp dụng trên một toán hạng duy nhất. Điều này đảo ngược tất cả các bit. tức là thay đổi 1 thành 0 và 0 thành 1.

Nếu x là một biến / hằng số có giá trị nhị phân tức là 0 hoặc 1. Thao tác bitwise not trên biến x có thể được biểu diễn trong bảng dưới đây:

KHÔNG PHẢI
x ~ x
0 1
1 0

Ví dụ 1: Toán tử KHÔNG theo bit cho số nguyên không dấu

 let initalNumber:UInt8 = 1 let invertedNumber = ~initalNumber print(invertedNumber) 

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 254

Trong chương trình trên, câu lệnh let initalNumber:UInt8 = 1kiểu Unsigned int có kích thước 8 bit. Vì vậy, 1 trong số thập phân có thể được biểu diễn dưới dạng 00000001nhị phân.

Toán tử bitwise not thay đổi tất cả các bit của một biến hoặc hằng số, bit 0 được thay đổi thành 1 và 1 thành 0. Vì vậy, invertedNumber chứa các bit 11111110. Sau khi chuyển đổi nó thành số thập phân, nó được biểu diễn là 254. Vì vậy, câu lệnh print(invertedNumber)xuất ra 254 trên màn hình.

Bạn cũng có thể thực hiện toán tử bitwise trực tiếp trong các bit như:

Ví dụ 2: Toán tử KHÔNG theo bit theo bit

 let initialBits: UInt8 = 0b11111111 let invertedBits = ~initialBits print(invertedBits) 

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 0

ban đầu chứa giá trị nhị phân 11111111tương ứng với 255 trong hệ thập phân. Để biểu diễn số trong hệ nhị phân, chúng ta có 0bmột tiền tố trong nghĩa đen. Nếu không có 0btiền tố, nó sẽ coi nó như một số nguyên bình thường và bạn sẽ gặp lỗi tràn (UInt8 chỉ có thể lưu trữ các số từ 0 đến 255).

Vì chúng tôi đã sử dụng toán tử bitwise not, nó thay đổi tất cả từ 1 thành 0. Vì vậy, hằng số invertedBits chứa 00000000tương đương với 0 in UInt8.

Ví dụ 3: Toán tử Bitwise NOT cho số nguyên có dấu

 let initalNumber:Int = 1 let invertedNumber = ~initalNumber print(invertedNumber) 

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 -2

Trong chương trình trên, 1 trong số thập phân có thể được biểu diễn dưới dạng 00000001nhị phân. Toán tử bitwise not thay đổi tất cả các bit của một biến hoặc hằng số, bit 0 được thay đổi thành 1 và 1 thành 0. Vì vậy, invertedNumber chứa các bit 11111110. Điều này sẽ xuất ra 254 trên màn hình. Nhưng thay vào đó trả về -2. Lạ nhỉ ?? Hãy cùng khám phá bên dưới làm thế nào điều này xảy ra.

let initalNumber:Int = 1là một int có dấu có thể chứa cả số nguyên dương và âm. Đó là lý do tại sao khi chúng tôi áp dụng toán tử not cho số nguyên có dấu, số nhị phân trả về cũng có thể đại diện cho một số âm.

Làm thế nào trình biên dịch giải thích -2 như 11111110 trong nhị phân?

Trình biên dịch đã sử dụng phần bổ sung của Two để biểu diễn các số nguyên. Để nhận được ký hiệu âm phần bù của hai số nguyên, trước tiên bạn nên viết số dưới dạng nhị phân, sau đó đảo ngược các chữ số và thêm một vào kết quả.

Các bước tìm phần bù -2 của Hai :

  1. Viết 2 ở dạng nhị phân: 00000010
  2. Đảo ngược các chữ số. 0 trở thành 1 và 1 trở thành 0:11111101
  3. Thêm 1: 11111110

Đó là cách trình biên dịch diễn giải số nhị phân 1111110dưới dạng -2thập phân. Tuy nhiên, có một chút thay đổi mà trình biên dịch thực hiện mà chúng tôi không nhận thấy. Nó cũng suy ra kiểu invertedNumber là Int8kiểu.

Để hiểu điều này, hãy xem một ví dụ dưới đây:

 print(Int8(bitPattern: 0b11111110)) print(0b11111110)

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 -2 254

Trong ví dụ trên, trình biên dịch đã xử lý số nhị phân thành -2 ở dạng thập phân chỉ cho Số nguyên 8 bit đã ký. Do đó câu lệnh print(Int8(bitPattern: 0b11111110))xuất ra -2 trên màn hình.

Nhưng đối với kiểu số nguyên bình thường có kích thước là 32/64 bit và có thể chứa các giá trị lớn, nó diễn giải giá trị là 254. Do đó, câu lệnh print(0b11111110)xuất ra 254 trên màn hình.

2. Toán tử VÀ Bitwise

Nó được đại diện bởi &và có thể được áp dụng trên hai toán hạng. Toán tử AND so sánh hai bit và trả về 1 nếu cả hai bit là 1, ngược lại trả về 0.

Nếu x và y là biến / hằng số có giá trị nhị phân tức là 0 hoặc 1. Phép toán Bitwise AND trên x và y có thể được biểu diễn trong bảng dưới đây:

x y x & y
0 0 0
0 1 0
1 1 1
1 0 0

Ví dụ 5: Phép toán Bitwise AND

 let xBits = 0b10000011 let yBits = 0b11111111 let result = xBits & yBits print("Binary:",String(result, radix: 2)) print(result)

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 Nhị phân: 10000011 131 

Trong chương trình trên, câu lệnh let result = xBits & yBitskết hợp các bit của hai toán hạng xBits và yBits. Nó trả về 1 nó cả hai bit là 1 nếu không nó trả về 0.

String(value , radix: )bộ khởi tạo được sử dụng để biểu diễn số trong hệ thống số khác nhau. Nếu chúng ta cung cấp giá trị cơ số 2. Nó sẽ chuyển đổi số thành hệ thống số nhị phân. Tương tự, chúng ta có thể sử dụng 16 cho hex và 10 cho thập phân.

Câu lệnh print("Binary:",String(result, radix: 2))xuất ra Binary: 10000011 trên màn hình. 10000011tương đương với 131 trong hệ thập phân, câu lệnh print(result)xuất ra 131 trong bảng điều khiển.

3. Toán tử HOẶC Bitwise

Nó được biểu diễn như |và có thể được áp dụng trên hai toán hạng. Toán tử OR bitwise so sánh hai bit và tạo ra kết quả là 1 nếu một hoặc nhiều đầu vào của nó là 1 nếu không thì 0.

Nếu x và y là biến / hằng số có giá trị nhị phân tức là 0 hoặc 1. Phép toán Bitwise OR trên x và y có thể được biểu diễn trong bảng dưới đây:

HOẶC LÀ
x y x | y
0 0 0
0 1 1
1 1 1
1 0 1

Ví dụ 6: Phép toán Bitwise OR

 let xBits = 0b10000011 let yBits = 0b11111111 let result = xBits | yBits print("Binary:", String(result, radix: 2)) print(result) 

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 Nhị phân: 11111111 255 

Trong chương trình trên, câu lệnh let result = xBits | yBitskết hợp các bit của hai hằng số xBits và yBits. Nó trả về 1 nếu bất kỳ bit nào là 1, ngược lại nó trả về 0.

Câu lệnh print("Binary:",String(result, radix: 2))xuất ra Binary: 11111111 trên màn hình. Vì, 11111111tương đương với 255ở dạng thập phân, câu lệnh print(result)xuất ra 255 trên màn hình.

4. Toán tử XOR Bitwise

Nó được biểu diễn như ^và có thể được áp dụng trên hai toán hạng. Toán tử XOR so sánh hai bit và tạo ra kết quả là 1 nếu chính xác một trong các đầu vào của nó là 1 nếu không thì trả về 0.

Nếu x và y là biến / hằng số giữ giá trị nhị phân tức là 0 hoặc 1. Phép toán Bitwise XOR trên x và y có thể được biểu diễn trong bảng dưới đây:

XOR
x y x y
0 0 0
0 1 1
1 1 0
1 0 1

Ví dụ 7: Phép toán Bitwise XOR

 let xBits = 0b10000011 let yBits = 0b11111111 let result = xBits yBits print("Binary:", String(result, radix: 2)) print(result) 

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 Nhị phân: 1111100 124 

Trong chương trình trên, câu lệnh let result = xBits yBitskết hợp các bit của hai hằng số xBits và yBits. Nó trả về 1 nếu chính xác một trong các bit là 1, ngược lại nó trả về 0.

Câu lệnh print("Binary:",String(result, radix: 2))xuất ra Binary: 1111100 (tương đương với 01111100) trên màn hình. Vì, 1111100tương đương với 124ở dạng thập phân, câu lệnh print(result)xuất ra 124 trên màn hình.

5. Toán tử Bitwise Shift

Toán tử này được sử dụng để di chuyển tất cả các bit trong một số sang trái hoặc phải theo một số vị trí nhất định và có thể được áp dụng cho toán hạng đơn. Nó được đại diện là <<hoặc >>.

Có hai loại điều hành ca:

Toán tử dịch trái bitwise

  • Được biểu thị là <<
  • Nó làm cho các bit bị dịch chuyển sang trái được chỉ định bởi số theo sau <<.
  • Các vị trí bit đã bị bỏ trống bởi hoạt động shift sẽ được điền bằng không.
  • Dịch chuyển các bit của số nguyên sang trái theo một vị trí sẽ làm tăng gấp đôi giá trị của nó

Ví dụ 8: Toán tử dịch trái bitwise

 let someBits:UInt8 = 0b11000100 print(someBits << 1) 

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 136

Trong chương trình trên, chúng ta đã sử dụng toán tử dịch trái. Sử dụng <<1 có nghĩa là để dịch chuyển bit 1 sang trái. Các chữ số được chuyển sang bên trái một vị trí và chữ số cuối cùng bên phải được điền bằng số 0.

Bạn cũng có thể thấy chữ số được dịch chuyển "ra khỏi đầu" từ phía bên trái bị mất. Nó không quấn quanh một lần nữa từ bên phải. Dịch chuyển nó sang trái một bit sẽ xóa số 1 khỏi hệ nhị phân và thêm số 0 ở bên phải để lấp đầy giá trị đã dịch chuyển cũng như phần còn lại của các bit khác được dịch chuyển sang vị trí bên trái 1.

Điều này trả về 10001000tương đương với 136in UInt8. Do đó, print(someBits << 1)câu lệnh xuất ra 136 trên màn hình.

Toán tử dịch chuyển phải bitwise

  • Được biểu thị là >>
  • Nó làm cho các bit được dịch chuyển sang phải bởi số theo sau là >>
  • Đối với các số không có dấu, các vị trí bit đã bị bỏ trống bởi hoạt động shift sẽ được điền bằng không.
  • Đối với các số có dấu (số cũng có thể là số âm), bit dấu được sử dụng để điền vào các vị trí bit còn trống. Nói cách khác, nếu số dương, 0 được sử dụng, và nếu số âm, 1 được sử dụng.
  • Dịch chuyển nó sang phải một vị trí làm giảm một nửa giá trị của nó.

Ví dụ 9: Toán tử dịch chuyển sang phải theo bit cho số nguyên không dấu

 let someBits: UInt8 = 4 print(someBits>> 1) 

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 2

Trong chương trình trên, chúng ta đã sử dụng toán tử dịch phải trên một số nguyên không dấu. Sử dụng >>1 có nghĩa là chuyển bit 1 sang phải. Các vị trí bit đã bị bỏ trống bởi hoạt động shift luôn được điền bằng 0 trên một số nguyên không dấu.

Vì, 4 được biểu diễn dưới dạng 00000100nhị phân. Di chuyển nó một chút sang phải, trả về 00000010tương đương với 2in UInt8. Do đó, print(someBits>> 1)câu lệnh xuất ra 2 trên màn hình.

Ví dụ 10: Toán tử dịch chuyển sang phải theo bit cho số nguyên có dấu

 let someBits:Int = -4 print(someBits>> 1) 

Khi bạn chạy chương trình trên, kết quả đầu ra sẽ là:

 -2

Trong chương trình trên, chúng ta đã sử dụng toán tử dịch phải trên một số nguyên không dấu. Không giống như số dương, sử dụng >>cho số âm, số 1 được dùng để điền vào chỗ trống, thay vì số 0.

Kể từ, -4được biểu diễn dưới dạng 11111100nhị phân. Di chuyển nó một chút sang phải và đặt 1 vào vị trí trống, trả về 11111110tương đương -2với Int8loại. Do đó, print(someBits>> 1)câu lệnh xuất ra -2 trên màn hình.

thú vị bài viết...