---
# System prepended metadata

title: 'Lista 1 (4. marca 2021), grupa pwit'
tags: [pwit, ask21, ćwiczenia]

---

# Lista 1 (4. marca 2021), grupa pwit

###### tags: `ask21` `ćwiczenia` `pwit`

## Deklaracje

Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie (co najwyżej jedno!) w trakcie dyskusji oznacz je znakiem ==X== na żółtym tle.

**UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!**

Tabelka zawiera tylko osoby zapisane do grupy. Osoby oczekujące proszone są o wpisanie się do osobnej tabelki poniżej.


:::danger
|                      | 1   | 2   | 3   | 4   |  5  |  6  | 7   |  8  |
| --------------------:| --- | --- | --- | --- |:---:|:---:| --- |:---:|
|Wojciech Adamiec      |  X  |==X==|  X  |     |  X  |  X  |  X  |     |
|Kacper Bajkiewicz     |==X==|  X  |  X  |  X  |  X  |  X  |  X  |  X  |
|Bartłomiej Hildebrandt|==X==|  X  |  X  |  X  |  X  |  X  |  X  |     |
|Dominik Komła         |  X  |  X  |  X  |  X  |  X  |  X  |  X  |  X  |
|Aleksandra Kosińska   |  X  |  X  |  X  |  X  |  X  |  X  |  X  |  X  |
|Oleś Kulcewicz        |     |     |     |     |     |     |     |     |
|Damian Lukas          |  X  |  X  |  X  |     |  X  |  X  |     |     |
|Michał Mikołajczyk    |  X  |  X  |  X  |     |==X==|  X  |  X  |     |
|Mateusz Opala         |  X   |  X   |  X   |  X   |  X   |  X   |  X   |  X   |
|Łukasz Orawiec        |  X  |  X  |  X  |  X  |  X  |     |  X  |  X  |
|Szymon Pielat         |  X  |  X  |==X==|     |  X  |  X  |  X  |     |
|Łukasz Pluta          |   X  |   X  |   X  |  X   |  X   |   X  |   X  |  X   |
|Kamil Puchacz         |  X  |  X  |  X  |  X  |  X  |  X  |  X  |  ==X==  |
|Magdalena Rzepka      |  X  |  X  |==X==|  X  |  X  |  X  |  X  |  X  |
|Cezary Stajszczyk     |  X  |  X  |  X  |  X  |  X  |  X  |  X  |  X  |
|Jakub Szajner         |  X  |  X  |  X  |  X  |  X  |  X  |  X  |  X  |
|Bartosz Troszka       |  ==X==  |  X   |  X   |  X   |  X   |  X   |  X   | X     |
|Miłosz Urbanik        |  X  |  X  |  X  |  X  |  X  |  X  |  X  |  X  |
|Oleś Kulczewicz       |  X  |  X  |  X  |  X  |  X  |  X  |  X  |     |




Tabelka dla osób oczekujących na zapis.

|                      | 1   | 2   | 3   | 4   |  5  |  6  | 7   |  8  |
| --------------------:| --- | --- | --- | --- |:---:|:---:| --- |:---:|
|    Łukasz Stasiak              |   X  |     | X    |  X   |  X   |  X   |     |    ==X== |

:::



## Zadanie 1
:::info
Autor: Kacper Bajkiewicz
:::

```c=
uint32_t copy_bit( uint32_t x, uint32_t i, uint32_t k ){
    uint32_t i_bit = (x >> i) & 1;
    x = x & ~( 1 << k ); //zerujemy k-ty bit
    return x | ( i_bit << k );
}
```

