2009-01-20 8 views
12

nie może zrozumieć to operatorowi sterujący (C# odniesienia)zrozumieć operatora przesunięcia

class MainClass1 
{ 
static void Main() 
    { 
     int i = 1; 
     long lg = 1; 
     Console.WriteLine("0x{0:x}", i << 1); 
     Console.WriteLine("0x{0:x}", i << 33); 
     Console.WriteLine("0x{0:x}", lg << 33); 
    } 
} 

/* 
Output: 
0x2 
0x2 
0x200000000 
*/ 

class MainClass2 
{ 
    static void Main() 
    { 
     int a = 1000; 
     a <<= 4; 
     Console.WriteLine(a); 
    } 
} 

/* 
Output: 
16000 
*/ 

Odpowiedz

34

<< jest operatorem lewej zmiany; bierze binarną reprezentację wartości i przesuwa wszystkie bity "n" o miejsca po lewej stronie (z wyjątkiem "mod", patrz "1"), wypełniając je zerami.

>> to operator z prawą zmianą; to robi prawie odwrotnie (przesuwając się w prawo), z wyjątkiem wartości podpisanych (tj. tych, które mogą być ujemne), które z powrotem wypełnia 1s dla wartości ujemnych, w przeciwnym razie zera.

1:

Operator przesunięcia jest zasadniczo "mod" szerokość danych. Wartość int wynosi 32 bity, więc przesunięcie w lewo o 33 (w Int32) jest dokładnie takie samo jak przesunięcie 1 w lewo. Nie otrzymasz wszystkich zer. A long ma 64 bity, więc przesunięcie w lewo o 33 daje inną odpowiedź (pierwotne czasy 2^33).

2:

każdym przesunięciem w lewo (w szerokości danych) jest taka sama (liczby całkowite), a X2 - tak < < 4 x2x2x2x2 = x16.

Jest to prosty binarny:

0000000001 = 1 

< < idzie

0000000010 = 2 

< < idzie

0000000100 = 4 

< < jedzie do

0000001000 = 8 
+0

Witam, czy mogę prosić o wyjaśnienie więcej? W pierwszym, dlaczego mam 0x200000000, a w drugim dlaczego mam 16000? Dziękuję bardzo –

+0

To tak, jakby powiedzieć "dlaczego 1 * 50000 różni się od 1000 * 8" - ponieważ robisz bardzo różne rzeczy. Pierwsza to 2^33 ("moc"), druga to 1000 * 16. –

+0

ok Rozumiem różnicę między 2^33 i 1000 * 16 Chcę wiedzieć dlaczego 2^32 –

6

Wystarczy rozwinąć na odpowiedź Marca trochę (Marc, prosimy o uwzględnienie tego w Ciebie i będę usunąć tę odpowiedź) jest to określone w punkcie 7.8 specyfikacji:


The predefiniowane operatory zmian są wymienione poniżej.

Przesunięcie lewej:

  • Int operatora < < (int x int liczba);
  • uint operator < < (uint x, int count);
  • długi operator < < (długi x, liczba int);
  • ulong operator < < (ulong x, int count);

Operator < < przesuwa x w lewo o liczbę bitów obliczoną w sposób opisany poniżej.

Bity wyższego rzędu spoza zakresu typu wyniku x są odrzucane, pozostałe bity są przesuwane w lewo, a pozycje pustego bitu niskiego rzędu są zerowane.

Przesunięcie w prawo:

  • int operator >> (int x, int count);
  • operator uint >> (uint x, int count);
  • długi operator >> (długie x, liczba int);
  • Operator ulong >> (ulong x, int count);

Operator >> przesuwa x w prawo o liczbę bitów obliczoną w sposób opisany poniżej.

Gdy x jest typu int lub long, bity niskiego rzędu z x są odrzucane, pozostałe bity są przesuwane w prawo, a pozycje pustych bitów wysokiego rzędu są ustawione na zero, jeśli x jest nieujemne i ustawione do jednego, jeśli x jest ujemne.

Gdy x jest typu uint lub ulong, bity niskiego rzędu z x są odrzucane, pozostałe bity są przesuwane w prawo, a pozycje pustych bitów o wysokim porządku są ustawione na zero.

dla predefiniowanych operatorów, liczba bitów do przesuwnego jest obliczana w następujący sposób:

Gdy typ x int lub uint liczba przesunięcia jest przez niskiego rzędu pięciu bitów liczby. Innymi słowy, liczba zmian jest obliczana z liczby & 0x1F.

Gdy typ x jest długi lub ulong, liczba przesunięć jest podana przez małe liczby bitów o mniejszej wartości. Innymi słowy, liczba zmian jest obliczana z liczby & 0x3F.

Jeśli wynikowa liczba zmian wynosi zero, operatory przesunięcia po prostu zwracają wartość x.


+0

Ja aprobuję twoją pomoc. –

2

Jeszcze kilka uwag dla początkującego programisty:

Dlaczego operatorzy używali Shift? Wydaje się, że niewiele z nich robią. Cóż, są 2 powody:

  1. Są one bardzo szybko, ponieważ prawie wszystkie procesory mają rejestrów przesuwnych, czyli operację zmiany biegów odbywa się w sprzęcie, w minimalnym nakładzie pracy (cykle).

  2. Ponieważ są szybkie, wiele protokołów i standardów zostało zaprojektowanych, aby z tego skorzystać. Na przykład operacje na adresie IP, sprawdzanie CRC, operacje graficzne itp.

1

"Operator zmiany to w zasadzie" mod "szerokość danych."

Śmieci! Jeśli wielkość przesunięcia jest większa lub równa szerokości danych, wynik jest niezdefiniowany. Nie oczekuj tej samej operacji "mod", którą zdarzyło Ci się zaobserwować, występującej z różnymi kompilatorami lub różnymi wersjami tego samego kompilatora lub w różnych sytuacjach zmian w tym samym programie lub gdy coś innego się zmieni. To oznacza "niezdefiniowane".

+0

Rzeczywista specyfikacja języka C# 4.0 mówi: 1) Gdy typ x jest int lub uint, liczba przesunięć jest podana przez niskie liczby pięciu bitów liczby. Innymi słowy, licznik zmian jest obliczany na podstawie liczby & 0x1F. 2) Kiedy typ x jest długi lub ulong, liczba przesunięć jest podana przez sześć bitów liczby mniejszej. Innymi słowy, licznik zmian jest obliczany na podstawie liczby & 0x3F. – Ivan