Toán tử bổ sung bitwise (~ tilde) hoạt động như thế nào?


Câu trả lời:


281

Hãy nhớ rằng các số âm được lưu trữ dưới dạng bổ sung của hai đối tác dương. Ví dụ, đây là biểu diễn của -2 trong phần bù hai: (8 bit)

1111 1110

Cách bạn có được điều này là bằng cách lấy biểu diễn nhị phân của một số, lấy phần bù của nó (đảo ngược tất cả các bit) và thêm một số. Hai bắt đầu là 0000 0010 và bằng cách đảo ngược các bit, chúng tôi nhận được 1111 1101. Thêm một cho chúng tôi kết quả ở trên. Bit đầu tiên là bit dấu, ngụ ý âm.

Vì vậy, hãy xem làm thế nào chúng ta nhận được ~ 2 = -3:

Đây là hai lần nữa:

0000 0010

Đơn giản chỉ cần lật tất cả các bit và chúng tôi nhận được:

1111 1101

Chà, -3 trông như thế nào trong phần bổ sung của hai? Bắt đầu với số dương 3: 0000 0011, lật tất cả các bit thành 1111 1100 và thêm một bit để trở thành giá trị âm (-3), 1111 1101.

Vì vậy, nếu bạn chỉ cần đảo ngược các bit trong 2, bạn sẽ có đại diện bổ sung của hai là -3.

Toán tử bổ sung (~) JUST FLIPS BITS. Nó phụ thuộc vào máy để giải thích các bit này.


43
Một điều khác có thể được đề cập là lật được gọi là bổ sung 1s, trước khi thêm 1.
Chris S

3
Nó có thể giúp những người khác không biết về Bổ sung của Một và Bổ sung của Hai. Đọc về họ ở đây. vi.wikipedia.org/wiki/Ones%27_compuity en.wikipedia.org/wiki/Two%27s_compuity
Sai

1
Không phải đó là toán tử bitwise KHÔNG?
Braden hay nhất

3
Làm thế nào để máy biết rằng nó đang nhận được một số âm hai bổ sung thay vì số dương cao hơn? Có phải vì hệ thống loại của ngôn ngữ tương ứng chỉ ra rằng loại đó là ký hiệu int so với không dấu?
GL2014

@ GL2014 Tôi nghĩ bạn đã trả lời câu hỏi của riêng bạn ở đó. Theo hiểu biết của tôi, đó là cách máy được thiết kế để hoạt động ngay từ đầu.
geekidharsh

40

~ lật các bit trong giá trị.

Tại sao ~2-3đã làm với bao số được biểu diễn trên bit. Các số được biểu diễn dưới dạng bổ sung của hai .

Vì vậy, 2 là giá trị nhị phân

00000010

Và ~ 2 lật các bit để giá trị bây giờ là:

11111101

Trong đó, là biểu diễn nhị phân của -3.


2
Không phải là 11111101 == thập phân 253 so với -3?
AKS

10
Phụ thuộc nếu nó đại diện cho một số nguyên có dấu hoặc không dấu.
driis

18

Như những người khác đã đề cập, ~chỉ lật các bit (thay đổi một thành 0 và 0 thành một) và vì hai phần bù được sử dụng, bạn nhận được kết quả mà bạn đã thấy.

Một điều cần nói thêm là tại sao hai phần bù được sử dụng, điều này là do các phép toán trên số âm sẽ giống như trên số dương. Hãy nghĩ về -3số 3cần được thêm vào để có số 0 và bạn sẽ thấy số này là 1101, hãy nhớ rằng phép cộng nhị phân giống như trường tiểu học (số thập phân) chỉ bạn mang theo một khi bạn lên hai chứ không phải 10 .

 1101 +
 0011 // 3
    =
10000
    =
 0000 // lose carry bit because integers have a constant number of bits.

Vì vậy 1101được -3, lật các bit bạn nhận được 0010mà là hai.


8

