转换大。Int to [2]int64,反之亦然,二的补码



我正在尝试转换 Go big。Int,表示 [2]int64 的 128 位整数。这个想法是能够匹配 Rust 的 i128::to_le_bytes(),它将 128 位有符号整数编码为小端字节顺序。该示例与 Rust 的i128::to_le_bytes()匹配。每当我尝试将其转换回大时。Int,我没有得到相同的值。在进行初始右移时是否有任何损失?谢谢。

package main

import (
"encoding/binary"
"fmt"
"math/big"
)

func main() {
initial := new(big.Int)
initial.SetString("-42", 10)

value, _ := new(big.Int).SetString("-42", 10)

var result [2]int64

result[0] = value.Int64()
result[1] = value.Rsh(value, 64).Int64()

leRepresentation := make([]byte, 16)

binary.LittleEndian.PutUint64(leRepresentation[:8], uint64(result[0]))
binary.LittleEndian.PutUint64(leRepresentation[8:], uint64(result[1]))

fmt.Println(leRepresentation)

fmt.Println(result)

reverse := big.NewInt(result[1])
reverse.Lsh(reverse, 64)
reverse.Add(reverse, big.NewInt(result[0]))

fmt.Println(reverse.String())

fmt.Println(initial.String() == reverse.String())
}

这里有许多问题:

value不能用int64表示,所以value.Int64()的结果是不确定的。

您的较低位没有考虑Int64的有符号结果,因此您可能会在结果中添加负数。您需要使用uint64(或至少在将其添加到big.Int之前对其进行转换)。

您正在Rsh方法中改变value,因此即使正确重新创建值,最后的比较也会失败。如果要比较原始值,请创建一个新big.Int来存储原始值。

如果要为big.Int提供正好 128 位的原始数据表示形式,可以使用FillBytes方法。我们可以获取大端数据并构建 2 个 64 位值,如下所示:

b := make([]byte, 16)
value.FillBytes(b)  
var result [2]uint64
result[0] = binary.BigEndian.Uint64(b[:8])
result[1] = binary.BigEndian.Uint64(b[8:])

现在字节顺序是固定的,将符号位添加到结果中。然而,为了使这项工作像int128,我们需要使用两个人的赞美来设置标志

const sign = uint64(1 << 63)
if value.Sign() < 0 {
// convert the unsigned value to two's compliment
result[0] = ^result[0]
result[1] = ^result[1]
result[1]++
// check for carry
if result[1] == 0 {
result[0]++
}
}

要创建新big.Int,请反转整个过程:

neg := uint128[0]&sign != 0
if neg {
// reverse the two's compliment
if uint128[1] == 0 {
uint128[0]--
}
uint128[1]--
uint128[0] = ^uint128[0]
uint128[1] = ^uint128[1]
}
b := make([]byte, 16)
binary.BigEndian.PutUint64(b[:8], uint128[0])
binary.BigEndian.PutUint64(b[8:], uint128[1])
result := new(big.Int).SetBytes(b)
if neg {
result.Neg(result)
}

测试多个键值的示例:https://go.dev/play/p/E1E-5CilFlr

由于输出是作为无符号值写入的,因此如果可以从 MaxInt128>值开始,则还应添加检查以确保不会溢出有符号值。将它们存储为[2]int64要混乱得多,因为我们需要 uint64 值进行按位运算,并且我们需要确保int64值不会通过它们自己的两个的补充进行滚动。在这种情况下,更容易将[2]int64与给定函数周围的[2]uint64相互转换。

相关内容

  • 没有找到相关文章

最新更新