¿Cómo funciona el operador de complemento bit a bit (~ tilde)?

Respuestas:

283

Recuerde que los números negativos se almacenan como el complemento de dos de la contraparte positiva. Como ejemplo, aquí está la representación de -2 en el complemento a dos: (8 bits)

1111 1110

La forma de obtener esto es tomando la representación binaria de un número, tomando su complemento (invirtiendo todos los bits) y agregando uno. Dos comienza como 0000 0010, e invirtiendo los bits obtenemos 1111 1101. Al agregar uno, obtenemos el resultado anterior. El primer bit es el bit de signo, lo que implica un negativo.

Así que echemos un vistazo a cómo obtenemos ~ 2 = -3:

Aquí hay dos de nuevo:

0000 0010

Simplemente voltea todos los bits y obtenemos:

1111 1101

Bueno, ¿cómo se ve -3 en el complemento de dos? Comience con 3: 0000 0011 positivo, voltee todos los bits a 1111 1100 y agregue uno para que sea un valor negativo (-3), 1111 1101.

Entonces, si simplemente invierte los bits en 2, obtendrá la representación del complemento de dos de -3.

El operador del complemento (~) SOLO FLIPS BITS. Depende de la máquina interpretar estos bits.

Antonio
fuente
44
Otra cosa que quizás deba mencionar es que el flip se llama complemento 1, antes de agregar el 1.
Chris S
3
Puede ayudar a otros que no conocen el Complemento de Uno y el Complemento de Dos. Lee sobre ellos aquí. en.wikipedia.org/wiki/Ones%27_complement en.wikipedia.org/wiki/Two%27s_complement
Sai
1
¿No es ese el operador NO bit a bit?
Braden Best
3
¿Cómo sabe la máquina que está obteniendo un número negativo de dos complementos en lugar de un número positivo más alto? ¿Se debe a que el sistema de tipos del idioma respectivo indica que el tipo es un int con signo versus sin signo?
GL2014
@ GL2014 Creo que respondiste tu propia pregunta allí. En mi opinión, es cómo se diseñó la máquina para trabajar en primer lugar.
geekidharsh
40

~ voltea los bits en el valor.

¿Por qué ~2es -3tiene que ver con cómo los números se representan en modo bit. Los números se representan como complemento de dos .

Entonces, 2 es el valor binario

00000010

Y ~ 2 voltea los bits para que el valor sea ahora:

11111101

Cuál, es la representación binaria de -3.

driis
fuente
2
¿No es 11111101 == decimal 253 vs -3?
AKS
10
Depende de si representa un entero con signo o sin signo.
driis
¿Cuál es su uso en la programación del mundo real? ¿Tiene aplicaciones en programación competitiva?
Noah J. Standerson hace
18

Como otros mencionaron, ~solo voltearon los bits (cambia uno a cero y cero a uno) y como se usa el complemento de dos, obtienes el resultado que viste.

Una cosa para agregar es por qué se usa el complemento de dos, esto es para que las operaciones en números negativos sean las mismas que en números positivos. Piense -3en el número al que 3debe agregarse para obtener cero y verá que este número es 1101, recuerde que la suma binaria es como la suma de la escuela primaria (decimal) solo que lleva una cuando llega a dos en lugar de 10 .

 1101 +
 0011 // 3
    =
10000
    =
 0000 // lose carry bit because integers have a constant number of bits.

Por 1101lo tanto -3, voltea los bits que obtienes, 0010que son dos.

Motti
fuente
8

Esta operación es un complemento, no una negación.

Considere que ~ 0 = -1, y trabaje desde allí.

El algoritmo para la negación es "complemento, incremento".

¿Sabías? También hay "complemento de uno" donde los números inversos son simétricos, y tiene tanto un 0 como un -0.

gbarry
fuente
6

Sé que la respuesta a esta pregunta se publicó hace mucho tiempo, pero quería compartir mi respuesta para la misma.

Para encontrar el complemento de un número, primero encuentre su equivalente binario. Aquí, el número decimal 2se representa como 0000 0010en forma binaria. Ahora tomando su complemento invirtiendo (volteando todos los 1 en 0 y todos los 0 en 1) todos los dígitos de su representación binaria, lo que resultará en:

