Posuny: a ten vpravo, který má dvě odpovědi
Posun vlevo je jednoznačný. Bity se posunou, zprava nalezou nuly, a co vyleze nahoře, to je pryč. Odpovídá to násobení dvěma:
A teď doprava
Zprava se bity ztrácejí a shora něco nalézt musí. Jenže co? Existují dvě odpovědi a obě jsou správně — pro jinou otázku:
| posun | shora leze | je to správně pro |
|---|---|---|
logický (>>>) | nula | vzorek bitů — masku, příznaky, surová data |
aritmetický (>>) | kopie znaménkového bitu | číslo se znaménkem |
U kladných čísel dávají obě totéž, takže se ten rozdíl nikdy neprojeví — dokud se neobjeví
první záporná hodnota. Pak logický posun z −1 udělá 255.
Který z nich dostanete, není vaše volba — je to typ.
V C rozhoduje, jestli je proměnná signed, nebo unsigned; ten samý zápis
x >> 1 udělá dvě různé věci. V Javě a v JavaScriptu jsou to dva různé operátory,
>> a >>>, což je poctivější.
Druhá polovina té pasti: zaokrouhlování
„Posun vpravo je dělení dvěma“ platí pro kladná čísla. Pro záporná ne úplně:
Aritmetický posun zaokrouhluje dolů, k mínus nekonečnu. Celočíselné dělení
v C zaokrouhluje k nule. Kdo v optimalizaci nahradí / 2 za
>> 1, změní chování u záporných vstupů — a překladač to sám neudělá právě proto,
že by tím změnil výsledek.
Rotace
Rotace je posun, který nic neztrácí: co vyleze nahoře, naleze zdola. Je to permutace bitů — počet jedniček se nemění a po w rotacích je slovo tam, kde bylo. Používá se v kryptografii a v kontrolních součtech; běžné jazyky pro ni operátor nemají a překladač ji poskládá z dvou posunů a OR.
Posun o víc než je šířka typu je v C nedefinovaný, ne
„vyjde nula“. Na x86 procesor bere jen spodních 5 bitů počtu, takže x << 32 je
x << 0 — tedy x. Na ARM vyjde nula. Obojí je „správně“, protože
norma neříká nic.