如何在golang中获取字节的位?

14

我想要计算两个字节之间的海明距离,例如

HammingDist(byte(255), byte(0)) == 8

我需要获取每个字节中的位,但是我在任何内置包中都找不到相应的函数。因此,如果给定byte(1),如何获得其二进制表示形式00000001?


你可以像 https://play.golang.org/p/Wyr_K9YAro 中那样使用 BitReader。 - dmitryro
5个回答

28
你可以使用fmt.Sprintf("%08b", ...)来看到位的可视化表示,正如其他人已经建议的那样。
然而,如果你想在操作中使用这些位,比如用于计算汉明距离,你需要使用位运算符
要计算一个字节的第n位,你需要将该字节与另一个字节进行位与运算,这个字节的第n位设置为1,其余位设置为0(也称为掩码)。换句话说,那个另外的字节(掩码)就是2n-1
例如,要找到数字13(00001101)的第1位,我们需要将它与20 = 1(00000001)进行掩码操作。我们将对这两个数字进行位与运算的输出与掩码进行比较。如果它们相等,意味着第n位为1,否则为0。我们继续这样找到所有的位。以下是用Go代码进行说明:
fmt.Print(13 & 1) // Output: 1 -> 1
fmt.Print(13 & 2) // Output: 0 -> 0
fmt.Print(13 & 4) // Output: 4 -> 1
fmt.Print(13 & 8) // Output: 8 -> 1
// Not necessary to continue, but shown for the sake of the example
fmt.Print(13 & 16) // Output: 0 -> 0
fmt.Print(13 & 32) // Output: 0 -> 0
fmt.Print(13 & 64) // Output: 0 -> 0
fmt.Print(13 & 128) // Output: 0 -> 0

因此,十进制数13在二进制中表示为00001101。
以下是我最近编写的一个函数,用于计算两个字节数组之间的汉明距离。在你的情况下,只需传递一个由单个字节组成的数组即可。
func hamming(a, b []byte) (int, error) {
    if len(a) != len(b) {
        return 0, errors.New("a b are not the same length")
    }

    diff := 0
    for i := 0; i < len(a); i++ {
        b1 := a[i]
        b2 := b[i]
        for j := 0; j < 8; j++ {
            mask := byte(1 << uint(j))
            if (b1 & mask) != (b2 & mask) {
                diff++
            }
        }
    }
    return diff, nil
}

Go Playground: https://play.golang.org/p/O1EGdzDYAn

2
只是好奇,你知道为什么“%b”单独只显示6位吗? - Matt

7

fmt.Sprintf("%08b", byte(1)) 是一个好方法。它展示了数字的内部存储方式。计算汉明距离的示例(非常无聊)可能如下:

package main

import (
    "fmt"
)

func HamDist(n1,n2 uint8) uint8 {
    var w uint8 = 0
    if n1&1 != n2&1 {
        w++
    }
    if n1&2 != n2&2 {
        w++
    }
    if n1&4 != n2&4 {
        w++
    }
    if n1&8 != n2&8 {
        w++
    }
    if n1&16 != n2&16 {
        w++
    }
    if n1&32 != n2&32 {
        w++
    }
    if n1&64 != n2&64 {
        w++
    }
    if n1&128 != n2&128 {
        w++
    }
    return w
}

func main() {
    fmt.Println(HamDist(255,0))
}

现在给你一些任务:

  1. 使用循环重写代码。
  2. 扩展程序以计算16位数字的汉明距离。
  3. 请思考异或运算符的作用,并考虑是否应该定义一个计算汉明重量的函数来更轻松地计算汉明距离。

1
非常好的回答,教育性的而不是直接给出解决方案。继续保持! - janos

5
import "math/bits"

bits.OnesCount8(byte(0) ^ byte(255))

这让我的性能大幅提升。谢谢。(确切地说是10倍) - Mert Gülsoy

3
您可以简单地执行以下操作:
fmt.Printf("%08b", YourNumber)

您也可以使用%016b%032b或其他任何格式。


0
这里有一些很好的答案,但计算两个字节之间的汉明距离的另一种方法是对它们进行异或运算并计算1的数量(权重)。我知道的最简单的计算1的方法是通过用1进行掩码处理,然后向右移位来获取最后一位。
这是我在golang中编写的一个函数,用于计算两个字符串之间的汉明距离。
func HammingDistance(s1, s2 string) (int, error) {
    if len(s1) != len(s2) {
        return 0, fmt.Errorf("Hamming distance of strings of different lengths %d and %d", len(s1), len(s2))
    }
    b1 := []byte(s1)
    b2 := []byte(s2)
    distance := 0
    for i := range b1 {
        xored := b1[i] ^ b2[i]
        for j := 0; j < 8; j++ {
            distance += int(xored & 1)
            xored = xored >> 1
        }
    }
    return distance, nil
}

要计算两个字节的汉明距离,您只需要内部for循环。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接