Cómo trabajar con los 1 y 0 en VB.NET

VB.NET no soporta operaciones a nivel de bit directamente. El Framework 1.1 (VB.NET 2003) introdujo operadores de cambio de bits (<<< y >>), pero no se dispone de una forma general de manipular bits individuales. Las operaciones de bits pueden ser muy útiles. Por ejemplo, es posible que su programa tenga que interactuar con otro sistema que requiera manipulación de bits. Pero, además, hay muchos trucos que se pueden hacer usando bits individuales.

Este artículo analiza lo que se puede hacer con la manipulación de bits usando VB.NET.

Antes que nada, hay que entender a los operadores de bits. En VB.NET, estos son:

  • And
  • Or
  • Xor
  • Not

Bitwise significa simplemente que las operaciones se pueden realizar en dos números binarios poco a poco. Microsoft utiliza tablas verdaderas para documentar las operaciones de bits. La tabla de la verdad para Y es:

1st Bit   2nd Bit   Result

    1      1      1

    1      0      0

    0      1      0

    0      0      0

En mi escuela, en cambio, enseñaban mapas de Karnaugh. El mapa de Karnaugh para las cuatro operaciones se muestra en la siguiente ilustración.

--------

Haga clic aquí para ver la ilustración

Haga clic en el botón Atrás de su navegador para volver

--------

He aquí un ejemplo simple usando la operación Y con números binarios de dos, cuatro bits:

El resultado de 1100 y 1010 es 1000.

Eso es porque 1 y 1 es 1 (el primer bit) y el resto son 0.

Para empezar, echemos un vistazo a las operaciones de bits que se soportan directamente en VB.NET: el desplazamiento de bits.

Aunque tanto el turno izquierdo como el derecho están disponibles, funcionan de la misma manera, por lo que sólo se hablará del turno izquierdo. El cambio de bits se utiliza con mayor frecuencia en criptografía, procesamiento de imágenes y comunicaciones.

Operaciones de cambio de bits de VB.NET....

  • Trabajar sólo con los cuatro tipos de enteros: Byte, corto, entero y largo
  • son operaciones de cambio aritmético. Esto significa que los bits que se desplazan más allá del final del resultado se tiran y las posiciones de bits abiertas en el otro extremo se ponen a cero. La alternativa se denomina desplazamiento de broca circular y las brocas que se desplazan más allá de un extremo se añaden simplemente al otro. VB.NET no soporta el desplazamiento de bits circulares directamente. Si lo necesitas, tendrás que codificarlo a la antigua usanza: multiplicarlo o dividirlo por 2.

  • Nunca genere una excepción de desbordamiento. VB.NET se encarga de cualquier problema posible y le mostraré lo que eso significa. Como ya se ha dicho, puedes codificar tu propio bit shifting multiplicando o dividiendo por 2, pero si usas el método "codifica tu propio", tienes que probar las excepciones de desbordamiento que pueden causar que tu programa se bloquee.

Una operación de cambio de bits estándar se vería algo así:

Dim StartingValue As Integer = 14913080

Dim ValueAfterShifting As Integer

ValueAfterShifting = StartingValue << 50

En otras palabras, esta operación toma el valor binario 0000 0000 0000 1110 0011 1000 1110 0011 1000 (14913080 es el valor decimal equivalente - observe que es sólo una serie de 3 0's y 3 1's repetidos varias veces) y lo desplaza 50 lugares a la izquierda. Pero como un número entero sólo tiene 32 bits de longitud, desplazarlo 50 lugares no tiene sentido.

VB.NET resuelve este problema enmascarando el recuento de turnos con un valor estándar que coincide con el tipo de datos que se está utilizando. En este caso, ValueAfterShifting es un número entero, por lo que el máximo que se puede desplazar es de 32 bits. El valor de la máscara estándar que funciona es 31 decimal o 11111.

Enmascarar significa que el valor, en este caso 50, es Anded con la máscara. Esto da el número máximo de bits que se pueden desplazar para ese tipo de datos.

En decimal:

50 Y 31 es 18 - El número máximo de bits que se pueden desplazar

En realidad, tiene más sentido en binario. Los bits de alto orden que no se pueden utilizar para la operación de cambio de marchas se quitan simplemente.

110010 Y 11111 es 10010

Cuando se ejecuta el fragmento de código, el resultado es 954204160 o, en binario, 0011 1000 1110 0000 0000 0000 0000 0000 0000 0000. Los 18 bits del lado izquierdo del primer número binario se desplazan y los 14 bits del lado derecho se desplazan hacia la izquierda.

