2013-03-22 15 views
6

próbuję napisać kalkulator bitowe w Javie, coś, co dało wejście określenia takie jak: ~ 101 i byłoby oddać 10 jednak gdy ten kodbitowe negacja daje nieoczekiwany rezultat

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)); 
    } 
} 

go Wyjścia -110 dlaczego?

+6

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

+0

Aby uzyskać szczegółowe informacje zobacz: http://stackoverflow.com/q/12337360/44522 – MicSim

Odpowiedz

8

Zakładasz, że 101 ma trzy bity. Java nie obsługuje operacji bitowych o zmiennej długości, działa na całym bitach, więc ~ będzie not 32-bitowego "101".

--- Edytowany po zapytaniu "Jak mogę to naprawić?" ---

To naprawdę dobre pytanie, ale odpowiedź brzmi: "nie możesz" i "możesz osiągnąć to samo na różne sposoby".

Nie można naprawić operatora ~, tak jak robi to, co robi. Byłoby to jak prośba o naprawienie +, aby dodać tylko miejsce 1. Po prostu nie nastąpi.

Możesz osiągnąć pożądaną operację, ale potrzebujesz trochę więcej "rzeczy", aby to osiągnąć. Najpierw musisz mieć coś (inny int), który określa interesujące bity . Nazywa się to zwykle maską bitową .

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

int masked_inverse = (~value) & mask; 

Zauważ, że to co zrobiliśmy, odwróciło 32 bity, a następnie wyzerowało 29 z tych bitów; ponieważ zostały one ustawione na zero w masce, co oznacza "nie dbamy o nie". Można to sobie również wyobrazić jako działanie operatora & tak, że mówimy "jeśli jest ustawione i zależy nam na tym, ustaw go".

Teraz będzie nadal ma 32 bity, ale tylko niższe 3 zostaną odwrócone. Jeśli potrzebujesz 3-bitowej struktury danych, to inna historia. Java (i większość języków) po prostu nie obsługuje takich rzeczy bezpośrednio. Można więc pokusić się o dodanie innego typu do Javy w celu obsługi tego. Java dodaje typy za pomocą mechanizmu klasy, ale typy wbudowane nie są zmienne. Oznacza to, że możesz napisać klasę reprezentującą 3-bitową strukturę danych, ale będzie ona musiała obsługiwać wewnętrznie jako pola 32-bitowe.

Na szczęście dla ciebie ktoś już to zrobił. Jest częścią standardowej biblioteki Java i 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); 

Jednakże takie manipulacje bitowe mają różny dotyk do nich ze względu na ograniczenia systemu klasy/obiekt w Javie, co wynika z definiowania klas jak jedynym sposobem aby dodać nowe typy w Javie.

+0

tak jak by to naprawić –

+0

@JoshSobel I zaktualizowaną odpowiedź. Niektóre naprawdę krótkie pytania wymagają długich wyjaśnień, ponieważ są one na tyle szczęśliwe, że otwierają drzwi do nowego zrozumienia. Powodzenia w twoim staraniu. –

+0

ale jak chciałbym dynamicznie dostosować maskę, aby pasował do danej liczby –

0

Metoda toString() interpretuje argument jako wartość podpisaną.

Aby wykazać operacje binarne, lepiej jest użyć Integer.toBinaryString(). Interpretuje swój argument jako niepodpisane, więc ~ 101 jest wyprowadzany jako 11111111111111111111111111111010.

Jeśli chcesz mniej bitów wyjścia można zamaskować wynik z &.

0

101 w liczbie całkowitej jest faktycznie reprezentowana jako 00000000000000000000000000000101 neguje to i otrzymujesz 11111111111111111111111111111010 - jest to -6.

+0

Myślę, że OP zastanawia się, dlaczego jeśli binarna reprezentacja ~ a jest '... 111111010', 'toString (~ a, 2)' wyświetla '-110'? – Pshemo

1

Jeśli a = ...0000101 (bin) = 5 (dec)

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

i Java używa "Two's complement" forma do reprezentacji liczb ujemnych tak

~a = -6 (dec) 

Teraz różnica między Integer.toBinaryString(number) i Integer.toString(number, 2) dla liczby ujemnej jest

  • toBinaryString Zwraca String w „Two's complement” postaci, ale
  • toString(number, 2) oblicza postać binarną jakby numer był dodatni i dodać znak „minus”, jeśli argumentem był ujemny.

Więc toString(number, 2) dla ~a = -6 będzie

  1. obliczyć wartość binarną dla 6 ->0000110,
  2. wykończenia zer ->110,
  3. minus Mark Dodaj ->-110.
0

Wystarczy rozwinąć odpowiedź Edwina trochę - jeśli szukasz, aby utworzyć zmiennej długości maski rozwijania bity zainteresowania, warto niektóre funkcje pomocnicze:

/** 
* 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); 
} 
Powiązane problemy