Celem drugiej linijki jest dostać się do bitu znajdującego się na i-tej pozycji w liczbie x.
Później chcemy wyzerować k-ty bit w x.
1 << k to jedynka na k-tym miejscu z samymi zerami na pozostałych, więc jej negacja ma zero na k-tym miejscu i jedynki na wszystkich miejscach od zerowego do k-1szego.
Kiedy więc zrobimy x & ~(1 << k), to w zmiennej x zgasimy k-ty bit (bo and-ujemy z 0), pozostałe bity pozostaną niezmienione(ANDowanie z 1).
Wyrażenie i_bit << k to liczba składająca się z i-tego bitu w liczbie x na k-tej pozycji (na innych pozycjach będą same zera).
x | (i_bit << k) da więc liczbę x z przekopiowanym i-tym bitem na k-tą pozycję (bo na k-tym miejscu wykonamy ORa na zerze z i-tym bicie w x, co da i-ty bit w x a na pozostałych miejscach na ORze z zerem, co nie zmieni tych bitów).

copy_bit( 22, 4, 0 ) zwróci liczbę 23. 10110 -> 10111
copy_bit( 22, 0, 4 ) zwróci liczbę 6.  10110 -> 00110
copy_bit( 22, 3, 3 ) zwróci liczbę 22. 10110 -> 10110
## Zadanie 2
:::info
Autor: Wojciech Adamiec
:::

:::info
Napisz fragment kodu, który wyznaczy liczbę zapalonych bitów w zmiennej x.

UWAGA! Oczekiwana złożoność to O(logn), gdzie n to liczba bitów w słowie. Posłuż się strategią „dziel i zwyciężaj”.
:::

https://en.wikipedia.org/wiki/Hamming_weight

```c=
int aux(uint32_t x){
    uint32_t m1  = 0x55555555; // 01010101010101010101010101010101
    uint32_t m2  = 0x33333333; // 00110011001100110011001100110011
    uint32_t m4  = 0x0f0f0f0f; // 00001111000011110000111100001111
    uint32_t m8  = 0x00ff00ff; // 00000000111111110000000011111111
    uint32_t m16 = 0x0000ffff; // 00000000000000001111111111111111
    
    x = (x & m1 ) + ((x >>  1)  & m1 ); //put count of each 2 bits into those 2 bits  
    x = (x & m2 ) + ((x >>  2)  & m2 ); //put count of each 4 bits into those 4 bits 
    x = (x & m4 ) + ((x >>  4)  & m4 ); //put count of each 8 bits into those 8 bits 
    x = (x & m8 ) + ((x >>  8)  & m8 ); //put count of each 16 bits into those 16 bits 
    x = (x & m16) + ((x >> 16)  & m16); //put count of each 32 bits into those 32 bits
    return x;
}
```
Co się dzieje w pojedynczym kroku:

