“$ ((~ 33))” neden -34 üretiyor?


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

ve benim çekirdeğim:

$ 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

SORU: ~ AFAIK sayısını reddetmek içindir. Ama neden ~33üretiyor -34ve neden ~255üretiyor -256?


2
Bitsel olumsuzlama, aritmetik olumsuzlama ile karıştırılmamalıdır ( -x )
chepner

Yanıtlar:


21

Bash'nin adam sayfası şöyle diyor:

   ! ~    logical and bitwise negation

İşaretli sayılar genellikle Two'nun tamamlayıcı gösteriminde saklanır :

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

Bu, 2 gibi bir sayı alırsanız, bitsel olarak 0010 olarak yorumlandığı anlamına gelir. Bitsel olumsuzlamadan sonra, bu -31'in temsili olan 1101 olur.


10

Bu ikisinin tamamlayıcı aritmetiğinin sonucudur.

~üzerinde çalışılan tüm bitleri tersine çeviren bitsel bir olumsuzlamadır. İkisinin tamamlayıcı aritmetiği, tüm bitleri ters çevirip 1 ekleyerek çalışır. Sadece bitleri çevirdiğiniz, ancak bir tane eklemediğiniz için, aynı sayıyı ters, eksi bir elde edersiniz.

Wikipedia'nın ikisinin tamamlayıcısı hakkında iyi bir makalesi var .

Örnek olarak:

  • İkili 3 0011
  • -3 inç (ikisinin tamamlayıcısı) ikili 1101
  • Ters Çevirme 0011, 11001 eklemediğiniz için -4 olan size verir .

3

~ Operatörü bitsel DEĞİL operatörüdür. Bunu kullanmak bir sayıyı reddetmekle aynı şey değildir.

Gönderen wikipedia , bit tabanlı DEĞİL operasyon değerinin eksi bir ikinin tümleyeni alarak eşittir:

DEĞİL x = −x - 1

İkili bir sayıyı reddetmek, iki tamamlayıcı değerini almakla eşdeğerdir.

~ NOT operatörünü = kullanarak bir tamamlayıcı değerini alın.

Daha basit bir ifadeyle, ~ ikili gösterimin tüm bitlerini çevirir .

Örnekleriniz için:

33 (ondalık) = 0x00100001 (8 bit ikili)

~ 33 = ~ 0x00100001 = 0x11011110 = -34 (ondalık)

Veya ondalık aritmetiklerde ~ x = -x - 1 formülünü kullanarak:

~ 33 = -33-1 = = 34

ve

~ 255 = -255 - 1 = -256


1

Sorun ~ biraz bilge bir operatör olmasıdır. Bu nedenle, belki de düşündüğünüzden daha fazla biti ihmal ediyorsunuz. Sonuçları onaltılık biçime dönüştürerek daha iyi görebilirsiniz, örn:

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

sahip olduklarınıza karşı:

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

0x33'ü reddetmek istediğinizi varsayıyorum. Durum buysa, bu işe yarayacaktır:

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

Ayrıca, başlangıçta tüm ff'yi önlemek için ve biraz akıllıca ve operatör kullanmanız gerekir.


1

~(Aritmetik) operatörün tüm bitleri döndürür bu bitdüzeyi zıtlık operatörü olarak adlandırılır:

! ~    logical and bitwise negation

Böylece, bağlamın aritmetik olduğu yerlerde, tüm bitleri sıfır olarak içeren bir sayıyı tüm bitler gibi değiştirir. A $(( ~0 )), sayı gösteriminin tüm bitlerini (günümüzde genellikle 64 bit) herkese dönüştürür.

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

Hepsine sahip bir sayı, negatif sayı (ilk bit 1) 1veya basitçe olarak yorumlanır -1.

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

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

Aynı şey diğer tüm sayılar için de geçerlidir, örneğin: $(( ~1 ))tüm bitleri çevirir:

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

Veya ikili olarak: 1111111111111111111111111111111111111111111111111111111111111110

Hangi, ikisinin temsilinde bir sayı olarak yorumlanır:

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

Genel olarak, insan matematik denklemi $(( ~n ))eşittir$(( -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

Ve (sorunuz):

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

0

Öncelikle 33'ün 32 bit veya 64 bit sayı olduğunu anlamalısınız.

Kolaylık sağlamak için sekiz bitlik bir sayı alıyorum (= 1 bayt)

ondalık 33 sekiz bittir: 00100001, bitleri çevirmek 11011110 ile sonuçlanır.

Yüksek dereceli bit 1 olduğu için negatif bir sayıdır.

Negatif bir sayı yazdırıldığında, sistem eksi işareti yazdırır ve daha sonra negatif sayının ikisini tamamlar.

Two'nun tamamlayıcısı: bitleri çevirmek ve 1 eklemek.

11011110 ==> 00100001 ==> 1 ==> 00100010 eklenmesi eksi işaretinin arkasında ondalık 34 ile sonuçlanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.