Dlaczego „$ ((~ 33))” daje -34?


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

a moje jądro to:

$ 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

PYTANIE: ~ służy do zanegowania liczby AFAIK. Ale dlaczego ~33produkuje -34i dlaczego ~255produkuje -256?


2
Negacja bitowa , nie mylić z negacją arytmetyczną ( -x )
chepner

Odpowiedzi:


21

Strona podręcznika bash mówi:

   ! ~    logical and bitwise negation

Podpisane liczby są zwykle przechowywane w reprezentacji uzupełnienia Two :

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

Oznacza to, że jeśli weźmiesz liczbę taką jak 2, zostanie ona zinterpretowana bitowo jako 0010. Po negacji bitowej staje się to 1101, co reprezentuje -3.


10

Jest to wynik arytmetyki dopełniacza dwóch.

~jest bitową negacją, która odwraca wszystkie operowane bity. Arytmetyka komplementu dwóch działa poprzez odwrócenie wszystkich bitów i dodanie 1. Ponieważ odwróciłeś tylko bity, ale nie dodałeś jednego, otrzymujesz tę samą liczbę, odwróconą, minus jeden.

Wikipedia ma dobry artykuł na temat uzupełnienia dwóch tutaj .

Jako przykład:

  • 3 w formacie binarnym to 0011
  • -3 cale (uzupełnienie dwóch) to 1101
  • Odwracanie 0011daje ci wartość 1100-4, ponieważ nie dodałeś 1.

3

Operator ~ jest bitowym operatorem NOT. Używanie go to nie to samo, co negowanie liczby.

Z wikipedii , bitowa operacja NIE jest równoznaczna z przyjmowaniem uzupełnienia dwóch wartości minus jeden:

NOT x = −x - 1

Negowanie liczby binarnej jest równoznaczne z przyjęciem jej wartości dwóch uzupełnień.

Za pomocą operatora ~ NOT = weź wartość jednego uzupełnienia.

Mówiąc prościej ~ odwraca wszystkie bity reprezentacji binarnej .

Dla twoich przykładów:

33 (dziesiętny) = 0x00100001 (8-bitowy plik binarny)

~ 33 = ~ 0x00100001 = 0x11011110 = -34 (dziesiętnie)

Lub w arytmetyce dziesiętnej przy użyciu wzoru ~ x = -x - 1:

~ 33 = -33 - 1 = -34

i

~ 255 = -255 - 1 = -256


1

Problem polega na tym, że ~ jest nieco mądrym operatorem. Dlatego negujesz więcej bitów, niż ci się wydaje. Możesz to lepiej zobaczyć, konwertując wyniki na hex, np .:

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

w porównaniu do tego, co miałeś:

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

Zakładam, że masz zamiar zanegować 0x33. W takim przypadku zadziałałoby to:

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

Musisz także użyć &, który jest nieco logiczny i operator, aby uniknąć całego ff na początku.


1

Operator ~(arytmetyczny) odwraca wszystkie bity , nazywany jest bitowym operatorem negacji:

! ~    logical and bitwise negation

Tak więc w miejscach, w których kontekst jest arytmetyczny, zmienia liczbę ze wszystkimi bitami jako zerami na wszystkie bity jako jedności. A $(( ~0 ))konwertuje wszystkie bity reprezentacji liczb (zwykle obecnie 64 bity) na wszystkie.

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

Liczba z wszystkimi z nich jest interpretowana jako liczba ujemna (pierwszy bit 1) 1lub po prostu -1.

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

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

To samo dzieje się ze wszystkimi innymi liczbami, na przykład: $(( ~1 ))odwraca wszystkie bity:

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

Lub binarnie: 1111111111111111111111111111111111111111111111111111111111111110

Który interpretowany jako liczba w reprezentacji dwóch jest następujący:

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

Ogólnie rzecz biorąc, równanie matematyczne człowieka $(( ~n ))jest równe$(( -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

I (twoje pytanie):

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

0

Najpierw musisz zrozumieć, że 33 to liczba 32-bitowa lub 64-bitowa.

Dla wygody biorę ośmiobitową liczbę (= 1 bajt)

dziesiętna 33 jest w ośmiu bitach: 00100001, przerzucanie bitów daje wynik w wyniku 11011110.

Ponieważ bit najwyższego rzędu wynosi 1, jest to liczba ujemna.

Drukując liczbę ujemną, system drukuje znak minus, a następnie wykonuje uzupełnienie dwóch liczb ujemnych.

Uzupełnieniem dwóch jest: podrzucanie bitów i dodawanie 1.

11011110 ==> 00100001 ==> dodanie 1 ==> 00100010 powoduje, że liczba dziesiętna 34 jest za znakiem minus.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.