TCH (statz) | #1, Főfasz (10443) |
2346 | #3a00 | ^ | Idézet | Mon, 04 Jan 2016 22:34:00 +01 |
188.36.*.* | *.catv.pool.telekom.hu |
Kétféle shift van. Az egyik a logikai, a másik az aritmetikai. A logikai azt csinálja, amit várna az ember, egy bittel erre vagy arra lépteti a számot. Az aritmetikai ugyanezt teszi, de előjelhelyesen. Felfele (ill. balra) ez nem jelent különbséget, viszont jobbra igen. Ha aritmetikai jobbraléptetést végzünk, akkor a tetején nem 0 fog bejönni, hanem az előjelbit. Két példa (8 biten): 10010011 >> 3 = 11110010 00101101 >> 2 = 00001011Amint lehetett látni, a tetejébe az előjel lépett be annyiszor, amennyivel elforgattuk. Ilyen művelet azonban maximum assemblyben van, a nyelvek nem támogatják, csak a logikait. "Emulálni" a következőképp lehet: s8 asr(s8 num, u8 step) { return (num >> 7 == 0 ? 0 : ~(-1 >> step)) | num >> step; }Azaz, ha az előjelbit 0, akkor nincs dolgunk, viszont, ha 1, akkor szükségünk van egy olyan maszkra, aminek a tetején pont annyi egyes van, amennyivel tolódni fog a szám. Ezt úgy lehet előállítani, ha egy csak 1-eseket tartalmazó számot (-1) a szükséges mértékben eltolunk, majd negálunk. Szemléltetem (8 biten): ; ha step = 3
11111111 >> 3 = 00011111
~00011111 = 11100000 Viszont a maszk összeállításához egy elágazást felhasználni talán nem a legoptimálisabb. Ki lehet váltani úgy, ha az előjelbitet nem feltételnek használjuk, hanem kivonunk belőle 1-et, amit utána negálunk és elforgatunk a bitszélesség és az eltolás mértékének különbségével.~((num >> 7) - 1) << (8 - step)Ez így elsőre biztos WTF, de máris mutatom (8 biten): ; ha num negatív (1xxxxxxx) és step = 3 1xxxxxxx >> 7 = 00000001 00000001 - 00000001 = 00000000 ~00000000 = 11111111 11111111 << (8 - 3) = 11100000 ; ha num pozitív 0xxxxxxx és step = 3 0xxxxxxx >> 7 = 00000000 00000000 - 00000001 = 11111111 ~11111111 = 00000000 00000000 << (8 - 3) = 00000000Tehát a fenti kód így módosul: s8 asr(s8 num, u8 step) { return ~((num >> 7) - 1) << (8 - step) | num >> step; }Viszont nem fontos éppenséggel függvénybe sem rakni, lehet makró is, csak akkor le kell kezelni a bitszélességet: #define asr(num, step) (~(((num) >> ((sizeof(num) << 3) - 1)) - 1) << ((sizeof(num) << 3) - (step)) | (num) >> (step)) |