0000 0010 → 1111 1101

Este es el complemento de uno del número decimal 2. Y dado que el primer bit, es decir, el bit de signo es 1 en el número binario, significa que el signo es negativo para el número que almacenó. (aquí, el número al que se hace referencia no es 2, sino el complemento de 2).

Ahora, dado que los números se almacenan como complemento de 2 (tomando el complemento de uno de un número más uno), para mostrar este número binario 1111 1101, en decimal, primero debemos encontrar el complemento de 2, que será:

1111 1101 → 0000 0010 + 1 → 0000 0011

Este es el complemento de 2. La representación decimal del número binario,, 0000 0011es 3. Y, dado que el bit de signo era uno como se mencionó anteriormente, la respuesta resultante es -3.

Sugerencia: si lees este procedimiento detenidamente, habrías observado que el resultado para el operador del complemento es, en realidad, el número (operando en el que se aplica este operador) más uno con un signo negativo. Puedes probar esto con otros números también.

Himanshu Aggarwal
fuente
¿Por qué se agrega dos veces? Estoy viendo add, flip, add. 0010-> 0011-> 1100->1101
Braden Mejor
1
Es voltear, voltear, agregar. Primer giro para el complemento de 1. Y dado que se almacena en el complemento de 2 en el sistema, cuando necesite mostrar el número, mostrará el complemento de 2 del número almacenado (es decir, la segunda vuelta y sumar).
Himanshu Aggarwal
¿Pero no sería flip (flip (2)) solo ser 2? 0010 1101 0010
Braden Best
Sí, solo serán 2. Pero dado que cuando los bits se almacenan en la memoria, el bit más significativo fue 1, lo que hará que el número sea negativo más adelante como se explica en la respuesta anterior.
Himanshu Aggarwal
1
Por lo que estás describiendo y todo lo que he investigado, este no es un complemento de dos, sino un complemento "regular", o un NO bit a bit. En lógica, NOT 0 = 1y NOT 1 = 0. En un sistema de cuatro bits, NOT 0011(3) = 1100(12 sin signo, -4 con signo). Por lo que entiendo, el complemento de dos se define como (NOT n) + 1, y se utiliza para encontrar la contraparte negativa de un número, independientemente de la cantidad de bits. Por lo tanto, 2c(5) = -5. Mira, ahora tiene mucho sentido. Siempre y cuando llame a esta operación lo que es: un NO bit a bit.
Braden Best
4

int a = 4; System.out.println (~ a); El resultado sería: -5

'~' de cualquier número entero en java representa el complemento de 1 del no. por ejemplo, estoy tomando ~ 4, lo que significa en representación binaria 0100. primero, la longitud de un entero es de cuatro bytes, es decir, 4 * 8 (8 bits para 1 byte) = 32. Entonces, en la memoria del sistema 4 se representa como 0000 0000 0000 0000 0000 0000 0000 0100 ahora ~ el operador realizará el complemento de 1 en el binario anterior no

