1 回答
TA贡献1859条经验 获得超6个赞
使用math.Float64bits()
您可以使用math.Float64bits()
which 返回一个与传递给它的uint64
值具有相同字节/位的值float64
。
一旦有了uint64
,对其执行按位运算就很简单了:
f := 1.0 // Some float64 value
bits := math.Float64bits(f)
if f >= 0 {
bits ^= 0x8000000000000000
} else {
bits ^= 0xffffffffffffffff
}
然后序列化该bits值而不是ffloat64 值,就大功告成了。
让我们看看实际效果。float64让我们创建一个包含数字及其字节的包装器类型:
type num struct {
f float64
data [8]byte
}
让我们创建这些 s 的一部分num:
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)
})
现在让我们看看按字节排序后的顺序:
fmt.Println("Final order byte-wise:")
for _, n := range nums {
fmt.Printf("% .7f %3v\n", n.f, n.data)
}
输出将是(在Go Playground上尝试):
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]
没有math.Float64bits()
另一种选择是先序列化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
}
}
}
其余的是一样的。输出也将相同。
- 1 回答
- 0 关注
- 135 浏览
添加回答
举报