![alt text](https://i.imgur.com/7m8ViLH.png "")

Jak wygląda całość algorytmu:

![alt text](https://i.imgur.com/TvBsipy.png "")

## Zadanie 3
:::info
Autor: Szymon Pielat
:::
![](https://i.imgur.com/6Axbnt6.png)

> [name=Piotr Witkowski] Na razie przyjmujemy "niestandardową" konwencję, że mamy Unix x86-64 ale ze wskaźnikami o rozmiarze 32-bitów. 

Struktura A:
```c=
struct A {
    int8_t a;  -- 1 bajt
               -- 3 bajty
    void *b;   -- 4 bajty
    int8_t c;  -- 1 bajt
               -- 1 bajt
    int16_t d; -- 2 bajty
};

Suma = 12 bajty
```
Optymalizacja:
```c=
struct A {
    void *b;   -- 4 bajty
    int16_t d; -- 2 bajty
    int8_t a;  -- 1 bajt
    int8_t c;  -- 1 bajt
};
Suma = 8 bajtów
```
Struktura B:
```c=
struct B {
    uint16_t a; -- 2 bajty
                -- 6 bajty
    double b;   -- 8 bajtów
    void *c;    -- 4 bajty
                -- 4 bajty
};
Suma = 24 bajty


```
Optymalizacja:
```c=
struct B {
    double b;   -- 8 bajtów
    void *c;    -- 4 bajty
    uint16_t a; -- 2 bajty
                -- 2 bajty
};
Suma = 16 bajtów
```
> []Standardowe konwencje: 
> 
a) Unix x86 

> W domu proszę skompilować przykładowy program z tymi strulturami tak:
> gcc -m32 nazwa.c -o program_wynikowy
> (być może trzeba doinstalować pakiet multilib) 
> zobacz: x86 struct alignment w google. 
  
b) Unix x86-64:
```c=
struct B {
    uint16_t a; -- 2 bajty
                -- 6 bajty
    double b;   -- 8 bajtów
    void *c;    -- 8 bajtów
}
Optymalizacja:

struct B {
    double b;   -- 8 bajtów
    void *c;    -- 8 bajtów
    uint16_t a; -- 2 bajty
                -- 6 bajty
};
```
```c=
struct A {
    int8_t a;  -- 1 bajt
               -- 7 bajty
    void *b;   -- 8 bajty
    int8_t c;  -- 1 bajt
               -- 1 bajt
    int16_t d; -- 2 bajty
		 -- 4 bajty
};

Suma = 24 bajty

Optymalizacja:

struct A {
    void *b;   -- 8 bajty
	int16_t d; -- 2 bajty
    int8_t a;  -- 1 bajt
    int8_t c;  -- 1 bajt
		 -- 4 bajty
};
Suma = 16 bajtów
```




## Zadanie 4
:::info
Autor: Łukasz Orawiec
:::

* ```volatile``` oznacza zmienną, która może zmienić wartość niezależnie od kodu, w którym się znajduje. Zmusza kompilator do tego, żeby nie cache'ował zmiennej i żeby przy każdym odwołaniu do niej wczytywał ją z pamięci. 
 
    Należy używać tego słowa kluczowego np. gdy mamy wskaźnik na adres pod którym jest zmapowana pamięć jakiegoś urządzenia z którym się komunikujemy.

* ```static```
    * statyczne zmienne globalne i procedury są widoczne tylko w pliku, w którym zostały zadeklarowane
    * statyczna zmienna lokalna jest inicjalizowana tylko raz i zachowuje swoją wartość między wywołaniami funkcji

```c=
void test()
{
    static int x = 0;
    x++;
    printf("%d ", x);
}


int main()
{
    for(int i = 0; i < 5; i++) test(); // wypisuje 1 2 3 4 5
    return 0;
}
```

* ```restrict``` mówi kompilatorowi, że oznaczony tym słowem kluczowym wskaźnik jest jedynym wskaźnikiem wskazującym na obiekt, na który wskazuje



## Zadanie 5
:::info
Autor: Michał Mikołajczyk
:::
![](https://i.imgur.com/d7kkAzg.png)
```c=
// C
s += b[j+1] + b[--j];

// TAC
t1 := j + 1
t2 := t1 * 4
t3 := b + t2
t4 := *t3       // b[j+1]

j  := j - 1
t5 := j * 4
t6 := b + t5
t7 := *t6       // b[--j]

s := s + t4     // s += b[j+1]
s := s + t7     // s += b[--j]
```

```c=
// C
a[i++] -= *b * (c[j*2] + 1);

// TAC
t1 := i * 4
i  := i + 1     // i++
t2 := a + t1    // Adres a[i++] (a[i])
t3 := *t2       // a[i]

t4 := *b        // *b

t5 := j * 2
t6 := t5 * 4
t7 := c + t6
t8 := *t7       // c[j*2]

t9 := t8 + 1    // c[j*2] + 1

t10 := t4 * t9  // *b * (c[j*2] + 1)

t11 := t3 - t10 // a[i] - (*b * (c[j*2] + 1))
*t2 := t11      // a[i] -= *b * (c[j*2] + 1)
```

## Zadanie 6
:::info
Autor: Jakub Szajner
:::

konwencja dokładnie taka, o jaką prosili w zadaniu 3 (unix x86 (32 bity)):
```c=
struct A {
int8_t a;   // 1 bajt
            // 3 bajty wypełnienia
void *b;    // 4 bajty
int8_t c;   // 1 bajt
            // 1 bajt
int16_t d;  // 2 bajty
};
// sizeof(struct A) == 12





t1 := vs + 10
t2 := us + 12
t3 := j * 12
t4 := us + t3
t5 := t4 + 8
t6 := *t2
t7 := *t5
t8 := t6 + t7
*t1 :=t8

```

## Zadanie 7
:::info
Autor: Miłosz Urbanik	
:::

```c=
void insertion_sort(int arr[], int length) {
    int j, temp;
    for (int i = 0; i < length; i++) {
        j = i;
        while(j > 0 && arr[j] < arr[j - 1]) {
            temp = arr[j];
            arr[j] = arr[j-1];
            arr[j-1] = temp;
            j--;
        }
    }
}
```

Insert sort w kodzie trójkowym

```c=
            i := 0                            //B1     
FBegin:     if (i >= length) goto End         //B2
            j := i                            //B3
            zero := 0
WBegin:     if (j <= zero) goto WEnd         //B4
            t0 := j * 4                      //B5
            t1 := t0 - 4
            adr0 := arr + t0
            adr1 := arr + t1
            elem0 := *adr0   //arr[j]
            elem1 := *adr1   //arr[j-1]
            if (elem0 >= elem1) goto WEnd
            *adr0 := elem1                  //B6
            *adr1 := elem0
            j := j - 1
            goto WBegin
WEnd:       i := i + 1                     //B7
            goto FBegin
End:        return                         //B8
```

```graphviz
digraph{
    START -> B1;
    B1->B2;
    B2->B3, B8;
    B3->B4;
    B4->B5, B7;
    B5->B6, B7;
    B6->B4;
    B7->B2
    B8->END
}
```

* blok podstawowy - fragment kodu, do którego mamy jedno wejście na jego początku oraz wyjście na jego końcu. Bez możliwości rozpoczęcia wykonywania instrukcji od żadnego innego miejsca bloku.

* graf przepływu sterowania - graf skierowany ilustrujący wejścia i wyjścia pomiędzy blokami podstawowymi. Wierzchołki to bloki podstawowe, a krawędzie to skoki pomiędzy nimi.

## Zadanie 8
:::info
Autor: Kamil Puchacz	
:::

:::info
Być może jest to zaskakujące, ale poniższy kod jest poprawny i w dodatku czasami korzysta się z tej niskopoziomowej techniki optymalizacji. Co robi procedura «secret»?
:::

```=
void secret(uint8_t *to, uint8_t *from, size_t count) {
    size_t n = (count + 7) / 8;
    switch (count % 8) {
        case 0: do { *to++ = *from++;
        case 7:      *to++ = *from++;
        case 6:      *to++ = *from++;
        case 5:      *to++ = *from++;
        case 4:      *to++ = *from++;
        case 3:      *to++ = *from++;
        case 2:      *to++ = *from++;
        case 1:      *to++ = *from++; } while (--n > 0);
    }
}
```
Ta procedura kopiuje n bajtów (lub liczb typu uint8_t) z położenia w pamięci from do pamięci położonej pod adresem 'to'.
Procedura Secret to taki odpowiednik procedury memcpy. 
przypadki case zastępują nam w tym przypadku etykiety oraz skoki goto. W rzeczywistości jest to sekwencyjny kod zaczynający się od case 0 (po prostu jest oetykietowany).

Trzeba jeszcze napisać wersje z goto:

```=
void secret2(uint8_t *to, uint8_t *from, size_t count) {
    size_t n = (count + 7) / 8;

    static void* label[]={ &&case_0, &&case_1, &&case_2, &&case_3, &&case_4, &&case_5, &&case_6, &&case_7};
    goto *label[count%8];

    case_0: *to++ = *from++;
    case_7: *to++ = *from++;
    case_6: *to++ = *from++;
    case_5: *to++ = *from++;
    case_4: *to++ = *from++;
    case_3: *to++ = *from++;
    case_2: *to++ = *from++;
    case_1: *to++ = *from++;
    --n;
    if(n>0) goto *label[0];
}
```

