[JAVA] Bitarithmetik des Binärwerts mit BigInteger

Da Java nicht viele praktische Funktionen zum Behandeln von Binärwerten hat, wird der Wertübergabeprozess zwischen Bits (Array) selbst implementiert, um Bitoperationen an einem Byte-Array auszuführen, in dem Binärwerte gespeichert sind. müssen es tun.

Eine häufig verwendete Methode besteht darin, das Byte-Array einmal in einem Integer-Typ wie dem Int-Typ oder dem Long-Typ zu speichern, eine Bitoperation auszuführen und es dann erneut an das Byte-Array zurückzugeben. Bei dieser Methode beträgt die maximale Länge 8 Byte. Kann nur bis zu.

Mit BigInteger-Klasse können Sie Byte-Arrays beliebiger Größe, aber Datenkonvertierung verarbeiten Ich muss ein wenig überlegen, also habe ich die Punkte zusammengefasst.

So führen Sie eine Bitoperation des Byte-Arrays mit BigInteger durch

Die Bitoperation des Bytearrays mit BigInteger kann wie folgt durchgeführt werden.

  1. Lesen Sie das Byte-Array als positive Zahl in BigInteger ein.
  1. Führen Sie verschiedene Operationen mit den Methoden der BigInteger-Instanz aus.
  1. Konvertieren Sie BigInteger erneut in ein Byte-Array.

Implementierungsbeispiel

Punkt 1: Halten Sie BigInteger immer positiv

Wenn der Wert von BigInteger negativ wird, funktioniert dies möglicherweise nicht.

Arithmetische Verschiebungsersetzung für logische Verschiebung

In BigInteger sind nur arithmetische Verschiebungen implementiert. (Da BigInteger eine Klasse für die Behandlung numerischer Werte ist, ohne die Byte-Zeichenfolgen zu kennen, hat die logische Verschiebung keine Bedeutung.) Daher muss die arithmetische Verschiebung durch logische Verschiebung ersetzt werden, negative Zahlen jedoch durch rechte Verschiebung Die Ergebnisse unterscheiden sich zwischen arithmetischen und logischen Verschiebungen.

1010 1010 --1 Bit logische Rechtsverschiebung--> 0101 0101
1010 1010 --1bit arithmetische Rechtsverschiebung--> 1101 0101 #Das Ergebnis unterscheidet sich von der logischen Verschiebung.

Daher muss der Wert von BigInteger so konvertiert werden, dass er immer eine positive Zahl ist. Dieser Konvertierungsprozess muss jedes Mal nach dem Lesen des ersten Byte-Arrays und jeder Operation ausgeführt werden.

1010 1010
  --Als Positiv in BigInteger konvertieren--> 0000 1010 1010
  --1bit arithmetische Rechtsverschiebung--> 0000 0101 0101 #Das Ergebnis ist das gleiche wie die logische Verschiebung.

Es gibt zwei Möglichkeiten, BigInteger zu einer positiven Zahl zu machen: Eine besteht darin, das Codebit anzugeben und das Bytearray zu lesen, und die andere darin, das Codebit durch Maskenverarbeitung auf 1 zu ändern. Die Maskenverarbeitung kann auch für den später beschriebenen Zweck von Punkt 2 verwendet werden Es ist einfach zu machen.

//Eingabebyte-Array: c0 00
byte[] input = new Bytes(new byte[] {(byte) 0xc0, (byte) 0x00}).toByteArray();

//Lesen als positive Zahl (Vorzeichenbit ist 0)
// 00 c0 00
new BigInteger(1, input).toByteArray();

//So ändern Sie das Codebit durch Maskieren auf 0
// ff c0 00 (Eingang) AND 00 ff ff (Maske) => 00 c0 00
//* In der AND-Operation von BigInteger, die eine andere Größe hat, wenn sie in ein Byte-Array umgewandelt wird,
//Der kleinere wird erweitert, um dem größeren zu entsprechen.
BigInteger mask = new BigInteger(1, new Bytes(new byte[] {(byte) 0xff, (byte) 0xff}).toByteArray());
new BigInteger(input).and(mask).toByteArray();

Punkt 2: Halten Sie jedes Bit des extra hohen Bytes bei 0

Wenn eine Inkrementierung / Dekrementierung für eine BigInteger-Instanz durchgeführt wird und der Bereich, der durch die ursprüngliche Anzahl von Bytes ausgedrückt werden kann, überschritten wird, oder wenn eine Linksverschiebungsoperation ausgeführt wird, werden die Daten in Bytes angezeigt, die höher als die ursprüngliche Anzahl von Bytes sind. Es kann bleiben.

