Arytmetyczny bit-shift na podpisanej liczbie całkowitej

Próbuję dowiedzieć się, jak dokładnie działają arytmetyczne operatory zmiany bitowej w C i jak wpłynie to na podpisane 32-bitowe liczby całkowite.

Aby wszystko było proste, powiedzmy, że pracujemy w jednym bajcie (8 bitów):

x = 1101.0101
MSB[ 1101.0101 ]LSB

Czytając inne posty na Stack Overflow i niektórych stronach internetowych, stwierdziłem, że: << przesunie się w kierunku MSB (w moim przypadku w lewo) i wypełni "puste" bity LSB 0s.

I >> przesuną się w kierunku LSB (w moim przypadku w prawo) i wypełnią" puste " bity MS bit

Tak więc, x = x << 7 spowoduje przeniesienie LSB do MSB i ustawienie wszystkiego na 0s.

1000.0000

Teraz, powiedzmy, że będę >> 7, ostatni wynik. Wynikałoby to z [0000.0010]? Mam rację?

Czy mam rację co do moich założeń dotyczących operatorów zmian?

Właśnie testowałem na mojej maszynie, * *

int x = 1;   //000000000......01

x = x << 31; //100000000......00

x = x >> 31; //111111111......11 (Everything is filled with 1s !!!!!) 
Dlaczego?
Author: Peter Mortensen, 2010-10-24

4 answers

Przesunięcie w prawo ujemnej liczby podpisanej ma zdefiniowane zachowanie.

Jeśli twoje 8 bitów ma reprezentować podpisaną wartość 8-bitową (jak mówisz o "podpisanej 32-bitowej liczbie całkowitej" przed przełączeniem na 8-bitowe przykłady), masz liczbę ujemną. Przesunięcie go w prawo może wypełnić "puste" bity oryginalnym MSB (tj. wykonać rozszerzenie sign) lub może przesunąć się w Zerach, w zależności od platformy i / lub kompilatora.

(zachowanie zdefiniowane w implementacji oznacza, że kompilator zrobi coś sensownego, ale w sposób zależny od platformy; dokumentacja kompilatora ma ci powiedzieć co.)


Przesunięcie w lewo, jeśli liczba zaczyna się od wartości ujemnej lub operacja przesunięcia przesunie 1 do bitu znaku lub poza niego, Ma nieokreślone zachowanie (podobnie jak większość operacji na podpisanych wartościach, które powodują przepełnienie).

(nieokreślone zachowanie oznacza, że wszystko może się zdarzyć.)


Te same operacje na unsigned wartości są dobrze zdefiniowane w obu przypadkach: "puste" bity będą wypełnione 0.

 52
Author: Matthew Slattery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-24 19:53:40

Operacje przesunięcia bitowego nie są zdefiniowane dla wartości ujemnych

Dla "

6.5.7/4 [...] Jeśli E1 ma typ podpisany i wartość nonnegatywną, a E1×2 E2 jest reprezentowalny w typie wynikowym, to jest to wartość wynikowa; w przeciwnym razie zachowanie jest niezdefiniowane.

I dla ">> "

6.5.7/5 [...] Jeśli E1 ma typ podpisany i wartość ujemną, wartość wynikowa jest zdefiniowana w implementacji.

To strata czasu na zbadanie zachowania tych operacji na podpisanych numerach na konkretnej implementacji, ponieważ nie masz gwarancji, że będzie działać tak samo na każdej innej implementacji(implementacją jest np. kompilator na twoim komputerze z konkretnymi parametrami linii commad).

Może nawet nie działać dla starszej lub nowszej wersji tego samego kompilatora. Kompilator może nawet zdefiniować te bity jako losowe lub niezdefiniowane. Oznaczałoby to, że ten sam kod sekwencja może przynieść zupełnie inne wyniki, gdy jest używana w różnych źródłach, a nawet zależy od takich rzeczy, jak optymalizacja montażu lub inne użycie rejestru. Jeśli funkcja jest zamknięta, to może nawet nie dać tego samego wyniku w tych bitach podczas dwóch kolejnych wywołań z tymi samymi argumentami.

Biorąc pod uwagę tylko wartości nieujemne , efekt przesunięcia w lewo o 1 (expression << 1) jest taki sam jak multpliying wyrażenia o 2 (pod warunkiem, że wyrażenie * 2 nie przepełnia się) i efekt przesunięcia w prawo o 1 (expression >> 1) jest taki sam jak dzielenie przez 2.

 34
Author: pmg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-11 12:43:51

Jak mówili inni przesunięcie wartości ujemnej jest definiowane implementacyjnie.

Większość implementacji traktuje signed right shift jako floor(x/2 N ), wypełniając przesunięte w bitach za pomocą bitów znaku. Jest to bardzo wygodne w praktyce, ponieważ ta operacja jest tak powszechna. Z drugiej strony, jeśli przesuniesz w prawo unsigned integer, przesunięte w bitach zostaną zerowane.

Patrząc od strony Maszyny, większość implementacji ma dwa rodzaje instrukcji shift-right:

  1. Na 'arytmetyczne' przesunięcie w prawo (często z mnemonicznym ASR lub SRA), które działa jak wyjaśniłem.

  2. "logiczne" przesunięcie w prawo (oftemoniczne LSR lub SRL lub SR), które działa zgodnie z oczekiwaniami.

Większość kompilatorów używa pierwszego dla typów podpisanych, a drugiego dla niepodpisanych. Dla wygody.

 5
Author: Vovanium,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-24 22:32:54

W 32-bitowym kompilatorze

X = x > > 31;

Tutaj x jest liczbą całkowitą ze znakiem, więc 32-gi bit jest bitem znaku.

Ostateczna wartość x to 100000...000. i 32. bit wskazuje-ive wartość.

Tutaj wartość x implementuje komplement 1.

Wtedy ostateczne x to -32768

 0
Author: user3060837,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-05 11:24:40