Go 浮点数的字节排序

Go 浮点数的字节排序,go,byte,computer-science,bit,Go,Byte,Computer Science,Bit,我正在研究由BadgerDB()支持的Tormenta()。BadgerDB按字节顺序存储密钥(字节片)。我正在创建包含浮点数的密钥,这些浮点数需要按顺序存储,以便正确使用Badger的密钥迭代。我没有扎实的CS背景,所以我有点不知所措 我对浮点进行如下编码:binary.Write(buf,binary.BigEndian,myFloat)。这对于正浮点很好——键顺序是您所期望的,但是对于负浮点,字节顺序会发生故障 顺便说一句,整数也存在同样的问题,但我可以通过使用math.Float64bi

我正在研究由BadgerDB()支持的Tormenta()。BadgerDB按字节顺序存储密钥(字节片)。我正在创建包含浮点数的密钥,这些浮点数需要按顺序存储,以便正确使用Badger的密钥迭代。我没有扎实的CS背景,所以我有点不知所措

我对浮点进行如下编码:
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
        }
    }
}