Hoạt động này là một bổ sung, không phải là một phủ định.

Hãy xem xét rằng ~ 0 = -1, và làm việc từ đó.

Thuật toán cho phủ định là "bổ sung, tăng dần".

Bạn có biết không? Ngoài ra còn có "phần bù của một" trong đó các số nghịch đảo đối xứng và nó có cả 0 và -0.


6

Tôi biết câu trả lời cho câu hỏi này được đăng lại từ lâu, nhưng tôi muốn chia sẻ câu trả lời của mình cho cùng.

Để tìm phần bù của một số, trước tiên hãy tìm tương đương nhị phân của nó. Ở đây, số thập phân 2được biểu diễn dưới dạng 0000 0010nhị phân. Bây giờ lấy phần bổ sung của nó bằng cách đảo ngược (lật tất cả 1 thành 0 và tất cả 0 thành 1) tất cả các chữ số của biểu diễn nhị phân của nó, điều này sẽ dẫn đến:

0000 0010 → 1111 1101

Đây là phần bù của một số thập phân 2. Và vì bit đầu tiên, tức là bit dấu là 1 trong số nhị phân, có nghĩa là dấu này âm đối với số được lưu. (ở đây, số được gọi là không 2 mà là phần bù của 2).

Bây giờ, vì các số được lưu dưới dạng phần bù 2 (lấy phần bù của một số cộng với một), do đó, để hiển thị số nhị phân này 1111 1101, thành số thập phân, trước tiên chúng ta cần tìm phần bù 2 của nó, sẽ là:

1111 1101 → 0000 0010 + 1 → 0000 0011

Đây là phần bổ sung của 2. Biểu diễn thập phân của số nhị phân 0000 0011, là 3. Và, vì bit dấu là một như đã đề cập ở trên, vì vậy câu trả lời kết quả là -3.

Gợi ý: Nếu bạn đọc quy trình này một cách cẩn thận, thì bạn sẽ nhận thấy rằng kết quả cho toán tử bổ sung của một người thực sự là số (toán hạng - trên đó toán tử này được áp dụng) cộng với một dấu có dấu âm. Bạn có thể thử điều này với các số khác quá.


Tại sao nó thêm hai lần? Tôi đang nhìn thấy add, flip, add. 0010-> 0011-> 1100->1101
Braden hay nhất

1
Đó là lật, lật, thêm. Lần đầu tiên cho phần bổ sung của 1. Và vì, nó được lưu trong phần bù 2 trong hệ thống, khi bạn cần hiển thị số, nó sẽ hiển thị phần bù 2 của số được lưu (nghĩa là lật thứ hai và thêm).
Himanshu Aggarwal

Nhưng sẽ không lật (lật (2)) chỉ là 2? 0010 1101 0010
Braden hay nhất

Có nó sẽ là 2 thôi. Nhưng vì khi các bit được lưu trữ trong bộ nhớ, bit đáng kể nhất là 1 sẽ làm cho số âm sau này như được giải thích trong câu trả lời ở trên.
Himanshu Aggarwal

1
Từ những gì bạn đang mô tả và tất cả mọi thứ tôi đã nghiên cứu, đây không phải là phần bù hai, mà là phần bổ sung "thông thường", hoặc một chút KHÔNG. Trong logic, NOT 0 = 1NOT 1 = 0. Trong hệ thống bốn bit, NOT 0011(3) = 1100(12 không dấu, -4 đã ký). Theo những gì tôi hiểu, phần bù của hai được định nghĩa là (NOT n) + 1và được sử dụng để tìm đối tác âm của một số bất kể số bit. Như vậy , 2c(5) = -5. Xem, bây giờ nó có ý nghĩa hoàn hảo. Chỉ cần bạn gọi thao tác này là gì: một chút KHÔNG.
Braden hay nhất

4

int a = 4; System.out.println (~ a); Kết quả sẽ là: -5

