Perché "$ ((~ 33))" produce -34?


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

e il mio kernel è:

$ 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

DOMANDA: ~ serve per annullare il numero AFAIK. Ma perché ~33produce -34e perché ~255produce -256?


2
Bitwise negazione, da non confondere con la negazione aritmetica ( -x )
chepner

Risposte:


21

La pagina man di bash dice:

   ! ~    logical and bitwise negation

I numeri firmati vengono generalmente memorizzati nella rappresentazione del complemento di Two :

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

Questo significa che se prendi un numero come 2, questo viene interpretato bit a bit come 0010. Dopo la negazione bit a bit, questo diventa 1101, che è la rappresentazione di -3.


10

Questo è il risultato dell'aritmetica del complemento a due.

~è una negazione bit a bit che inverte tutti i bit su cui si opera. L'aritmetica del complemento di Two funziona invertendo tutti i bit e aggiungendo 1. Dato che hai capovolto solo i bit, ma non ne hai aggiunto uno, ottieni lo stesso numero, invertito, meno uno.

Wikipedia ha un buon articolo sul complemento a due qui .

Come esempio:

  • 3 in binario è 0011
  • -3 in (complemento a due) binario è 1101
  • Inversione 0011ti dà 1100, che è -4, poiché non hai aggiunto 1.

3

L'operatore ~ ​​è l'operatore NOT bit a bit. Usarlo non equivale a negare un numero.

Da Wikipedia , un'operazione NOT bit a bit equivale a prendere il complemento a due del valore meno uno:

NON x = −x - 1

Negare un numero binario equivale a prendere il suo valore di due complementi.

Utilizzando l'operatore ~ ​​NOT = prendi il suo valore di un complemento.

In termini più semplici, ~ lancia semplicemente tutti i bit della rappresentazione binaria .

Per i tuoi esempi:

33 (decimale) = 0x00100001 (binario a 8 bit)

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

O in aritmetica decimale, usando la formula ~ x = -x - 1:

~ 33 = -33 - 1 = -34

e

~ 255 = -255 - 1 = -256


1

Il problema è che ~ è un operatore un po 'saggio. Quindi stai negando più bit di quelli che forse intendi. Puoi vederlo meglio convertendo i risultati in esadecimale, ad esempio:

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

rispetto a quello che hai avuto:

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

Suppongo che intendi negare 0x33. In tal caso, funzionerebbe:

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

Devi anche usare & quale è il bit-saggio e l'operatore per evitare tutto il ff all'inizio.


1

L' ~operatore (aritmetico) lancia tutti i bit , si chiama operatore di negazione bit a bit:

! ~    logical and bitwise negation

Quindi, nei luoghi in cui il contesto è aritmetico, cambia un numero con tutti i bit come zero in tutti i bit come uno. A $(( ~0 ))converte tutti i bit della rappresentazione numerica (di solito 64 bit al giorno d'oggi) in tutti i bit.

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

Un numero con tutti è interpretato come il numero negativo (primo bit 1) 1, o semplicemente -1.

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

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

Lo stesso accade a tutti gli altri numeri, ad esempio: $(( ~1 ))lancia tutti i bit:

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

Oppure, in binario: 1111111111111111111111111111111111111111111111111111111111111110

Che, interpretato come un numero nella rappresentazione di due è:

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

In generale, l'equazione matematica umana $(( ~n ))è uguale a$(( -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

E (la tua domanda):

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

0

Per prima cosa devi capire che 33 è un numero di 32 bit o 64 bit.

Per convenzione, prendo un numero di otto bit (= 1 byte)

il decimale 33 è in otto bit: 00100001, capovolgendo i bit si ottiene 11011110.

Poiché il bit di ordine superiore è 1, è un numero negativo.

Stampando un numero negativo, il sistema stampa un segno meno e quindi compie un complemento a due sul numero negativo.

Il complemento a due è: lanciando i bit e aggiungendo 1.

11011110 ==> 00100001 ==> l'aggiunta di 1 ==> 00100010 porta al decimale 34 dietro il segno meno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.