Pourquoi «$ ((~ 33))» produit -34?


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

et mon noyau est:

$ 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

QUESTION: ~ est pour annuler le nombre AFAIK. Mais pourquoi ~33produit -34et pourquoi ~255produit-il -256?


2
Négation au niveau du bit , à ne pas confondre avec la négation arithmétique ( -x )
chepner

Réponses:


21

La page de manuel de bash dit:

   ! ~    logical and bitwise negation

Les nombres signés sont généralement stockés dans la représentation du complément à deux :

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

Cela signifie que si vous prenez un nombre comme 2, il est interprété au niveau du bit comme 0010. Après la négation au niveau du bit, cela devient 1101, qui est la représentation de -3.


10

Ceci est le résultat de l'arithmétique du complément à deux.

~est une négation au niveau du bit qui inverse tous les bits opérés. L'arithmétique du complément à deux fonctionne en inversant tous les bits et en ajoutant 1. Puisque vous n'avez retourné que les bits, mais n'en avez pas ajouté un, vous obtenez le même nombre, inversé, moins un.

Wikipedia a un bon article sur le complément à deux ici .

Par exemple:

  • 3 en binaire est 0011
  • -3 en (complément à deux) binaire est 1101
  • Inverser 0011vous donne 1100, ce qui est -4, puisque vous n'avez pas ajouté 1.

3

L'opérateur ~ est l'opérateur NOT au niveau du bit. Son utilisation n'est pas la même chose que la négation d'un nombre.

D'après wikipedia , une opération NOT au niveau du bit équivaut à prendre le complément à deux de la valeur moins un:

PAS x = −x - 1

La négation d'un nombre binaire équivaut à prendre sa valeur à deux compléments.

En utilisant l'opérateur ~ NOT = prenez sa valeur à un complément.

En termes plus simples, ~ retourne simplement tous les bits de la représentation binaire .

Pour vos exemples:

33 (décimal) = 0x00100001 (binaire 8 bits)

~ 33 = ~ 0x00100001 = 0x11011110 = -34 (décimal)

Ou en arithmétique décimale, en utilisant la formule ~ x = -x - 1:

~ 33 = -33 - 1 = -34

et

~ 255 = -255 - 1 = -256


1

Le problème est que ~ est un opérateur bit à bit. Par conséquent, vous niez plus de bits que vous n'en avez peut-être l'intention. Vous pouvez mieux voir cela en convertissant les résultats en hexadécimal, par exemple:

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

par rapport à ce que vous aviez:

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

Je suppose que vous voulez annuler 0x33. Si tel est le cas, cela fonctionnerait:

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

Vous devez également utiliser & qui est le bit et l'opérateur pour éviter tous les ff au début.


1

L' ~opérateur (arithmétique) retourne tous les bits , il est appelé l'opérateur de négation au niveau du bit:

! ~    logical and bitwise negation

Ainsi, dans les endroits où le contexte est arithmétique, il change un nombre avec tous les bits sous forme de zéros en tous les bits sous forme de uns. A $(( ~0 ))convertit tous les bits de la représentation numérique (généralement 64 bits de nos jours) en tous ceux.

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

Un nombre avec tous les uns est interprété comme le nombre négatif (premier bit 1) 1, ou simplement -1.

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

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

La même chose se produit pour tous les autres nombres, par exemple: $(( ~1 ))retourne tous les bits:

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

Ou, en binaire: 1111111111111111111111111111111111111111111111111111111111111110

Ce qui, interprété comme un nombre dans la représentation de deux, est:

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

En général, l'équation mathématique humaine $(( ~n ))est égale à$(( -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

Et (votre question):

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

0

Vous devez d'abord comprendre que 33 est un nombre de 32 bits ou 64 bits.

Par convenance, je prends un nombre de huit bits (= 1 octet)

la décimale 33 est en huit bits: 00100001, inverser les bits donne 11011110.

Étant donné que le bit de poids fort est 1, il s'agit d'un nombre négatif.

En imprimant un nombre négatif, le système imprime un signe moins puis fait un complément à deux sur le nombre négatif.

Le complément à deux est: retourner les bits et ajouter 1.

11011110 ==> 00100001 ==> l'ajout de 1 ==> 00100010 entraîne une décimale de 34 derrière le signe moins.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.