英文:
Bitmasking conversion of CPU ids with Go
问题
我有一个包含cpu_ids的二进制计数的掩码(对于3个CPU,为0xA00000800000
),我想将其转换为逗号分隔的cpu_ids字符串:"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 {
// 获取cpu ids
cpu_ids_i, _ := strconv.ParseInt(cpuMap, 0, 64) // 将字符串转换为整数
cpu_ids_b := strconv.FormatInt(cpu_ids_i, 2) // 转换为二进制字符串
var buff bytes.Buffer
for i, runeValue := range cpu_ids_b {
// 注意!Go返回的是码点而不是字符串
if runeValue == '1' {
buff.WriteString(fmt.Sprintf("%d", i))
}
if (i+1 < len(cpu_ids_b)) && (runeValue == '1') {
buff.WriteString(string(","))
}
}
cpuIds := buff.String()
// 移除最后一个逗号
cpuIds = cpuIds[:len(cpuIds)-1]
return cpuIds
}
返回结果:
"0,2,24"
英文:
I have a mask that contains a binary counting of cpu_ids (0xA00000800000
for 3 CPUs) which I want to convert into a string
of comma separated cpu_ids: "0,2,24"
.
I did the following Go implementation (I am a Go starter). Is it the best way to do it? Especially the handling of byte buffers seems to be inefficient!
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
}
Returns:
> "0,2,24"
答案1
得分: 3
你正在做的事情实际上是从左到右输出二进制表示中"1"
的索引,并从左侧开始计数索引(不寻常)。
你可以使用位掩码和位运算符实现相同的功能,而无需将其转换为二进制字符串。我会返回索引的切片,而不是格式化的字符串,这样更容易处理。
要测试最低(最右边)的位是否为1
,可以使用x&0x01 == 1
,要将一个整数按位右移:x >>= 1
。移位后,最右边的位"消失",之前的第二位变为第一位,因此可以使用相同的逻辑再次进行测试。可以循环直到数字大于0(这意味着它仍然有1位)。
请参阅此问题以获取更多位运算的示例:https://stackoverflow.com/questions/28432398/difference-between-some-operators-golang/28433370#28433370
当然,如果我们测试最右边的位并向右移位,我们会得到_相反顺序_的位(与您想要的相比),并且索引是从右边计数的,因此在返回结果之前我们必须进行修正。
因此,解决方案如下:
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)
}
}
// 索引是从右边计数的,进行修正:
for i, v := range r {
r[i] = count - v - 1
}
// 结果是相反顺序的:
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)
输出(在Go Playground上尝试):
0,2,24
英文:
What you're doing is essentially outputting the indices of the "1"
's in the binary representation from left-to-right, and starting index counting from the left (unusal).
You can achieve the same using bitmasks and bitwise operators, without converting it to a binary string. And I would return a slice of indices instead of its formatted string, easier to work with.
To test if the lowest (rightmost) bit is 1
, you can do it like x&0x01 == 1
, and to shift a whole number bitwise to the right: x >>= 1
. After a shift, the rightmost bit "disappears", and the previously 2nd bit becomes the 1st, so you can test again with the same logic. You may loop until the number is greater than 0 (which means it sill has 1-bits).
See this question for more examples of bitwise operations: https://stackoverflow.com/questions/28432398/difference-between-some-operators-golang/28433370#28433370
Of course if we test the rightmost bit and shift right, we get the bits (indices) in reverse order (compared to what you want), and the indices are counted from right, so we have to correct this before returning the result.
So the solution looks like this:
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
}
Output (try it on the Go Playground):
[0 2 24]
If for some reason you need the result as a comma separated string
, this is how you can obtain that:
buf := &bytes.Buffer{}
for i, v := range cpuIds {
if i > 0 {
buf.WriteString(",")
}
buf.WriteString(strconv.Itoa(v))
}
cpuIdsStr := buf.String()
fmt.Println(cpuIdsStr)
Output (try it on the Go Playground):
0,2,24
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论