¿Por qué es que el operador NOT bit a bit (~
en la mayoría de los idiomas) convierte los valores siguientes de esta manera:Explicación de bit a bit NO operador
-2 -> 1
-1 -> 0
0 -> -1
1 -> -2
-2
convertir a 2
, 1
convertir a -1
, etc.?
¿Por qué es que el operador NOT bit a bit (~
en la mayoría de los idiomas) convierte los valores siguientes de esta manera:Explicación de bit a bit NO operador
-2 -> 1
-1 -> 0
0 -> -1
1 -> -2
-2
convertir a 2
, 1
convertir a -1
, etc.?
Ver two's complement para la representación de números enteros negativos en varios idiomas. Como puede ver, -2 está representado por 1111110
; Si invierte todos esos bits obtiene 0000001
, es decir, un valor de 1.
La mayoría de las arquitecturas modernas (todas?) usan two's complement para representar enteros con signo. El NOT bit a bit es, por lo tanto, el complemento del entero menos uno.
Ayuda si lo miras en binario.
En primer lugar, como usted sabe, los números negativos se expresan como (número más alto posible sin signo más 1 valor negativo). Entonces -1 en un entero de 16 bits, que tiene el valor más alto sin signo de 65535, sería 65536-1 = 65535, es decir, 0xffff en hexadecimal, o 1111 1111 1111 1111
en binario.
Así:
1 en binario = 0000 0000 0000 0001
en todos los bits se traduciría en 1111 1111 1111 1110
. Eso, en decimal, es 65534. Y 65536 menos 65535 es 1, entonces esto es -1.
Esto se debe a la forma en que los números negativos se representan como bits. Para esto comúnmente se usan Two's Complements.
-2 pasa a ser 1.111.110 en esta notación, que negada es 1
Esto es porque el operador de bits literalmente invierte cada bit en la palabra. NO es estrictamente una operación aritmética, es una operación lógica.
-2 ==% 1110, ~ -2 == ~% 1110 =% 0001 == 1 -1 ==% 1111, ~ -1 ~ ==% 1111 =% 0000 == 0
y así sucesivamente.
Para pasar de -2 a 2 y de 1 a -1, debe usar la operación de negación aritmética.
Dim mask As Integer = -1
'11111111111111111111111111111111
For x As Integer = -3 To 3
Dim i As Integer = x
Debug.WriteLine("")
Debug.WriteLine("'" & Convert.ToString(i, 2).PadLeft(32, "0"c) & " > Num = " & i.ToString)
i = i Xor mask 'reverse the bits (same as Not)
Debug.WriteLine("'" & Convert.ToString(i, 2).PadLeft(32, "0"c) & " > Not = " & i.ToString)
i += 1 'convert to two's complement
Debug.WriteLine("'" & Convert.ToString(i, 2).PadLeft(32, "0"c) & " > 2's Comp = " & i.ToString)
Next
'debug results
'11111111111111111111111111111101 > Num = -3
'00000000000000000000000000000010 > Not = 2
'00000000000000000000000000000011 > 2's Comp = 3
'11111111111111111111111111111110 > Num = -2
'00000000000000000000000000000001 > Not = 1
'00000000000000000000000000000010 > 2's Comp = 2
'11111111111111111111111111111111 > Num = -1
'00000000000000000000000000000000 > Not = 0
'00000000000000000000000000000001 > 2's Comp = 1
'00000000000000000000000000000000 > Num = 0
'11111111111111111111111111111111 > Not = -1
'00000000000000000000000000000000 > 2's Comp = 0
'00000000000000000000000000000001 > Num = 1
'11111111111111111111111111111110 > Not = -2
'11111111111111111111111111111111 > 2's Comp = -1
'00000000000000000000000000000010 > Num = 2
'11111111111111111111111111111101 > Not = -3
'11111111111111111111111111111110 > 2's Comp = -2
'00000000000000000000000000000011 > Num = 3
'11111111111111111111111111111100 > Not = -4
'11111111111111111111111111111101 > 2's Comp = -3
Adición: útil señalar que 'NOT' bit a bit es casi siempre el más rápido para analizar una cadena en un número: https://jsperf.com/number-vs-plus-vs-toint-vs-tofloat/20 –