Tại sao, $ $ ((~ 33)) sản xuất -34?


12
$ echo $(( 255 ))
255
$ echo $(( 33 ))
33
$ echo $(( ~33 ))
-34
$ echo $(( ~255 ))
-256
$ 

và hạt nhân của tôi là:

$ uname -a
Linux HOSTNAME 3.2.0-40-generic-pae #64-Ubuntu SMP Mon Mar 25 21:44:41 UTC 2013 i686 i686 i386 GNU/Linux

HỎI: ~ là để phủ định số AFAIK. Nhưng tại sao ~33sản xuất -34và tại sao ~255sản xuất -256?


2
Bitwise phủ định, không nên nhầm lẫn với số học phủ định ( -x )
chepner

Câu trả lời:


21

Trang người đàn ông của bash nói:

   ! ~    logical and bitwise negation

Số đã ký thường được lưu trữ trong biểu diễn bổ sung của Two :

...
-4 = 1100
-3 = 1101
-2 = 1110
-1 = 1111
 0 = 0000
 1 = 0001
 2 = 0010
 3 = 0011
...

Điều này có nghĩa là nếu bạn lấy một số như 2 thì nó được hiểu theo chiều bit là 0010. Sau khi phủ định bitwise, nó trở thành 1101, là đại diện của -3.


10

Đây là kết quả của số học bổ sung của hai.

~là một phủ định bitwise đảo ngược tất cả các bit được vận hành theo. Số học bổ sung của hai hoạt động bằng cách đảo ngược tất cả các bit và thêm 1. Vì bạn chỉ lật các bit, nhưng không thêm một bit, bạn nhận được cùng một số, đảo ngược, trừ đi một.

Wikipedia có một bài viết hay về bổ sung của hai ở đây .

Ví dụ:

  • 3 trong nhị phân là 0011
  • -3 trong nhị phân (hai phần bù) là 1101
  • Đảo ngược 0011mang lại cho bạn 1100, đó là -4, vì bạn chưa thêm 1.

3

Toán tử ~ là toán tử bitwise NOT. Sử dụng nó không giống như phủ định một số.

Từ wikipedia , thao tác KHÔNG theo bit bằng với lấy phần bù của hai giá trị trừ đi một:

KHÔNG x = −x - 1

Phủ định một số nhị phân tương đương với việc lấy giá trị hai phần bù của nó.

Sử dụng toán tử ~ NOT = lấy giá trị một bổ sung của nó.

Nói một cách đơn giản hơn, ~ chỉ cần lật tất cả các bit của biểu diễn nhị phân .

Ví dụ của bạn:

33 (thập phân) = 0x00100001 (nhị phân 8 bit)

~ 33 = ~ 0x00100001 = 0x11011110 = -34 (thập phân)

Hoặc trong các số học thập phân, sử dụng công thức ~ x = -x - 1:

~ 33 = -33 - 1 = -34

~ 255 = -255 - 1 = -256


1

Vấn đề là ~ là một toán tử khôn ngoan. Do đó bạn đang phủ nhận nhiều bit hơn bạn có thể dự định. Bạn có thể thấy điều này tốt hơn bằng cách chuyển đổi kết quả thành hex, ví dụ:

result_in_hex=$(printf "%x" $(( ~33 ))); echo $result_in_hex
ffffffffffffffde

so với những gì bạn đã có:

result_in_dec=$(printf "%d" $(( ~33 ))); echo $result_in_dec
-34

Tôi giả sử bạn có nghĩa là phủ nhận 0x33. Nếu đó là trường hợp thì điều này sẽ làm việc:

result_in_hex=$(printf "%2x" $(( ( ~ 0x33 ) & 0xFF))); echo $result_in_hex
cc

Bạn cũng cần sử dụng & đó là bit-khôn ngoan và toán tử để tránh tất cả các ff khi bắt đầu.


1

Các ~(số học) điều hành flips tất cả các bit , nó được gọi là toán tử Bitwise phủ định:

! ~    logical and bitwise negation

Vì vậy, ở những nơi bối cảnh là số học, nó thay đổi một số với tất cả các bit là số không thành tất cả các bit là số. A $(( ~0 ))chuyển đổi tất cả các bit của biểu diễn số (thường là 64 bit ngày nay) thành tất cả các bit.

$ printf '%x\n' "$(( ~0 ))"
ffffffffffffffff

Một số có tất cả các số được hiểu là số âm (bit đầu tiên 1) 1, hoặc đơn giản -1.

$ printf '%x\n' "-1"
ffffffffffffffff

$ echo "$(( ~0 ))"
-1

Điều tương tự cũng xảy ra với tất cả các số khác, ví dụ: $(( ~1 ))lật tất cả các bit:

$ printf '%x\n' "$(( ~1 ))"
fffffffffffffffe

Hoặc, ở dạng nhị phân: 1111111111111111111111111111111111111111111111111111111111111110

Trong đó, được hiểu là một số trong đại diện của hai là:

$ echo "$(( ~1 ))"
-2

Nói chung, phương trình toán học của con người $(( ~n ))là bằng$(( -n-1 ))

$ n=0    ; echo "$(( ~n )) $(( -n-1 ))"
-1 -1

$ n=1    ; echo "$(( ~n )) $(( -n-1 ))"
-2 -2

$ n=255  ; echo "$(( ~n )) $(( -n-1 ))"
-256 -256

Và (câu hỏi của bạn):

$ n=33   ; echo "$(( ~n )) $(( -n-1 ))"
-34 -34

0

Trước tiên, bạn phải hiểu rằng 33 là số 32 bit hoặc 64 bit.

Để triệu tập, tôi lấy một số tám bit (= 1 byte)

thập phân 33 có tám bit: 00100001, lật các bit kết quả trong 11011110.

Bởi vì bit thứ tự cao là 1, nó là một số âm.

In một số âm, hệ thống sẽ in một dấu trừ và sau đó thực hiện bổ sung hai số cho số âm.

Bổ sung của hai là: lật các bit và thêm 1.

11011110 ==> 00100001 ==> thêm 1 ==> 00100010 kết quả là số thập phân 34 phía sau dấu trừ.

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.