Mengapa "$ ((~ 33))" menghasilkan -34?


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

dan kernel saya adalah:

$ 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

PERTANYAAN: ~ untuk meniadakan nomor AFAIK. Tetapi mengapa ~33menghasilkan -34dan mengapa ~255menghasilkan -256?


2
Negasi bitwise , jangan dikelirukan dengan negasi aritmatika ( -x )
chepner

Jawaban:


21

Halaman manual bash mengatakan:

   ! ~    logical and bitwise negation

Nomor yang ditandatangani biasanya disimpan dalam representasi komplemen Two :

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

Ini berarti jika Anda mengambil angka seperti 2 bitwise ditafsirkan sebagai 0010. Setelah negasi bitwise ini menjadi 1101, yang merupakan representasi -3.


10

Ini adalah hasil dari aritmatika komplemen dua.

~adalah negasi bitwise yang membalikkan semua bit yang dioperasikan. Aritmatika komplemen dua berfungsi dengan membalik semua bit dan menambahkan 1. Karena Anda hanya membalik bit, tetapi tidak menambahkan satu, Anda mendapatkan nomor yang sama, terbalik, minus satu.

Wikipedia memiliki artikel bagus tentang komplemen dua di sini .

Sebagai contoh:

  • 3 dalam biner adalah 0011
  • -3 dalam (dua komplemen) biner adalah 1101
  • Inverting 0011memberi Anda 1100, yaitu -4, karena Anda belum menambahkan 1.

3

Operator ~ adalah operator bitwise TIDAK. Menggunakannya tidak sama dengan meniadakan angka.

Dari wikipedia , operasi bitwise TIDAK sama dengan mengambil pelengkap keduanya dari nilai minus satu:

BUKAN x = −x - 1

Meniadakan bilangan biner sama dengan mengambil nilai dua komplemennya.

Menggunakan operator ~ NOT = ambil nilai satu komplemennya.

Dalam istilah yang lebih sederhana, ~ hanya membalik semua bit dari representasi biner .

Untuk contoh Anda:

33 (desimal) = 0x00100001 (biner 8-bit)

~ 33 = ~ 0x00100001 = 0x11011110 = -34 (desimal)

Atau dalam aritmatika desimal, menggunakan rumus ~ x = -x - 1:

~ 33 = -33 - 1 = -34

dan

~ 255 = -255 - 1 = -256


1

Masalahnya adalah ~ adalah operator yang sedikit bijaksana. Karenanya, Anda meniadakan bit lebih banyak daripada yang mungkin Anda inginkan. Anda dapat melihat ini dengan lebih baik dengan mengonversi hasilnya menjadi hex misalnya:

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

versus apa yang Anda miliki:

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

Saya berasumsi Anda bermaksud meniadakan 0x33. Jika itu masalahnya maka ini akan berhasil:

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

Anda juga harus menggunakan & yang merupakan bit-wise dan operator untuk menghindari semua ff di awal.


1

Operator ~(aritmatika) membalik semua bit , itu disebut operator negasi bitwise:

! ~    logical and bitwise negation

Jadi, di tempat-tempat di mana konteksnya adalah aritmatika, ia mengubah angka dengan semua bit sebagai nol menjadi semua bit. A $(( ~0 ))mengkonversi semua bit dari representasi angka (biasanya 64 bit saat ini) ke semua yang ada.

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

Angka dengan semua yang ditafsirkan sebagai angka negatif (bit pertama 1) 1, atau sederhana -1.

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

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

Hal yang sama terjadi pada semua angka lainnya, misalnya: $(( ~1 ))membalik semua bit:

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

Atau, dalam biner: 1111111111111111111111111111111111111111111111111111111111111110

Yang, ditafsirkan sebagai angka dalam representasi dua adalah:

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

Secara umum, persamaan matematika manusia $(( ~n ))adalah sama dengan$(( -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

Dan (pertanyaan Anda):

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

0

Pertama, Anda harus memahami bahwa 33 adalah angka 32 bit atau 64 bit.

Untuk penyelenggaraan, saya mengambil angka delapan bit (= 1 byte)

desimal 33 dalam delapan bit: 00100001, membalikkan bit menghasilkan 11011110.

Karena bit pesanan tinggi adalah 1, itu adalah angka negatif.

Mencetak angka negatif, sistem mencetak tanda minus dan kemudian melakukan pelengkap dua pada angka negatif.

Dua komplemen adalah: membalik bit dan menambahkan 1.

11011110 ==> 00100001 ==> menambahkan 1 ==> 00100010 menghasilkan desimal 34 di belakang tanda minus.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.