2013-03-22 16 views
6

Ich versuche, eine bitweise Rechner in Java zu schreiben, etwas, was man konnte Eingabe einen Ausdruck wie ~ 101 und zurück 10 jedoch geben würde, wenn ich diesen Code ausführenbitweise Negation gibt unerwartetes Ergebnis

import java.util.Scanner; 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     Integer a = Integer.valueOf("101", 2); 
     System.out.println(Integer.toString(~a,2)); 
    } 
} 

es Ausgaben -110 warum?

+6

http: // en.wikipedia.org/wiki/Two's_complement –

+0

Für Details siehe: http://Stackoverflow.com/q/12337360/44522 – MicSim

Antwort

8

Sie gehen davon aus, dass 101 drei Bits lang ist. Java unterstützt Bitoperationen mit variabler Länge nicht, es arbeitet an einem ganzen int von Bits, so dass ~ der not eines 32 Bit langen "101" sein wird.

--- Editiert nach der Frage "Wie kann ich das beheben?" ---

Das ist eine wirklich gute Frage, aber die Antwort ist eine Mischung aus "Sie können nicht" und "Sie können dasselbe mit anderen Mitteln erreichen".

Sie können den Operator ~ nicht reparieren, da es tut, was es tut. Es wäre so, als würde man bitten, + zu korrigieren, um nur den Platz der 1 hinzuzufügen. Es wird einfach nicht passieren.

Sie können die gewünschte Operation erreichen, aber Sie brauchen ein bisschen mehr "Zeug", um es in Gang zu bringen. Zuerst müssen Sie haben etwas (ein anderes int), das die Bits von Interesse angibt. Dies wird typischerweise als Bitmaske bezeichnet.

int mask = 0x00000007; // just the last 3 bits. 

int masked_inverse = (~value) & mask; 

Beachten Sie, dass, was wir wirklich 32 Bit tat, war invertieren, dann 29 dieser Bits auf Null gesetzt; weil sie in der Maske auf Null gesetzt wurden, was bedeutet, dass wir uns nicht um sie kümmern. Man kann sich das auch so vorstellen, dass man den Operator & so einsetzt, dass wir sagen "wenn gesetzt und wir kümmern uns darum, setzen Sie es".

Jetzt werden Sie noch haben 32 Bits, aber nur die unteren 3 werden invertiert werden. Wenn Sie eine 3-Bit-Datenstruktur möchten, dann ist das eine andere Geschichte. Java (und die meisten Sprachen) unterstützen solche Dinge nicht direkt. Sie könnten versucht sein, einen weiteren Typ zu Java hinzuzufügen, um dies zu unterstützen. Java fügt Typen über einen Klasse--Mechanismus hinzu, aber die integrierten Typen sind nicht änderbar. Das bedeutet, dass Sie eine Klasse schreiben könnten, die eine 3-Bit-Datenstruktur darstellt, aber intern als 32-Bit-Felder behandelt werden muss.

Zum Glück für Sie, jemand hat dies bereits getan. Es ist Teil der Standard-Java-Bibliothek und is called a BitSet.

BitSet threeBits = new BitSet(3); 
threeBits.set(2); // set bit index 2 
threeBits.set(0); // set bit index 0 
threeBits.flip(0,3); 

Allerdings ist eine solche Bit-Manipulationen haben ein anderes Gefühl zu ihnen aufgrund der Beschränkungen des Klassen-/Objektsystem in Java, die von der Definition der Klassen als folgt einzige Weg neue Typen in Java hinzuzufügen.

+0

also wie würde ich das beheben –

+0

@JoshSobel Ich aktualisierte die Antwort. Einige wirklich kurze Fragen erfordern lange Erklärungen, da sie nur das Glück haben, Türen für neues Verständnis zu öffnen. Viel Glück bei Ihrem Vorhaben. –

+0

aber wie würde ich die Maske dynamisch anpassen, um die gegebene Zahl zu passen –

0

Die Methode toString() interpretiert ihr Argument als vorzeichenbehafteten Wert.

Um binäre Operationen zu demonstrieren, ist es besser, Integer.toBinaryString() zu verwenden. Er interpretiert sein Argument als vorzeichenlos, so dass ~ 101 als 1111111111111111111111111111111010 ausgegeben wird.

Wenn Sie weniger Bits der Ausgabe möchten, können Sie das Ergebnis mit & maskieren.

0

101 in Integer wird eigentlich als 00000000000000000000000000000101 negiert dies und Sie erhalten 11111111111111111111111111111010 - das ist -6.

+0

Ich denke, OP fragt sich, warum, wenn binäre Darstellung von ~ a ist "... 111111010", 'toString (~ a, 2)' druckt '-110'? – Pshemo

1

Wenn a = ...0000101 (bin) = 5 (dec)

~a = ~...0000101(bin) = ...1111010(bin) 

und Java verwendet "Two's complement" Form negative Zahlen darstellen, so

~a = -6 (dec) 

Jetzt Unterschied zwischen Integer.toBinaryString(number) und Integer.toString(number, 2) für negative Zahl ist, dass

  • toBinaryString returns String in "Two's complement" Formular, aber
  • toString(number, 2) berechnet binäre Form als ob die Zahl positiv war und füge "Minus" hinzu, wenn das Argument negativ war. >0000110,
  • trim führende Nullen - -

So toString(number, 2) für ~a = -6 für 6

  1. binären Wert berechnen>110,
  2. add minus Zeichen ->-110.
0

einfach zu erarbeiten auf Edwin Antwort ein wenig - wenn Sie eine variable Länge Maske erzeugen nun das Bit von Interesse zu entwickeln, könnten Sie einige Hilfsfunktionen wollen:

/** 
* Negate a number, specifying the bits of interest. 
* 
* Negating 52 with an interest of 6 would result in 11 (from 110100 to 001011). 
* Negating 0 with an interest of 32 would result in -1 (equivalent to ~0). 
* 
* @param number the number to negate. 
* @param bitsOfInterest the bits we're interested in limiting ourself to (32 maximum). 
* @return the negated number. 
*/ 
public int negate(int number, int bitsOfInterest) { 
    int negated = ~number; 
    int mask = ~0 >>> (32 - bitsOfInterest); 
    logger.info("Mask for negation is [" + Integer.toBinaryString(mask) + "]"); 
    return negated & mask; 
} 

/** 
* Negate a number, assuming we're interesting in negation of all 31 bits (exluding the sign). 
* 
* Negating 32 in this case would result in ({@link Integer#MAX_VALUE} - 32). 
* 
* @param number the number to negate. 
* @return the negated number. 
*/ 
public int negate(int number) { 
    return negate(number, 31); 
} 
Verwandte Themen