El otro gran problema con los bits de desplazamiento es lo que sucede cuando el número de lugares a desplazar es un número negativo. Usemos -50 como el número de bits para cambiar y ver qué pasa.

ValueAfterShifting = StartingValue << -50

Cuando se ejecuta este fragmento de código, obtenemos -477233152 o 1110 0011 1000 1110 0000 0000 0000 0000 0000 0000 en binario. El número se ha desplazado 14 lugares a la izquierda. ¿Por qué 14? VB.NET asume que el número de lugares es un entero sin signo y realiza una operación Y con la misma máscara (31 para enteros).

1111 1111 1111 1111 1111 1111 1100 1110

0000 0000 0000 0000 0000 0000 0001 1111

(And)----------------------------------

0000 0000 0000 0000 0000 0000 0000 1110

1110 en binario es 14 decimal. Fíjese que esto es lo contrario de desplazar 50 posiciones positivas.

En la página siguiente, pasamos a otras operaciones de bits, ¡empezando por Xor Encryption!

Mencioné que uno de los usos de las operaciones de bits es el cifrado. La encriptación Xor es una forma popular y sencilla de "encriptar" un archivo. En mi artículo, Very Simple Encryption using VB.NET, le muestro una mejor manera de usar la manipulación de cadenas. Pero la encriptación Xor es tan común que merece al menos ser explicada.

Cifrar una cadena de texto significa traducirla a otra cadena de texto que no tiene una relación obvia con la primera.

También necesitas una forma de desencriptarlo de nuevo. La encriptación Xor convierte el código ASCII binario de cada carácter de la cadena en otro carácter utilizando la operación Xor. Para hacer esta traducción, necesita otro número para usar en el Xor. Este segundo número se llama la llave.

La encriptación Xor se denomina "algoritmo simétrico". Esto significa que también podemos usar la clave de cifrado como clave de descifrado.

Usemos "A" como clave y encriptemos la palabra "Básico". El código ASCII para "A" es:

0100 0001 (decimal 65)

El código ASCII para Basic es:

B - 0100 0010

a - 0110 0001

s - 0111 0011

i - 0110 1001

c - 0110 0011

El Xor de cada uno de ellos es:

0000 0011 - decimal 3

0010 0000 - decimal 32

0011 0010 - decimal 50

0010 1000 - decimal 40

0010 0010 - decimal 34

Esta pequeña rutina funciona:

-- Xor Encryption --

Dim i As Short

ResultString.Text = ""

Dim KeyChar As Integer

KeyChar = Asc(EncryptionKey.Text)

For i = 1 To Len(InputString.Text)

   ResultString.Text &= _

      Chr(KeyChar Xor _

      Asc(Mid(InputString.Text, i, 1)))

Next

El resultado se puede ver en esta ilustración:

-------

Haga clic aquí para ver la ilustración

Haga clic en el botón Atrás de su navegador para volver

--------

Para revertir la encriptación, simplemente copie y pegue la cadena de la Caja de Texto Resultante en la Caja de Texto de la Cadena y haga clic de nuevo en el botón.

Otro ejemplo de algo que puede hacer con los operadores de bits es intercambiar dos enteros sin declarar una tercera variable para el almacenamiento temporal.

Este es el tipo de cosas que solían hacer en los programas de lenguaje ensamblador hace años. No es muy útil ahora, pero usted podría ganar una apuesta algún día si puede encontrar a alguien que no crea que usted puede hacerlo. En cualquier caso, si todavía tienes preguntas sobre cómo funciona Xor, trabajar en ello debería ponerlas a descansar. Aquí está el código:

Dim FirstInt As Integer

Dim SecondInt As Integer

FirstInt = CInt(FirstIntBox.Text)

SecondInt = CInt(SecondIntBox.Text)

FirstInt = FirstInt Xor SecondInt

SecondInt = FirstInt Xor SecondInt

FirstInt = FirstInt Xor SecondInt

ResultBox.Text = "First Integer: " & _

   FirstInt.ToString & " - " & _

   "Second Integer: " & _

   SecondInt.ToString

Y aquí está el código en acción:

--------

Haga clic aquí para ver la ilustración

Haga clic en el botón Atrás de su navegador para volver

--------

Descubrir exactamente por qué esto funciona quedará como "un ejercicio para el alumno".

En la página siguiente, alcanzamos el objetivo: Manipulación general de bits