'~' của bất kỳ số nguyên nào trong java đại diện cho phần bù 1 của số không. ví dụ tôi đang lấy ~ 4, có nghĩa là trong biểu diễn nhị phân 0100. đầu tiên, độ dài của một số nguyên là bốn byte, tức là 4 * 8 (8 bit cho 1 byte) = 32. Vì vậy, trong bộ nhớ hệ thống 4 được biểu thị là 0000 0000 0000 0000 0000 0000 0000 0100 bây giờ ~ toán tử sẽ thực hiện bổ sung 1 trên nhị phân trên

tức là 1111 1111 1111 1111 1111 1111 1111 1011-> 1 'bổ sung cho bit quan trọng nhất đại diện cho dấu không (hoặc - hoặc +) nếu là 1 thì ký là' - 'nếu là 0 thì ký là' + 'theo kết quả của chúng tôi là một số âm, trong java các số âm được lưu trữ ở dạng bổ sung của 2, kết quả thu được chúng tôi phải chuyển đổi thành phần bù 2 (đầu tiên thực hiện phần bù 1 và chỉ cần thêm phần bù 1). tất cả một số sẽ trở thành số không, ngoại trừ bit 1 có ý nghĩa nhất (là đại diện ký hiệu của chúng tôi cho số đó, có nghĩa là 31 bit 1111 1111 1111 1111 1111 1111 1111 1011 (kết quả thu được của ~ toán tử) 1000 0000 0000 0000 0000 0000 0000 0100 (bổ sung 1)

1 (bổ sung 2)

1000 0000 0000 0000 0000 0000 0000 0101 bây giờ kết quả là -5 hãy xem liên kết này cho video <[Bit toán tử khôn ngoan trong java] https://youtu.be/w4pJ4cGwe9Y


2

Đơn giản ...........

Khi bổ sung 2 cho bất kỳ số nào, chúng ta có thể tính bằng cách đảo ngược tất cả 1 đến 0 và ngược lại so với chúng ta thêm 1 vào số đó ..

Ở đây N = ~ N tạo ra kết quả - (N + 1) luôn. Bởi vì hệ thống lưu trữ dữ liệu dưới dạng bổ sung 2, có nghĩa là nó lưu trữ ~ N như thế này.

  ~N = -(~(~N)+1) =-(N+1). 

Ví dụ::

  N = 10  = 1010
  Than ~N  = 0101
  so ~(~N) = 1010
  so ~(~N) +1 = 1011 

Bây giờ điểm là từ nơi Minus đến. Ý kiến ​​của tôi là giả sử chúng ta có thanh ghi 32 bit, nghĩa là 2 ^ 31 -1 bit có liên quan đến hoạt động và để nghỉ một bit thay đổi trong tính toán trước đó (bổ sung) được lưu trữ dưới dạng bit dấu thường là 1 bit. Và chúng tôi nhận được kết quả là ~ 10 = -11.

~ (-11) = 10;

Điều trên là đúng nếu printf ("% d", ~ 0); ta được kết quả: -1;

Nhưng printf ("% u", ~ 0) so với kết quả: 4294967295 trên máy 32 bit.


1

Toán tử bổ sung Bitwise (~) là một đơn vị .

Nó hoạt động theo các phương pháp sau

Đầu tiên, nó chuyển đổi số thập phân đã cho thành nhị phân tương ứng Trong trường hợp 2, trước tiên, nó chuyển đổi 2 thành 0000 0010 (thành số nhị phân 8 bit).

Sau đó, nó chuyển đổi tất cả 1 trong số thành 0 và tất cả các số 0 thành 1, sau đó số sẽ trở thành 1111 1101.

đó là đại diện bổ sung của 2 -3.

Để tìm giá trị không dấu bằng cách sử dụng bổ sung, tức là chỉ cần chuyển đổi 1111 1101 thành thập phân (= 4294967293), chúng ta chỉ cần sử dụng% u trong khi in.


1

