Blog : Convert values between decimal, hexadecimal, octal, and binary


Title    Convert values between decimal, hexadecimal, octal, and binary


Keywords    convert, decimal, hexadecimal, octal, binary, base
Categories    Algorithms

Decimal, hexadecimal, and octal representations are straightforward. To read a string in these formats, use CLng. Hexadecimal strings should begin with &H and octal strings should begin with &O.

To convert a value into a decimal, hexadecimal, or octal string representation, use Format$, Hex$, and Oct$ respectively. For example, Oct$(256) returns the octal representation of the value 256 (which is "400").

Working with binary values is trickier, largely because the leftmost bit in a number determines its sign. For example, the value &H7FFFFFFF has leftmost bit 0 and its decimal value is 2147483647. Adding 1 to this gives &H80000000 in hexadecimal. That value has its leftmost bit 1 and its decimal value is -2147483648.

A cool trick for working with binary values (pointed out to me by Chris Wagg) is to look at the digits in the number's hexadecimal digits individually. Rather than trying to work with the number's leftmost bits, pull them off the number and consider them separately. Then concatenate the results of working with the digits separately.

For example, consider the value &H80000000. The leftmost hexadecimal digit is 8. It's not too hard to convert the hexadecimal value 8 into the binary value 1000. Similarly you can convert the 0s into 0000. Then you can concatenate thes results to get &H80000000 = &B10000000 00000000 00000000 00000000 (I add the &B for consistency, it's not part of VB).

  Interesting Fact: Half of a byte is called a nibble. Honest, I'm not making this up! A byte has a left nibble and a right nibble. This technique considers numbers one nibble at a time.

You reverse this process when you want to convert a binary representation into a numeric value. Consider the binary digits in groups of 4. Convert each group into a hexadecimal digit and concatenate them. When you're done, you can use CLng to convert the hexadecimal value into a numeric value if you like.

Now to some code. Subroutine DisplayValue uses CLng or the BinaryToLong function to convert a string value from decimal, hexadecimal, octal, or binary into a Long variable. It then uses Format$, Hex$, Oct$, and LongToBinary to display the value in different formats.

' Display the value in the indicated control in
' the other controls.
Private Sub DisplayValue(ByVal source As TextBox)
Dim txt As String
Dim value As Long

  ' Don't recurse.
  If m_IgnoreEvents Then Exit Sub
  m_IgnoreEvents = True

  ' Get the value.
  On Error Resume Next
  Select Case source.Name
  Case "txtDecimal"
  value = CLng(source.Text)
  Case "txtHexadecimal"
  txt = UCase$(Trim$(source.Text))
  If Left$(txt, 2) <> "&H" Then txt = "&H" & txt
  value = CLng(txt)
  Case "txtOctal"
  txt = UCase$(Trim$(source.Text))
  If Left$(txt, 2) <> "&O" Then txt = "&O" & txt
  value = CLng(txt)
  Case "txtBinary"
  value = BinaryToLong(source.Text)
  End Select
  On Error GoTo 0

  ' Display the value in different formats.
  If source.Name <> "txtDecimal" Then
  txtDecimal.Text = Format$(value)
  End If
  If source.Name <> "txtHexadecimal" Then
  txtHexadecimal.Text = "&H" & Hex$(value)
  End If
  If source.Name <> "txtOctal" Then
  txtOctal.Text = "&O" & Oct$(value)
  End If
  If source.Name <> "txtBinary" Then
  txtBinary.Text = LongToBinary(value)
  End If

  m_IgnoreEvents = False
End Sub

Function BinaryToLong reads the binary bits that make up each nibble in the value. For each nibble, it calculates the nibble's value. It uses Hex$ to concatenate the nibble values into a hexadecimal string and finally uses CLng to convert the result into a Long value.

' Convert this binary value into a Long.
Private Function BinaryToLong(ByVal binary_value As String) _
  As Long
Dim hex_result As String
Dim nibble_num As Integer
Dim nibble_value As Integer
Dim factor As Integer
Dim bit As Integer

  ' Remove any leading &B if present.
  ' (Note: &B is not a standard prefix, it just
  ' makes some sense.)
  binary_value = UCase$(Trim$(binary_value))
  If Left$(binary_value, 2) = "&B" Then binary_value = _
  Mid$(binary_value, 3)

  ' Strip out spaces in case the bytes are separated
  ' by spaces.
  binary_value = Replace(binary_value, " ", "")

  ' Left pad with zeros so we have a full 32 bits.
  binary_value = Right$(String(32, "0") & binary_value, _
  32)

  ' Read the bits in nibbles from right to left.
  ' (A nibble is half a byte. No kidding!)
  For nibble_num = 7 To 0 Step -1
  ' Convert this nibble into a hexadecimal string.
  factor = 1
  nibble_value = 0

  ' Read the nibble's bits from right to left.
  For bit = 3 To 0 Step -1
  If Mid$(binary_value, 1 + nibble_num * 4 + bit, _
  1) = "1" Then
  nibble_value = nibble_value + factor
  End If
  factor = factor * 2
  Next bit

  ' Add the nibble's value to the left of the
  ' result hex string.
  hex_result = Hex$(nibble_value) & hex_result
  Next nibble_num

  ' Convert the result string into a long.
  BinaryToLong = CLng("&H" & hex_result)
End Function

Function LongToBinary uses Hex$ to create a hexadecimal representation of a Long value. It then examines each hexadecimal digit and converts them into binary.

' Convert this Long value into a binary string.
Private Function LongToBinary(ByVal long_value As Long, _
  Optional ByVal separate_bytes As Boolean = True) As _
  String
Dim hex_string As String
Dim digit_num As Integer
Dim digit_value As Integer
Dim nibble_string As String
Dim result_string As String
Dim factor As Integer
Dim bit As Integer

  ' Convert into hex.
  hex_string = Hex$(long_value)

  ' Zero-pad to a full 8 characters.
  hex_string = Right$(String$(8, "0") & hex_string, 8)

  ' Read the hexadecimal digits
  ' one at a time from right to left.
  For digit_num = 8 To 1 Step -1
  ' Convert this hexadecimal digit into a
  ' binary nibble.
  digit_value = CLng("&H" & Mid$(hex_string, _
  digit_num, 1))

  ' Convert the value into bits.
  factor = 1
  nibble_string = ""
  For bit = 3 To 0 Step -1
  If digit_value And factor Then
  nibble_string = "1" & nibble_string
  Else
  nibble_string = "0" & nibble_string
  End If
  factor = factor * 2
  Next bit

  ' Add the nibble's string to the left of the
  ' result string.
  result_string = nibble_string & result_string
  Next digit_num

  ' Add spaces between bytes if desired.
  If separate_bytes Then
  result_string = _
  Mid$(result_string, 1, 8) & " " & _
  Mid$(result_string, 9, 8) & " " & _
  Mid$(result_string, 17, 8) & " " & _
  Mid$(result_string, 25, 8)
  End If

  ' Return the result.
  LongToBinary = result_string
End Function