Por que “$ ((~ 33))” produz -34?

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

e meu 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

PERGUNTA: ~ é para negar o número AFAIK. Mas por que ~33 produz -34 e por que ~255 produz -256 ?

    
por gasko peter 09.05.2013 / 08:15

4 respostas

20

A página man do bash diz:

   ! ~    logical and bitwise negation

Os números assinados geralmente são armazenados na representação Complemento de dois :

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

Isso significa que, se você pegar um número como 2, ele será interpretado como 0010. Após a negação bit a bit, isso se torna 1101, que é a representação de -3.

    
por 09.05.2013 / 08:40
9

Este é o resultado da aritmética do complemento de dois.

~ é uma negação bit a bit que inverte todos os bits sendo operados. A aritmética de complemento de dois funciona invertendo todos os bits e adicionando 1. Já que você só inverte os bits, mas não adiciona um, você obtém o mesmo número, invertido, menos um.

A Wikipedia tem um bom artigo sobre o complemento de dois aqui .

Como exemplo:

  • 3 no binário é 0011
  • -3 in (complemento de dois) o binário é 1101
  • A inversão de 0011 fornece 1100 , que é -4, pois você não adicionou 1.
por 09.05.2013 / 08:39
2

O operador ~ é o operador NOT bit a bit. Usá-lo não é o mesmo que negar um número.

A partir da wikipedia , uma operação NOT bit a bit é igual a considerar o complemento de dois do valor menos um:

NOT x = −x − 1

Negar um número binário é equivalente a obter seu valor de dois complementos.

Usando o operador ~ NOT = pegue seu valor de um complemento.

Em termos mais simples, ~ apenas inverte todos os bits da representação binária .

Para seus exemplos:

33 (decimal) = 0x00100001 (8-bit binary)

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

Ou na aritmética decimal, usando a fórmula ~ x = -x - 1:

~33 = -33 - 1 = -34

e

~255 = -255 - 1 = -256

    
por 09.05.2013 / 08:52
1

O problema é que ~ é um operador bit-wise. Daí você está negando mais bits do que você pretende. Você pode ver isso melhor convertendo os resultados em hexadecimais, por exemplo:

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

versus o que você tinha:

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

Suponho que você queira negar 0x33. Se esse for o caso, isso funcionaria:

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

Você também precisa usar & qual é o bit-wise e operador para evitar todos os ff no início.

    
por 30.07.2015 / 17:37