Tôi nghĩ đối với hầu hết mọi người, phần nhầm lẫn xuất phát từ sự khác biệt giữa số thập phân và số nhị phân đã ký, vì vậy hãy làm rõ trước:

đối với thế giới thập phân của con người: 01 có nghĩa là 1, -01 có nghĩa là -1, đối với thế giới nhị phân của máy tính: 101 có nghĩa là 5 nếu không được ký. 101 có nghĩa là (-4 + 1) nếu được ký trong khi chữ số được ký ở vị trí x. | x

vì vậy bit lật của 2 = ~ 2 = ~ (010) = 101 = -4 + 1 = -3 sự nhầm lẫn xuất phát từ việc trộn lẫn kết quả đã ký (101 = -3) và kết quả không mong muốn (101 = 5)


1

tl; dr ~ lật các bit. Kết quả là dấu hiệu thay đổi. ~2là số âm ( 0b..101). Để xuất một số rubyin âm -, sau đó bổ sung hai ~2:-(~~2 + 1) == -(2 + 1) == 3 . Số dương là đầu ra.

Có một giá trị nội bộ và biểu diễn chuỗi của nó. Đối với các số nguyên dương, về cơ bản chúng trùng khớp:

irb(main):001:0> '%i' % 2
=> "2"
irb(main):002:0> 2
=> 2

Cái sau tương đương với:

irb(main):003:0> 2.to_s
"2"

~lật các bit của giá trị nội bộ. 20b010. ~20b..101. Hai dấu chấm ( ..) đại diện cho vô số 1's. Vì bit có ý nghĩa nhất (MSB) của kết quả là 1, kết quả là số âm ( (~2).negative? == true). Để xuất một số rubyin âm -, sau đó bổ sung hai giá trị nội bộ. Bổ sung của hai được tính bằng cách lật các bit, sau đó thêm 1. Bổ sung của hai 0b..1013. Như vậy:

irb(main):005:0> '%b' % 2
=> "10"
irb(main):006:0> '%b' % ~2
=> "..101"
irb(main):007:0> ~2
=> -3

Để tổng hợp nó, nó lật các bit, làm thay đổi dấu hiệu. Để xuất ra một số âm nó in -, sau đó ~~2 + 1( ~~2 == 2).

Lý do tại sao rubyxuất ra các số âm như vậy, là vì nó coi giá trị được lưu trữ là phần bù hai của giá trị tuyệt đối. Nói cách khác, những gì được lưu trữ là 0b..101. Đó là một số âm, và như vậy nó là phần bổ sung của hai giá trị x. Để tìm x, nó bổ sung hai 0b..101. Đó là hai phần bù của hai phần bù của x. Đó là x(ví dụ ~(~2 + 1) + 1 == 2).

Trong trường hợp bạn áp dụng ~cho một số âm, nó chỉ lật các bit (tuy nhiên thay đổi dấu):

irb(main):008:0> '%b' % -3
=> "..101"
irb(main):009:0> '%b' % ~-3
=> "10"
irb(main):010:0> ~-3
=> 2

Điều khó hiểu hơn là ~0xffffff00 != 0xff(hoặc bất kỳ giá trị nào khác với MSB bằng 1). Hãy đơn giản hóa nó một chút : ~0xf0 != 0x0f. Đó là bởi vì nó được coi 0xf0là một số dương. Mà thực sự có ý nghĩa. Vì vậy, ~0xf0 == 0x..f0f. Kết quả là một số âm. Bổ sung của hai 0x..f0f0xf1. Vì thế:

irb(main):011:0> '%x' % ~0xf0
=> "..f0f"
irb(main):012:0> (~0xf0).to_s(16)
=> "-f1"

Trong trường hợp bạn sẽ không áp dụng toán tử bitwise cho kết quả, bạn có thể xem xét ~như một -x - 1toán tử:

irb(main):018:0> -2 - 1
=> -3
irb(main):019:0> --3 - 1
=> 2