es decir, 1111 1111 1111 1111 1111 1111 1111 1011-> complemento de 1, el bit más significativo representa el signo del no (ya sea - o +) si es 1, entonces el signo es '-' si es 0, entonces el signo es '+' según este nuestro resultado es un número negativo, en java los números negativos se almacenan en forma de complemento de 2, el resultado adquirido tenemos que convertirlo en complemento de 2 (primero realice el complemento de 1 y simplemente agregue el complemento de 1 a 1). todos se convertirán en ceros, excepto el bit 1 más significativo (que es nuestra representación de signo del número, que significa para los 31 bits restantes 1111 1111 1111 1111 1111 1111 1111 1011 (resultado adquirido del operador ~) 1000 0000 0000 0000 0000 0000 0000 0100 (complemento de 1)

1 (complemento de 2)

1000 0000 0000 0000 0000 0000 0000 0101 ahora el resultado es -5 mira este enlace para el video <[Operadores sabios en Java] https://youtu.be/w4pJ4cGWe9Y

Mike Aluydiav
fuente
2

Simplemente ...........

Como complemento de 2 de cualquier número, podemos calcular invirtiendo todos los 1s en 0 y viceversa de lo que le agregamos 1.

Aquí N = ~ N produce resultados - (N + 1) siempre. Debido a que el sistema almacena datos en forma de complemento de 2, lo que significa que almacena ~ N de esta manera.

  ~N = -(~(~N)+1) =-(N+1). 

Por ejemplo::

  N = 10  = 1010
  Than ~N  = 0101
  so ~(~N) = 1010
  so ~(~N) +1 = 1011 

Ahora el punto es de donde viene Minus. Mi opinión es suponer que tenemos un registro de 32 bits, lo que significa 2 ^ 31 -1 bits involucrados en la operación y descansar un bit que cambia en el cómputo anterior (complemento) almacenado como bit de signo, que generalmente es 1. Y obtenemos el resultado como ~ 10 = -11.

~ (-11) = 10;

Lo anterior es cierto si printf ("% d", ~ 0); obtenemos el resultado: -1;

Pero printf ("% u", ~ 0) que el resultado: 4294967295 en la máquina de 32 bits.

Shubham Kumar Mishra
fuente
1

El operador de complemento Bitwise (~) es un operador unario .

Funciona según los siguientes métodos.

Primero, convierte el número decimal dado a su valor binario correspondiente. En el caso de 2, primero convierte 2 a 0000 0010 (a número binario de 8 bits).

Luego convierte todo el 1 en el número a 0, y todos los ceros a 1; entonces el número se convertirá en 1111 1101.

esa es la representación del complemento a 2 de -3.

Para encontrar el valor sin signo usando el complemento, es decir, simplemente para convertir 1111 1101 a decimal (= 4294967293) simplemente podemos usar el% u durante la impresión.

james.bondu
fuente
1

Creo que para la mayoría de las personas, la parte de confusión proviene de la diferencia entre el número decimal y el número binario con signo, así que aclaremos primero:

para el mundo decimal humano: 01 significa 1, -01 significa -1, para el mundo binario de la computadora: 101 significa 5 si no está firmado. 101 significa (-4 + 1) si está firmado mientras el dígito firmado está en la posición x. El | X

entonces el bit invertido de 2 = ~ 2 = ~ (010) = 101 = -4 + 1 = -3 la confusión viene de mezclar el resultado firmado (101 = -3) y el resultado sin señalizar (101 = 5)

usuario7537910
fuente
1

tl; dr ~ voltea los bits. Como resultado, el signo cambia. ~2es un número negativo ( 0b..101) Para dar salida a un número negativo rubyimpresiones -, luego de complemento de dos de ~2: -(~~2 + 1) == -(2 + 1) == 3. Los números positivos se emiten tal cual.

Hay un valor interno y su representación de cadena. Para enteros positivos, básicamente coinciden:

irb(main):001:0> '%i' % 2
=> "2"
irb(main):002:0> 2
=> 2

Este último es equivalente a:

irb(main):003:0> 2.to_s
"2"

~voltea los bits del valor interno. 2es 0b010. ~2es 0b..101. Dos puntos ( ..) representan un número infinito de 1's. Como el bit más significativo (MSB) del resultado es 1, el resultado es un número negativo ( (~2).negative? == true). Para generar un número negativo se rubyimprime -, luego dos complementan el valor interno. El complemento a dos se calcula volteando los bits y luego sumando 1. Complemento de dos de 0b..101es 3. Como tal:

irb(main):005:0> '%b' % 2
=> "10"
irb(main):006:0> '%b' % ~2
=> "..101"
irb(main):007:0> ~2
=> -3

Para resumir, voltea los bits, lo que cambia el signo. Para generar un número negativo, imprime -, luego ~~2 + 1( ~~2 == 2).

La razón por la cual rubylos números negativos salen así es porque trata el valor almacenado como un complemento de dos del valor absoluto. En otras palabras, lo que está almacenado es 0b..101. Es un número negativo, y como tal es un complemento de dos de algún valor x. Para encontrarlo x, hace dos complementos de 0b..101. Cuál es el complemento de dos del complemento de dos de x. Cuál es x(por ejemplo ~(~2 + 1) + 1 == 2).

En caso de que aplique ~a un número negativo, simplemente voltea los bits (que sin embargo cambia el signo):

irb(main):008:0> '%b' % -3
=> "..101"
irb(main):009:0> '%b' % ~-3
=> "10"
irb(main):010:0> ~-3
=> 2

Lo que es más confuso es eso ~0xffffff00 != 0xff(o cualquier otro valor con MSB igual a 1). Vamos a simplificar un poco: ~0xf0 != 0x0f. Eso es porque se trata 0xf0como un número positivo. Lo que en realidad tiene sentido. Por lo tanto, ~0xf0 == 0x..f0f. El resultado es un número negativo. Complemento de dos de 0x..f0fes 0xf1. Entonces:

irb(main):011:0> '%x' % ~0xf0
=> "..f0f"
irb(main):012:0> (~0xf0).to_s(16)
=> "-f1"

En caso de que no vaya a aplicar operadores bit a bit al resultado, puede considerar ~como -x - 1operador:

irb(main):018:0> -2 - 1
=> -3
irb(main):019:0> --3 - 1
=> 2

Pero eso podría decirse que no es de mucha utilidad.

Un ejemplo Supongamos que le dan una máscara de red de 8 bits (por simplicidad) y desea calcular el número de 0's. Puede calcularlos volteando los bits y llamando bit_length( 0x0f.bit_length == 4). Pero ~0xf0 == 0x..f0f, así que tenemos que cortar los bits innecesarios:

irb(main):014:0> '%x' % (~0xf0 & 0xff)
=> "f"
irb(main):015:0> (~0xf0 & 0xff).bit_length
=> 4

O puede usar el operador XOR ( ^):

irb(main):016:0> i = 0xf0
irb(main):017:0> '%x' % i ^ ((1 << i.bit_length) - 1)
=> "f"
x-yuri
fuente
0

Primero tenemos que dividir el dígito dado en sus dígitos binarios y luego revertirlo agregando el último dígito binario. Después de esta ejecución tenemos que dar un signo opuesto al dígito anterior que estamos encontrando el complemento ~ 2 = -3 Explicación : La forma binaria 2s es 00000010 cambia a 11111101 este es un complemento, luego se completa 00000010 + 1 = 00000011 que es la forma binaria de tres y con -sign Ie, -3

balusabavath
fuente
0

El operador bit-wise es un operador unario que trabaja en el método de signo y magnitud según mi experiencia y conocimiento.

Por ejemplo ~ 2 daría como resultado -3.

Esto se debe a que el operador en cuanto a bits representaría primero el número en signo y magnitud que es 0000 0010 (operador de 8 bits) donde el MSB es el bit de signo.

Luego, tomaría el número negativo de 2, que es -2.

-2 se representa como 1000 0010 (operador de 8 bits) en signo y magnitud.

Más tarde agrega un 1 al LSB (1000 0010 + 1) que le da 1000 0011.

Cuál es -3.

Santhosh Kumar Jhadav
fuente
0

Javascript tilde (~) obliga a un valor dado al complemento de uno: todos los bits están invertidos. Eso es todo lo que tilde hace. No es signo obstinado. No suma ni resta ninguna cantidad.

0 -> 1
1 -> 0
...in every bit position [0...integer nbr of bits - 1]

En los procesadores de escritorio estándar que utilizan lenguajes de alto nivel como JavaScript, la aritmética con signo BASE10 es la más común, pero tenga en cuenta que no es el único tipo. Los bits a nivel de CPU están sujetos a interpretación en función de una serie de factores. En el nivel de "código", en este caso JavaScript, se interpretan como un entero con signo de 32 bits por definición (dejemos flotantes fuera de esto). Piense en ello como cuántico, esos 32 bits representan muchos valores posibles a la vez. Depende completamente de la lente de conversión a través de la cual los vea.

JavaScript Tilde operation (1's complement)

BASE2 lens
~0001 -> 1110  - end result of ~ bitwise operation

BASE10 Signed lens (typical JS implementation)
~1  -> -2 

BASE10 Unsigned lens 
~1  -> 14 

Todo lo anterior es cierto al mismo tiempo.

Elvn
fuente
0

Básicamente, la acción es un complemento, no una negación.

Aquí x = ~ x produce resultados - (x + 1) siempre.

x = ~ 2

- (2 + 1)

-3

Sunil
fuente