Aunque estos trucos son divertidos y educativos, no sustituyen a la manipulación general de bits. Si realmente llegas al nivel de los bits, lo que quieres es una manera de examinar los bits individuales, establecerlos o cambiarlos. Ese es el código real que falta en .NET.

Quizás la razón por la que falta es que no es tan difícil escribir subrutinas que logren lo mismo.

Una razón típica para hacer esto es mantener lo que a veces se llama un byte de bandera.

Algunas aplicaciones, especialmente las escritas en lenguajes de bajo nivel como assembler, mantendrán ocho banderas booleanas en un solo byte. Por ejemplo, el registro de estado de un chip de procesador 6502 contiene esta información en un único byte de 8 bits:

Bit 7. Indicador negativo

Bit 6. Indicador de desbordamiento

Bit 5. Sin usar

Bit 4. Bandera de la ruptura

Bit 3. Indicador decimal

Bit 2. Indicador de interrupción desactivada

Bit 1. Bandera cero

Bit 0. Llevar bandera

(de Wikipedia)

Si su código tiene que trabajar con este tipo de datos, necesita código de manipulación de bits de propósito general. Este código hará el trabajo!

' The ClearBit Sub clears the 1 based, nth bit

' (MyBit) of an integer (MyByte).

Sub ClearBit(ByRef MyByte, ByVal MyBit)

   Dim BitMask As Int16

   ' Create a bitmask with the 2 to the nth power bit set:

   BitMask = 2 ^ (MyBit - 1)

   ' Clear the nth Bit:

   MyByte = MyByte And Not BitMask

End Sub

' The ExamineBit function will return True or False

' depending on the value of the 1 based, nth bit (MyBit)

' of an integer (MyByte).

Function ExamineBit(ByVal MyByte, ByVal MyBit) As Boolean

   Dim BitMask As Int16

   BitMask = 2 ^ (MyBit - 1)

   ExamineBit = ((MyByte And BitMask) > 0)

End Function

' The SetBit Sub will set the 1 based, nth bit

' (MyBit) of an integer (MyByte).

Sub SetBit(ByRef MyByte, ByVal MyBit)

   Dim BitMask As Int16

   BitMask = 2 ^ (MyBit - 1)

   MyByte = MyByte Or BitMask

End Sub

' The ToggleBit Sub will change the state

' of the 1 based, nth bit (MyBit)

' of an integer (MyByte).

Sub ToggleBit(ByRef MyByte, ByVal MyBit)

   Dim BitMask As Int16

   BitMask = 2 ^ (MyBit - 1)

   MyByte = MyByte Xor BitMask

End Sub

Para demostrar el código, esta rutina lo llama (parámetros no codificados en Click Sub):

Private Sub ExBitCode_Click( ...

   Dim Byte1, Byte2 As Byte

   Dim MyByte, MyBit

   Dim StatusOfBit As Boolean

   Dim SelectedRB As String

   StatusLine.Text = ""

   SelectedRB = GetCheckedRadioButton(Me).Name

   Byte1 = ByteNum.Text ' Number to be converted into Bit Flags

   Byte2 = BitNum.Text ' Bit to be toggled

   ' The following clears the high-order byte & returns only the

   ' low order byte:

   MyByte = Byte1 And &HFF

   MyBit = Byte2

   Select Case SelectedRB

      Case "ClearBitButton"

         ClearBit(MyByte, MyBit)

         StatusLine.Text = "New Byte: " & MyByte

      Case "ExamineBitButton"

         StatusOfBit = ExamineBit(MyByte, MyBit)

         StatusLine.Text = "Bit " & MyBit & _

            " is " & StatusOfBit

      Case "SetBitButton"

         SetBit(MyByte, MyBit)

         StatusLine.Text = "New Byte: " & MyByte

      Case "ToggleBitButton"

         ToggleBit(MyByte, MyBit)

         StatusLine.Text = "New Byte: " & MyByte

   End Select

End Sub

Private Function GetCheckedRadioButton( _

   ByVal Parent As Control) _

   As RadioButton

   Dim FormControl As Control

   Dim RB As RadioButton

   For Each FormControl In Parent.Controls

      If FormControl.GetType() Is GetType(RadioButton) Then

         RB = DirectCast(FormControl, RadioButton)

         If RB.Checked Then Return RB

      End If

   Next

   Return Nothing

End Function

El código en acción se ve así:

--------

Haga clic aquí para ver la ilustración

Haga clic en el botón Atrás de su navegador para volver

--------

(0 votes)