Nhưng đó được cho là không sử dụng nhiều.

Một ví dụ Giả sử bạn được cung cấp một mặt nạ mạng 8 bit (để đơn giản) và bạn muốn tính số lượng 0. Bạn có thể tính toán chúng bằng cách lật các bit và gọi bit_length( 0x0f.bit_length == 4). Nhưng ~0xf0 == 0x..f0f, vì vậy chúng tôi phải cắt bỏ các bit không cần thiết:

irb(main):014:0> '%x' % (~0xf0 & 0xff)
=> "f"
irb(main):015:0> (~0xf0 & 0xff).bit_length
=> 4

Hoặc bạn có thể sử dụng toán tử XOR ( ^):

irb(main):016:0> i = 0xf0
irb(main):017:0> '%x' % i ^ ((1 << i.bit_length) - 1)
=> "f"

0

Đầu tiên chúng ta phải chia chữ số đã cho thành chữ số nhị phân của nó và sau đó đảo ngược nó bằng cách thêm vào chữ số nhị phân cuối cùng. Sau khi thực hiện, chúng ta phải đưa ra dấu ngược lại với chữ số trước mà chúng ta đang tìm thấy sự tuân thủ ~ 2 = -3 Giải thích : Dạng nhị phân của 2s là 00000010 thay đổi thành 11111101, đây là dạng bổ sung, sau đó được khen 00000010 + 1 = 00000011 là dạng nhị phân của ba và với -e Ie, -3


0

Toán tử bit-khôn ngoan là một toán tử đơn nguyên hoạt động theo phương pháp ký hiệu và cường độ theo kinh nghiệm và kiến ​​thức của tôi.

Ví dụ ~ 2 sẽ cho kết quả là -3.

Điều này là do toán tử bit-bit trước tiên sẽ đại diện cho số có dấu và cường độ là 0000 0010 (toán tử 8 bit) trong đó MSB là bit dấu.

Sau đó, nó sẽ lấy số âm 2 là -2.

-2 được biểu thị bằng 1000 0010 (toán tử 8 bit) theo dấu và độ lớn.

Sau đó, nó thêm 1 vào LSB (1000 0010 + 1) cung cấp cho bạn 1000 0011.

Đó là -3.


0

Javascript dấu ngã (~) ép buộc một giá trị nhất định cho phần bù của một người - tất cả các bit được đảo ngược. Đó là tất cả dấu ngã. Đó không phải là ý kiến. Nó không thêm hay bớt bất kỳ số lượng nào.

0 -> 1
1 -> 0
...in every bit position [0...integer nbr of bits - 1]

Trên các bộ xử lý máy tính để bàn tiêu chuẩn sử dụng các ngôn ngữ cấp cao như JavaScript, số học có chữ ký BASE10 là phổ biến nhất, nhưng hãy nhớ, đây không phải là loại duy nhất. Các bit ở cấp độ CPU có thể được giải thích dựa trên một số yếu tố. Ở cấp độ 'mã', trong trường hợp này là JavaScript, chúng được hiểu là số nguyên có chữ ký 32 bit theo định nghĩa (chúng ta hãy bỏ qua phần nổi này). Hãy coi nó là lượng tử, 32 bit đó đại diện cho nhiều giá trị có thể cùng một lúc. Nó phụ thuộc hoàn toàn vào ống kính chuyển đổi mà bạn xem chúng thông qua.

JavaScript Tilde operation (1's complement)

BASE2 lens
~0001 -> 1110  - end result of ~ bitwise operation

BASE10 Signed lens (typical JS implementation)
~1  -> -2 

BASE10 Unsigned lens 
~1  -> 14 

Tất cả những điều trên là đúng cùng một lúc.


0

Về cơ bản hành động là một bổ sung không phải là một phủ định.

Ở đây x = ~ x tạo kết quả - (x + 1) luôn.

x = ~ 2

- (2 + 1)

-3

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.