ElloU
ElloU

Reputation: 67

Convert a hexadecimal number to binary in Go and be able to access each bit

I am fiddling around with Go at the moment and have stumpled upon a problem where I want to get some feedback and help :)

My problem is that I have a string containing a hexadecimal value as input, such as this:

"60A100"

Now, I want to convert this to the binary representation of the number and be able to look at specific bits within.

My solution to this right now is:

i, err := strconv.ParseUint(rawHex, 16, 32)
if err != nil {
    fmt.Printf("%s", err)
}

// Convert int to binary representation
// %024b indicates base 2, padding with 0, with 24 characters.
bin := fmt.Sprintf("%024b", i)

The variable bin now holds exactly what I want, except it is a string which I don't think is optimal. I would rather that I could have an array of the individual bits such that I could just choose index i to get bit number i :)

Because as far as I know right now, if I lookup index 8 like so; bin[8], I will get a decimal that corresponds to the binary number, in the ASCII table.

I have searched quite a bit, but I can't find a solution that fits perfectly, but maybe I am looking in the wrong spot.

I hope you guys can guide me to the correct / optimal solution in this case :)

Thanks in advance!

Upvotes: 1

Views: 8272

Answers (3)

dinigo
dinigo

Reputation: 7438

Following @n-carter answer, you can access each bit individually

There are two approaches:

Option 1: Shifting the value:

Shift the bin number to the right n possitions to get the n-th bit the first one. then mask it with 1

func getNthBit(val, n uint32) int {
    // 1. reverse the golang endian
    nthBit := 32-n
    // 2. move the nth bit to the first position
    movedVal := val >> nthBit
    // 3. mask the value, selecting only this first bit
    maskedValue := movedVal & 1
    return maskedValue
    // can be shortened like so
    // return (val >> (32-n)) & 1
}

Explanation:

1. Get the right bit index according to the endian
01100000101000010000000001000101
  ^
(32-3)=29nth bit

2. Shift the bits to get n-th in the first possition
01100000101000010000000001000101 >> 29
^^^
00000000000000000000000000000011
                             ^^^

3. Mask first bit. This picks(extracts) the value from this bit
00000000000000000000000000000011
&                              ^
00000000000000000000000000000001
                               1

Option 2: shifting 1 and masking with it

This can be done the way @n-carter does. Shift a 1 to the left

func getNthBit(val, n uint32) int {
    // 1. reverse the golang endian
    nthBit := 32-n
    // 2. move the mask 1 bit to the nth position
    mask := 1 << nthBit
    // 3. mask the value, selecting only this nth bit
    maskedValue := val & mask
    if maskedValue == 0 {
        return 0
    }
    return 1
    // can be written shorter like:
    //if val & (1 << (32-n)) == 0 {
    //    return 0
    //}
    //return 1

}

Explanation:

1. Get the right bit index according to the endian
01100000101000010000000001000101
  ^
(32-3)=29nth bit

2. Shift the 1 to the n-th position (1 << 29 == 2^(29-1))
00000000000000000000000000000001 << 29
00100000000000000000000000000000

3. Mask n-th bit. This picks(extracts) the value from this bit
01100000101000010000000001000101
&
00100000000000000000000000000000
  1

Hope this helps. It takes some time to visualise bit operations in your head.

Upvotes: 2

sberry
sberry

Reputation: 132018

You could turn it into a slice representing bits

// This could also return []bool
func asBits(val uint64) []uint64 {
    bits := []uint64{}
    for i := 0; i < 24; i++ {
        bits = append([]uint64{val & 0x1}, bits...)
        // or
        // bits = append(bits, val & 0x1)
        // depending on the order you want
        val = val >> 1
    }
    return bits
}

func main() {
    rawHex := "60A100"
    i, err := strconv.ParseUint(rawHex, 16, 32)
    if err != nil {
        fmt.Printf("%s", err)
    }
    fmt.Printf("%024b\n", i)

    fmt.Println(asBits(i))

}

OUTPUT

011000001010000100000000
[0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0]

https://play.golang.org/p/KK_AUPgbZu

As @jimb points out, you can also just check an individual bit

fmt.Printf("9th bit is set? %t\n", (i >> 8) & 1 == 1)

which is what @n-carter's answer does.

Upvotes: 2

n-canter
n-canter

Reputation: 288

After parsing the value you can directly access each bit. You can use something like this:

func getNthBit(val, n uint32) int {
    n = 32 - n
    if 1 << n & val > 0 {
        return 1
    }
    return 0
}

Upvotes: 2

Related Questions