Heim > Artikel > Backend-Entwicklung > Konvertieren Sie big.Int in int64 und umgekehrt sowie das Zweierkomplement
Der PHP-Editor Yuzi zeigt Ihnen, wie Sie big.Int in PHP in int64 konvertieren und wie Sie int64 in big.Int konvertieren. In der Computerprogrammierung sind big.Int und int64 zwei verschiedene Datentypen. big.Int wird zur Verarbeitung großer Ganzzahlen verwendet, während int64 ein 64-Bit-Ganzzahltyp mit Vorzeichen ist. Bei der Typkonvertierung müssen wir auf das Konzept des Zweierkomplements achten, das eine Möglichkeit zur Darstellung vorzeichenbehafteter Ganzzahlen in Computern darstellt. Als nächstes werden wir den Konvertierungsprozess zwischen diesen beiden Typen detailliert beschreiben.
Ich versuche go big.int, das eine 128-Bit-Ganzzahl darstellt, in [2]int64 zu konvertieren. Die Idee besteht darin, eine Übereinstimmung mit i128::to_le_bytes() von Rust herzustellen, das 128-Bit-Ganzzahlen mit Vorzeichen in Little-Endian-Bytereihenfolge kodiert. Dieses Beispiel passt zu Rusts i128::to_le_bytes()
. Immer wenn ich versuche, es wieder in big.int zu konvertieren, erhalte ich nicht den gleichen Wert. Gehen bei der anfänglichen Rechtsverschiebung irgendwelche Bits verloren? Danke.
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()) }
Viele Fragen hier:
Das Ergebnis vonvalue
无法用 int64
表示,因此 value.int64()
ist undefiniert.
Ihre unteren Bits werden vor der Konvertierung nicht berücksichtigt int64
的签名结果,因此您可能会在结果中添加负数。您需要使用 uint64
(或者至少在将其添加到 big.int
).
Sie rsh
方法中改变 value
,因此即使正确重新创建了该值,最后的比较也会失败。如果要比较的话,新建一个 big.int
speichern den ursprünglichen Wert.
Wenn Sie möchten big.int
的原始数据表示形式恰好为 128 位,您可以使用 fillbytes
Methode. Wir können Big-Endian-Daten nehmen und zwei 64-Bit-Werte wie folgt erstellen:
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:])
Da nun die Bytereihenfolge festgelegt ist, fügen Sie das Vorzeichenbit zum Ergebnis hinzu. Damit es jedoch wie int128
funktioniert, müssen wir das Symbol
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]++ } }
Um ein neues big.int
zu erstellen, kehren Sie den gesamten Vorgang um:
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) }
Beispiel für das Testen mehrerer Schlüsselwerte: https://go.dev/play/ p/e1e-5cilflr
Da die Ausgabe als vorzeichenloser Wert geschrieben wird, sollten Sie, wenn Sie mit einem Wert > maxint128 beginnen können, auch eine Prüfung hinzufügen, um sicherzustellen, dass vorzeichenbehaftete Werte nicht überlaufen. Es ist einfacher, sie ineinander umzuwandeln, indem man sie als [2]int64
会更加混乱,因为我们需要 uint64 值进行按位运算,并且我们需要确保 int64
值不会通过它们自己的补码进行滚动。在这种情况下,围绕给定函数将 [2]int64
与 [2]uint64
speichert.
Das obige ist der detaillierte Inhalt vonKonvertieren Sie big.Int in int64 und umgekehrt sowie das Zweierkomplement. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!