Da diese zusätzlichen Bytedaten höherer Ordnung die Verschiebungsoperation in der nachfolgenden Verarbeitung beeinflussen, ist es notwendig, jedes Bit nach jeder Operation auf 0 zu löschen. Dies kann gleichzeitig mit dem in Punkt 1 beschriebenen Maskierungsprozess erfolgen.

//Eingabebyte-Array: c0 00
byte[] input = new Bytes(new byte[] {(byte) 0xc0, (byte) 0x00}).toByteArray();
BigInteger mask = new BigInteger(1, new Bytes(new byte[] {(byte) 0xff, (byte) 0xff}).toByteArray());
//Die Verschiebungsberechnung wird in der Reihenfolge der 1-Bit-Linksverschiebung und der 1-Bit-Rechtsverschiebung durchgeführt.
//Ursprünglich wird das höchstwertige 1-Bit verworfen und es wird 80 00, aber es kehrt zum ursprünglichen c 0 00 zurück.
new BigInteger(input).and(mask).shiftLeft(1).shiftRight(1);

Punkt 3: Passen Sie die Anzahl der Bytes an, wenn Sie BigInteger an ein Byte-Array zurückgeben

toByteArray-Methode ist erforderlich, um die in BigInteger gespeicherten Zahlen darzustellen. Da das Bytearray mit der minimalen Anzahl von Elementen zurückgegeben wird, kann das Bytearray kleiner sein als das ursprüngliche Bytearray.

//Eingabebyte-Array: 00 7f
byte[] input = new Bytes(new byte[] {(byte) 0x00, (byte) 0x7f}).toByteArray();
//Ausgabebyte-Array: 7f
//In BigInteger konvertiert, wird es 1 Byte. (Weil 127 durch 1 Byte als Zahl dargestellt werden kann.)
byte[] output = new BigInteger(input).toByteArray();

Zusätzlich kann jede Operation zu einem Byte-Array führen, dessen Größe größer ist als das ursprüngliche Byte-Array.

//Eingabebyte-Array: 40 00
byte[] input = new Bytes(new byte[] {(byte) 0x40, (byte) 0x00}).toByteArray();
//Ausgabebyte-Array nach 1-Bit-Links-Arithmetikverschiebung: 00 80 00
byte[] output = new BigInteger(input).shiftLeft(2).toByteArray();

Wenn Sie zum Byte-Array zurückkehren, müssen Sie daher anpassen, dass es mit der ursprünglichen Anzahl von Bytes übereinstimmt.

//Zu konvertierende BigInteger-Instanz
BigInteger bi;
//Größe des zu konvertierenden Byte-Arrays
int byteSize;

byte[] ba = bi.toByteArray();
ByteBuffer bb = ByteBuffer.allocate(byteSize);
//Entfernen Sie zusätzliche Bytes höherer Ordnung.
if (ba.length >= byteSize) {
  bb.put(ba, ba.length-byteSize, byteSize);
//Füllen Sie den ByteBuffer von Anfang an für die Anzahl der fehlenden Bytes.
} else {
  int byteSizeToFill = byteSize - ba.length;
  for(int i=0; i<byteSizeToFill; i++) {
    bb.put((byte) 0);
  }
  bb.put(ba);
}

//Byte-Array nach der Konvertierung
byte[] output = bb.array();

Genau genommen, wenn BigInteger eine negative Zahl ist, ist es notwendig, die fehlenden Bytes mit 1 anstelle von 0 zu füllen, aber da der Wert von BigInteger so angepasst wird, dass es immer eine positive Zahl ist, die mit Punkt 1 übereinstimmt, ist dies der Fall einer negativen Zahl Keine Notwendigkeit zu berücksichtigen.

//Eingabebyte-Array: ff ff
byte[] input = new Bytes(new byte[] {(byte) 0xff, (byte) 0xff}).toByteArray();
//Ausgabebyte-Array: ff
//Bei einer negativen Zahl müssen die fehlenden höherwertigen Bits mit 1 gefüllt werden.
byte[] output = new BigInteger(input).toByteArray();

Recommended Posts

Bitarithmetik des Binärwerts mit BigInteger
Geben Sie den Standardwert mit @Builder of Lombok an
Festlegen des Werts von log4jdbc.properties
Überprüfen Sie die Funktion von zwei Rollen mit einer Chat-Anwendung