我有一个包含cpu_ids的二进制计数(口罩0xA00000800000,我想转换成3级的CPU)string逗号分隔的cpu_ids:"0,2,24"。
0xA00000800000
string
"0,2,24"
我执行了以下Go实施(我是Go入门)。这是最好的方法吗?特别是字节缓冲区的处理似乎效率很低!
package main import ( "fmt" "os" "os/exec" ) func main(){ cpuMap := "0xA00000800000" cpuIds = getCpuIds(cpuMap) fmt.Println(cpuIds) } func getCpuIds(cpuMap string) string { // getting the cpu ids cpu_ids_i, _ := strconv.ParseInt(cpuMap, 0, 64) // int from string cpu_ids_b := strconv.FormatInt(cpu_ids_i, 2) // binary as string var buff bytes.Buffer for i, runeValue := range cpu_ids_b { // take care! go returns code points and not the string if runeValue == '1' { //fmt.Println(bitString, i) buff.WriteString(fmt.Sprintf("%d", i)) } if (i+1 < len(cpu_ids_b)) && (runeValue == '1') { //fmt.Println(bitString) buff.WriteString(string(",")) } } cpuIds := buff.String() // remove last comma cpuIds = cpuIds[:len(cpuIds)-1] //fmt.Println(cpuIds) return cpuIds }
返回值:
“ 0,2,24”
您要做的实际上"1"是从左至右输出二进制表示形式中的的索引,并从左侧开始计数(不常用)。
"1"
您可以使用位掩码和按位运算符来实现相同功能,而无需将其转换为二进制字符串。而且我将返回索引的一部分而不是其格式化的字符串,以便于使用。
要测试最低(最右边)的位是否为1,您可以像一样进行操作x&0x01 == 1,然后将一个整数按位右移:x >>= 1。移位后,最右边的位“消失”,先前的第二位变为第一位,因此您可以使用相同的逻辑再次进行测试。您可以循环播放直到该数字大于0(这意味着底数为1位)。
1
x&0x01 == 1
x >>= 1
当然,如果我们测试最右边的位并向右移动,我们将获得 相反 的位(索引)(与所需值相比),并且索引从右开始计数,因此我们必须在返回结果之前对其进行更正。
因此,解决方案如下所示:
func getCpuIds(cpuMap string) (r []int) { ci, err := strconv.ParseInt(cpuMap, 0, 64) if err != nil { panic(err) } count := 0 for ; ci > 0; count, ci = count+1, ci>>1 { if ci&0x01 == 1 { r = append(r, count) } } // Indices are from the right, correct it: for i, v := range r { r[i] = count - v - 1 } // Result is in reverse order: for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } return }
输出(在Go Playground上尝试):
[0 2 24]
如果由于某种原因您需要将结果以逗号分隔string,则可以通过以下方式获得该结果:
buf := &bytes.Buffer{} for i, v := range cpuIds { if i > 0 { buf.WriteString(",") } buf.WriteString(strconv.Itoa(v)) } cpuIdsStr := buf.String() fmt.Println(cpuIdsStr)
0,2,24