###### tags: `ASK` # Lista 2 ## Zadanie 1 ```c (x > 0) || (x - 1 < 0) ``` wyrażenie zwróci *fałsz* dla x = $INT32\_MIN$ (wartość możemy sprawdzić po dołączeniu biblioteki `stdint.h`), które jest równe $100...00_{(2)} = -2147483648$ $x > 0 \to false$ $x - 1 = 100...00_{(2)} - 1 = 011...11_{(2)} = 2147483647 = INT32\_MAX$ występuje *overflow*, więc $x - 1 < 0 \to false$ ```c (x & 7) != 7 || (x << 29 < 0) ``` wyrażenie zawsze zwróci *prawdę* $(x \& 7) \ != 7 \to$ będzie fałszem, gdy wszystkie trzy skrajnie prawe bity $x$ będą równe $1$ weźmy $x =\ ...111{(2)}$ wtedy po przesunięciu $x << 29$ otrzymamy $111....00_{(2)}$ widzimy, że jest to liczba ujemna, czyli $(x << 29 < 0) \to true$ ```c (x * x) >= 0 ``` wyrażenie zwróci *fałsz* gdy w wyniku $x^2$ na 31 pozycji w reprezentacji binarnej będzie zapalony bit, znaleźć taką liczbę możemy w następujący sposób (uwzględniając dziedziny): \begin{cases} x^2 = (2^t + 2^r)^2 = 2^{2t} + 2^{t+r + 1} + 2^{2r}\\ t + r + 1 = 31 \end{cases} weźmy np. $x = 2^{10} + 2^{20} = 1049600 = 00000000000100000000010000000000_{(2)}$ $x^2 = (2^{10} + 2^{20})^2 = 2^{20} + 2^{31} + 2^{40}$ po utracie bitów wyniku zapalone będą bity $31$ i $20 \to$ liczba ujemna ```c x < 0 || -x <= 0 ``` wyrażenie zawsze zwróci *prawdę* ponieważ liczb ujemnych jest o jeden więcej ```c x > 0 || -x >= 0 ``` wyrażenie zwróci *fałsz* dla $x = INT32\_MIN$ `-x = ~x + 1` $-x = -INT32\_MIN = -(-2147483648) = 2147483648 =\\ = INT32\_MAX + 1 = 011...111 + 1 = 10...000 = INT32\_MIN$ ```c (x | -x) >> 31 == -1 ``` wyrażenie zwróci *fałsz* dla $x = 0$ $(x \ | -x)$ zwróci $0$, a $(0 >> 31)$ to też $0$ ```c x + y == (uint32_t)y + (uint32_t)x ``` wyrażenie zawsze zwróci *prawdę* ponieważ `unsigned` jest zarażający to nastąpi niejawne rzutowanie, czyli tak naprawdę nasze wyrażenie będzie wyglądać tak: `(uint32_t)(x + y) == (uint32_t)y + (uint32_t)x` ```c x * ~y + (uint32_t)y * (uint32_t)x == -x ``` wyrażenie zawsze zwróci *prawdę* `(uint32_t)x * (uint32_t)(~y) + (uint32_t)y * (uint32_t)x == (uint32_t)(-x)` Lewa strona: `(uint32_t)x * ((uint32_t)(~y) + (uint32_t)y)` korzystając z : `-y = ~y + 1` $\to$ `-1 = ~y + y` mamy: `(uint32_t)x * (-1)` `(uint32_t)x * UINT32_MAX` $\to$ zwraca `(uint32_t)(-x)` Prawa strona: `(uint32_t)(-x)` `(uint32_t)(~x + 1)` ## Zadanie 2 Sposób z dodawaniem: ```c= void swap(int *x, int *y) { *x += *y; *y = *x - *y; *x -= *y; } ``` Sposób z xorem: ```c= void swap(int *x, int *y) { *x ^= *y; *y ^= *x; *x ^= *y; } ``` ## Zadanie 3 **Nadmiar (overflow)** - przekroczenie zakresu wartości, które może przyjąć zmienna (liczba zajmuje więcej bitów pamięci, niż zostało jej przydzielone) **Niedomiar (underflow)** - dla liczb typu *integer* oznacza, że wartość wyniku jest bliższa minus nieskończoności niż minimalna wartość jaki może przyjąć dana zmienna zakładam, że $x, y, s$ są typu `int32_t` - jeżeli $x$ i $y$ mają rózne znaki to nie może wystąpić *overflow* - jeżeli $x,y > 0$ to w wyniku 31 bit będzie zapalony - jeżeli $x,y < 0$ to w wyniku 31 bit będzie zgaszony ```c= (((s ^ y) & (s ^ x)) >> 31) & 1; ``` ## Zadanie 4 ```c= uint32_t sum = (x & 0x7F7F7F7F) + (y & 0x7F7F7F7F); sum ^= ((x ^ y) & 0x80808080); uint32_t diff = (x | 0x80808080) - (y & 0x7F7F7F7F); diff ^= ((0x80808080 ^ x) ^ y) & 0x80808080; ``` Przykład dodawania: x = 1001 y = 1111 sum = (x & 0111) + (y & 0111) = 0001 + 0111 = 1000 sum ^= (x ^ y) & 1000 Przykład odejmowania: x = 1001 y = 1111 diff = 1001 - 0111 = 0010 ## Zadanie 5 $x * 3/4 = x * (1/2 + 1/4) = x * 1/2 + x * 1/4 = x / 2 + x/2^2$ ```c= int32_t threefourths(int32_t x){ x = ((x >> 1) + (x >> 2)) + (1 & x & (x >> 1)); } ``` druga część sumy sprawdza czy dwa bity po prawej są oba zapalone $\to$ utrata bitu wyniku i trzeba dodać 1 ## Zadanie 6 ```c ((x >> 1) - (y >> 1) - (~x & y & 1) >> N - 1) & 1; ``` Sprawdzamy znak `x/2 - y/2`. Jeśli najmniej znaczące bity `x` i `y` to odpowiednio `0` i `1`, odejmujemy jeszcze `1`. Dla liczb bez znaku, jeśli `x < y`, to `x/2 - y/2` ma również zapalony najbardziej znaczący bit: ``` x/2 - y/2 = (2^N - 1) + 1 + x/2 - y/2 = 2^N - (y/2 - x/2) >= 2^(N-1) ``` ## Zadanie 7 `-x = ~x + 1` ```c= int abs(int x) { int64_t mask = x >> N - 1; return mask & ~x+1 + ~mask & x; } ``` ## Zadanie 8 `-x = ~x + 1` ```c= int sign(int x){ return (x >> N-1) | (~x+1 >> N-1 & 1); } ``` ## Zadanie 9 z xor'em: ```c= int32_t odd_ones(uint32_t x) { x ^= x >> 1; x ^= x >> 2; x ^= x >> 4; x ^= x >> 8; x ^= x >> 16; return x & 1; } ``` wykorzystując zadanie z poprzedniej listy zliczające liczbę zapalonych bitów: ```cpp= int32_t odd_ones(uint32_t x) { x = (x & 0x55555555) + ((x >> 1) & 0x55555555); // 01010101010101010101010101010101 x = (x & 0x33333333) + ((x >> 2) & 0x33333333); // 00110011001100110011001100110011 x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F); // 00001111000011110000111100001111 x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF); // 00000000111111110000000011111111 x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF); // 00000000000000001111111111111111 return x & 1; } ```