Go 浮点数的字节排序
我正在研究由BadgerDB()支持的Tormenta()。BadgerDB按字节顺序存储密钥(字节片)。我正在创建包含浮点数的密钥,这些浮点数需要按顺序存储,以便正确使用Badger的密钥迭代。我没有扎实的CS背景,所以我有点不知所措 我对浮点进行如下编码:Go 浮点数的字节排序,go,byte,computer-science,bit,Go,Byte,Computer Science,Bit,我正在研究由BadgerDB()支持的Tormenta()。BadgerDB按字节顺序存储密钥(字节片)。我正在创建包含浮点数的密钥,这些浮点数需要按顺序存储,以便正确使用Badger的密钥迭代。我没有扎实的CS背景,所以我有点不知所措 我对浮点进行如下编码:binary.Write(buf,binary.BigEndian,myFloat)。这对于正浮点很好——键顺序是您所期望的,但是对于负浮点,字节顺序会发生故障 顺便说一句,整数也存在同样的问题,但我可以通过使用math.Float64bi
binary.Write(buf,binary.BigEndian,myFloat)
。这对于正浮点很好——键顺序是您所期望的,但是对于负浮点,字节顺序会发生故障
顺便说一句,整数也存在同样的问题,但我可以通过使用math.Float64bits()
b[0]^=1翻转整数上的符号位来相对轻松地解决这个问题
您可以使用它返回一个uint64
值,该值与传递给它的float64
值具有相同的字节/位
一旦有了一个uint64
,对它执行位操作就很简单了:
f := 1.0 // Some float64 value
bits := math.Float64bits(f)
if f >= 0 {
bits ^= 0x8000000000000000
} else {
bits ^= 0xffffffffffffffff
}
然后序列化位
值而不是f
float64值,就完成了
让我们看看这一行动。让我们创建一个包含float64
数字及其字节的包装器类型:
type num struct {
f float64
data [8]byte
}
让我们从这些num
s中创建一个片段:
nums := []*num{
{f: 1.0},
{f: 2.0},
{f: 0.0},
{f: -1.0},
{f: -2.0},
{f: math.Pi},
}
序列化它们:
for _, n := range nums {
bits := math.Float64bits(n.f)
if n.f >= 0 {
bits ^= 0x8000000000000000
} else {
bits ^= 0xffffffffffffffff
}
if err := binary.Write(bytes.NewBuffer(n.data[:0]), binary.BigEndian, bits); err != nil {
panic(err)
}
}
这就是我们如何按字节对它们进行排序:
sort.Slice(nums, func(i int, j int) bool {
ni, nj := nums[i], nums[j]
for k := range ni.data {
if bi, bj := ni.data[k], nj.data[k]; bi < bj {
return true // We're certain it's less
} else if bi > bj {
return false // We're certain it's not less
} // We have to check the next byte
}
return false // If we got this far, they are equal (=> not less)
})
输出将是(在上尝试):
不带math.float64位()
另一个选项是首先序列化float64
值,然后对字节执行异或操作
如果数字为正数(或零),则将第一个字节与0x80
进行异或,其余字节与0x00
进行异或,这基本上与它们无关
如果数字为负数,则用0xff
对所有字节进行异或运算,这基本上是一种按位求反
实际操作:唯一不同的部分是序列化和XOR操作:
for _, n := range nums {
if err := binary.Write(bytes.NewBuffer(n.data[:0]), binary.BigEndian, n.f); err != nil {
panic(err)
}
if n.f >= 0 {
n.data[0] ^= 0x80
} else {
for i, b := range n.data {
n.data[i] = ^b
}
}
}
其余的都一样。输出也将是相同的。试一试这个。对此我感激不尽——你真的了解我需要的帮助程度。我需要研究一下,找出哪一个最好。我一做完就回来报告。再次感谢。好的-我调整了你的第二个解决方案,以获得最终有效的解决方案!!因为我只写了
[]字节
,而没有原始的数字,所以我创建了这两个函数:func flipFloat(b[]字节)[]字节{if b[0]>>7>0{for I,bb:=范围b{b[I]=^bb}else{b[0]^=0x80}返回b}func flipFloatBack(b[]字节)[]字节{if b[0]>>7>0{b[0]^=0x80}else{对于i,bb:=范围b{b[i]=^bb}}返回b}
Final order byte-wise:
-2.0000000 [ 63 255 255 255 255 255 255 255]
-1.0000000 [ 64 15 255 255 255 255 255 255]
0.0000000 [128 0 0 0 0 0 0 0]
1.0000000 [191 240 0 0 0 0 0 0]
2.0000000 [192 0 0 0 0 0 0 0]
3.1415927 [192 9 33 251 84 68 45 24]
for _, n := range nums {
if err := binary.Write(bytes.NewBuffer(n.data[:0]), binary.BigEndian, n.f); err != nil {
panic(err)
}
if n.f >= 0 {
n.data[0] ^= 0x80
} else {
for i, b := range n.data {
n.data[i] = ^b
}
}
}