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ẢIx | ~ 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 = 1
kiể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 00000001
nhị 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 11111111
tươ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ó 0b
một tiền tố trong nghĩa đen. Nếu không có 0b
tiề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 00000000
tươ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 00000001
nhị 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 = 1
là 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 :
- Viết 2 ở dạng nhị phân:
00000010
- Đảo ngược các chữ số. 0 trở thành 1 và 1 trở thành 0:
11111101
- Thêm 1:
11111110
Đó là cách trình biên dịch diễn giải số nhị phân 1111110
dưới dạng -2
thậ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à Int8
kiể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:
VÀ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 & yBits
kế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. 10000011
tươ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 | yBits
kế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ì, 11111111
tươ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:
XORx | 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 yBits
kế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ì, 1111100
tươ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ề 10001000
tương đương với 136
in 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 00000100
nhị phân. Di chuyển nó một chút sang phải, trả về 00000010
tương đương với 2
in 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 11111100
nhị phân. Di chuyển nó một chút sang phải và đặt 1 vào vị trí trống, trả về 11111110
tương đương -2
với Int8
loại. Do đó, print(someBits>> 1)
câu lệnh xuất ra -2 trên màn hình.