---
# System prepended metadata

title: 'C: Отчёт по второй лабораторной работе'

---

# C: Отчёт по второй лабораторной работе
## Оглавление.
[[_TOC_]]
## Задача 1.
### Условие.
Найти среднее геометрическое положительных элементов массива.
### Решение.
Обратился к [википедии](https://en.wikipedia.org/wiki/Geometric_mean) для ознакомления с этой операцией.

$`(\prod^n_{i=1}x_i)^{1 \over n}`$, где $`n`$ -количество элементов. 

Разбил задачу на следующие функции:
- `input_array` - ввод массива
- `filter_positive_array` - создание нового массива, содержащего только положительные элементы
- `geometric_mean` - нахождение среднего геометрического элементов массива 
- `print_result` - вывод результата
###  Тестироание.
Написал тесты и произвёл тестирование программы. Проверяю покрытие тестами. 

```
$ gcov main.c
File 'main.c'
Lines executed:100.00% of 19
Creating 'main.c.gcov'

$ gcov array.c
File 'array.c'
Lines executed:90.63% of 32
Creating 'array.c.gcov'
```

Не удалось достичь 100% покрытия кода. Рассмотрим вывод утилиты `gcov`.

```
        -:    0:Source:array.c
        -:    0:Graph:array.gcno
        -:    0:Data:array.gcda
        -:    0:Runs:8
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        -:    2:#include <math.h>
        -:    3:
        -:    4:#include "array.h"
        -:    5:
        8:    6:int input_array(int *array, int *lenght)
        -:    7:{
        8:    8:    if (!array || !lenght)
    #####:    9:        return POINTER_ERROR;
        -:   10:    
        8:   11:    int err = INPUT_SUCCESS;
        -:   12:
        8:   13:    printf("Input lenght of array: ");
        8:   14:    if (scanf("%d", lenght) != 1 || *lenght <= 0 || *lenght > MAX_ARRAY_SIZE)
        3:   15:        err = INPUT_ERROR;
        8:   16:    if (!err)
        5:   17:        printf("Input array elements: ");
        -:   18:    
       39:   19:    for (int i = 0; i < (*lenght) && !err; i++)
        -:   20:    {
       31:   21:        if (scanf("%d", array + i) != 1)
        1:   22:            err = INPUT_ERROR; 
        -:   23:    }
        -:   24:    
        8:   25:    return err;
        -:   26:}
        -:   27:
        4:   28:int filter_positive_array(int *array, int *lenght, int *filtered_array, int *filtered_lenght)
        -:   29:{ 
        4:   30:    if (!array || !lenght || !filtered_array || !filtered_lenght)
    #####:   31:        return POINTER_ERROR;
        -:   32:
        4:   33:    *filtered_lenght = 0;
       32:   34:    for (int i = 0; i < *lenght; i++)
       28:   35:        if (array[i] > 0)
        -:   36:        {
       12:   37:            filtered_array[*filtered_lenght] = array[i];
       12:   38:            (*filtered_lenght)++;
        -:   39:        }
        -:   40:            
        4:   41:    return 0;
        -:   42:}
        3:   43:double geometric_mean(int *array, int *lenght)
        -:   44:{
        3:   45:    if (!array || !lenght)
    #####:   46:        return POINTER_ERROR;
        -:   47:    
        3:   48:    int product = 1;
        -:   49:
       15:   50:    for (int i = 0; i < *lenght; i++)
       12:   51:        product *= array[i];
        -:   52:    
        3:   53:    return pow(product, 1.0 / (double)(*lenght));
        -:   54:}
        -:   55:
        3:   56:void print_result(double result)
        -:   57:{
        3:   58:    printf("Result is %lf", result);
        3:   59:}
```
Не покрыты тестами только участки кода, отвечающие за проверку нулевых указателей.

## Задача 2.
### Условие.
Сформируйте новый массив из элементов исходного массива. При этом в новый массив
помещаются (копируются) элементы исходного массива, которые являются числами Армстронга.
### Решение.
Обратился к [википедии](https://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%BE_%D0%90%D1%80%D0%BC%D1%81%D1%82%D1%80%D0%BE%D0%BD%D0%B3%D0%B0) для ознакомления с данным понятием.

Любое число Армстронга можно представить в виде $`n=\sum _{{i=1}}^{k}{d_i}^{k}`$, где $`k`$ - количество разрядов числа, а $`d_i`$ - $`i`$-ый разряд числа.

Разбил задачу на следующие функции:
- `input_array` - ввод массива
- `output_array` - вывод массива
- `filter_armstrong_array` - создание нового массива, содержащего только числа Армстронга
- `is_armstrong_number` - проверка числа на число Армстронга
- `get_digits_of_number` - возращает количество разрядов числа
- `my_pow` - возведение в степень целого числа

### Тестирование.
Написал тесты для задачи и произвел тестирование. Провел покрытие кода решения тестами.
```
$ gcov main.c
File 'main.c'
Lines executed:100.00% of 16
Creating 'main.c.gcov'

$ gcov untils.c
File 'untils.c'
Lines executed:94.34% of 53
Creating 'untils.c.gcov'
```
Не удалось достичь 100% покрытия кода. Рассмотрим результаты работы `gcov`.
```
        -:    0:Source:untils.c
        -:    0:Graph:untils.gcno
        -:    0:Data:untils.gcda
        -:    0:Runs:8
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        -:    2:#include "untils.h"
        -:    3:
        8:    4:int input_array(long long *array, int *lenght)
        -:    5:{
        8:    6:    if (!array || !lenght)
    #####:    7:        return POINTER_ERROR;
        -:    8:    
        8:    9:    int err = INPUT_SUCCESS;
        -:   10:
        8:   11:    printf("Input lenght of array: ");
        8:   12:    if (scanf("%d", lenght) != 1 || *lenght <= 0 || *lenght > MAX_ARRAY_SIZE)
        3:   13:        err = INPUT_ERROR;
        8:   14:    if (!err)
        5:   15:        printf("Input array elements: ");
        -:   16:    
       36:   17:    for (int i = 0; i < (*lenght) && !err; i++)
        -:   18:    {
       28:   19:        if (scanf("%lld", array + i) != 1)
        1:   20:            err = INPUT_ERROR; 
        -:   21:    }
        -:   22:    
        8:   23:    return err;
        -:   24:}
        -:   25:
        3:   26:int output_array(long long *array, int lenght)
        -:   27:{
        3:   28:    if (!array)
    #####:   29:        return POINTER_ERROR;
        -:   30:    
        3:   31:    printf("Your array is \n");
       17:   32:    for (int i = 0; i < lenght; i++)
       14:   33:        printf("%lld ", array[i]);
        3:   34:    printf("\n");
        -:   35:
        3:   36:    return 0;
        -:   37:}
        -:   38:
        4:   39:int filter_armstrong_array(long long *array, int *lenght, long long *filtered_array, int *filtered_lenght)
        -:   40:{ 
        4:   41:    if (!array || !lenght || !filtered_array || !filtered_lenght)
    #####:   42:        return POINTER_ERROR;
        -:   43:
        4:   44:    *filtered_lenght = 0;
       29:   45:    for (int i = 0; i < *lenght; i++)
       25:   46:        if (is_armstrong_number(array[i]))
        -:   47:        {
       14:   48:            filtered_array[*filtered_lenght] = array[i];
       14:   49:            (*filtered_lenght)++;
        -:   50:        }
        -:   51:            
        4:   52:    return 0;
        -:   53:}
        -:   54:
       25:   55:int is_armstrong_number(long long number)
        -:   56:{
       25:   57:    int result = number >= 0;
        -:   58:
       25:   59:    int digits = get_digits_of_number(number);
        -:   60:
       25:   61:    long long temp_result = 0;
       25:   62:    long long temp_number = number;
        -:   63:
       25:   64:    if (result)
        -:   65:    {
      123:   66:        while (temp_number > 0 && temp_result <= number)
        -:   67:        {
       91:   68:            temp_result += my_pow(temp_number % 10, digits);
       91:   69:            temp_number /= 10;
        -:   70:        }
       16:   71:        result = temp_result == number;
        -:   72:    }
        -:   73:
       25:   74:    return result;
        -:   75:}
        -:   76:
       91:   77:long long my_pow(const long long number, const int power)
        -:   78:{
       91:   79:    long long result = 1;
      816:   80:    for (int i = 0; i < power; i++)
      725:   81:        result *= number;
       91:   82:    return result;
        -:   83:}
        -:   84:
       25:   85:int get_digits_of_number(const long long number)
        -:   86:{
       25:   87:    int digits = 1;
       25:   88:    long long temp = 10;
      126:   89:    while (temp < number)
        -:   90:    {
       76:   91:        digits++;
       76:   92:        temp *= 10;
        -:   93:    }
       25:   94:    return digits;
        -:   95:}
```
Не достигаюся только строки кода, отвечающие за обработку нулевых указателей.

## Задача 3.
### Условие.
Вставьте в исходный массив после каждого положительного элемента этот же элемент,
записанный наоборот.
### Решение.
Заметил, что размер массива может увеличиться максимум в два раза, поэтому принял решение выделять в два раза больше пямити для нового массива, для предотвращения ошибок выхода за пределы выделенной памяти.

Разбил решение на следующие функции:
- `input_array` - ввод массива
- `output_array` -  вывод массива
- `generate_new_array` - обработка массива согласно условию
- `insert_array` -  вставка элемента в определённую позицию массива со сдвигом всех элементов 
- `copy_array` - копирование массива в новую область памяти  
- `reverse_number` - функция возвращает обращенное число

### Тестирование.
Написал тесты для задачи и произвел тестирование. Провел покрытие кода решения тестами.
```
$ gcov main.c
File 'main.c'
Lines executed:100.00% of 16
Creating 'main.c.gcov'

$ gcov untils.c
File 'untils.c'
Lines executed:92.16% of 51
Creating 'untils.c.gcov'
```
Не удалось достичь 100% покрытия кода. Рассмотрим результаты работы `gcov`.

```
        -:    0:Source:untils.c
        -:    0:Graph:untils.gcno
        -:    0:Data:untils.gcda
        -:    0:Runs:7
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        -:    2:#include "untils.h"
        -:    3:
        7:    4:int input_array(long long *array, int *lenght)
        -:    5:{
        7:    6:    if (!array || !lenght)
    #####:    7:        return POINTER_ERROR;
        -:    8:    
        7:    9:    int err = INPUT_SUCCESS;
        -:   10:
        7:   11:    printf("Input lenght of array: ");
        7:   12:    if (scanf("%d", lenght) != 1 || *lenght <= 0 || *lenght > MAX_ARRAY_SIZE)
        3:   13:        err = INPUT_ERROR;
        7:   14:    if (!err)
        4:   15:        printf("Input array elements: ");
        -:   16:    
       28:   17:    for (int i = 0; i < (*lenght) && !err; i++)
        -:   18:    {
       21:   19:        if (scanf("%lld", array + i) != 1)
        1:   20:            err = INPUT_ERROR; 
        -:   21:    }
        -:   22:    
        7:   23:    return err;
        -:   24:}
        -:   25:
        3:   26:int output_array(long long *array, int lenght)
        -:   27:{
        3:   28:    if (!array)
    #####:   29:        return POINTER_ERROR;
        -:   30:    
        3:   31:    printf("Your array is \n");
       28:   32:    for (int i = 0; i < lenght; i++)
       25:   33:        printf("%lld ", array[i]);
        3:   34:    printf("\n");
        -:   35:
        3:   36:    return 0;
        -:   37:}
        -:   38:
        -:   39:
        3:   40:int generate_new_array(const long long *array, const int lenght, long long *generated, int *generated_lenght)
        -:   41:{
        3:   42:    int err = copy_array(generated, array, lenght);
        -:   43:    
        3:   44:    if (!err)
        -:   45:    {
        3:   46:        *generated_lenght = lenght;
       21:   47:        for (int i = 0; i < *generated_lenght; i++)
        -:   48:        {
       18:   49:            if (generated[i] > 0)
        -:   50:            {
        7:   51:                insert_array(reverse_number(generated[i]), i + 1, generated, *generated_lenght);
        7:   52:                (*generated_lenght)++;
        7:   53:                i++;
        -:   54:            }
        -:   55:        }
        -:   56:    }
        -:   57:
        3:   58:    return err;
        -:   59:}
        -:   60:
        7:   61:int insert_array(long long element, int position, long long *array, int lenght)
        -:   62:{
        7:   63:    if (!array)
    #####:   64:        return POINTER_ERROR;
        -:   65:    
       18:   66:    for (int i = lenght; i > position; i--)
       11:   67:        array[i] = array[i - 1];
        -:   68:    
        7:   69:    array[position] = element;
        -:   70:
        7:   71:    return 1;
        -:   72:}
        -:   73:
        3:   74:int copy_array(long long *dest_array, const long long *source_array, const int lenght)
        -:   75:{
        3:   76:    if (!dest_array || !source_array)
    #####:   77:        return POINTER_ERROR;
        -:   78:
       21:   79:    for (int i = 0; i < lenght; i++)
       18:   80:        dest_array[i] = source_array[i];
        -:   81:    
        3:   82:    return 0;
        -:   83:}
        -:   84:
        7:   85:long long reverse_number(long long number)
        -:   86:{
        7:   87:    long long result = 0;
        -:   88:
       57:   89:    while (number > 0)
        -:   90:    {
       43:   91:        result *= 10;
       43:   92:        result += number % 10;
       43:   93:        number /= 10;
        -:   94:    }
        -:   95:
        7:   96:    return result;
        -:   97:}

```
Не достигаюся только строки кода, отвечающие за обработку нулевых указателей.

## Задача 4.
### Условие.
Упорядочите исходный массив по возрастанию выбором.
### Решение.
С данным методом сортировки уже работал в рамках лабораторных работ и семинаров по программированию 1-го семестра. Кратко дам описание алгоритму, описав его шаги:
- находим номер минимального значения в текущем списке
- производим обмен этого значения со значением первой неотсортированной позиции (обмен не нужен, если минимальный элемент уже находится на данной позиции)
- теперь сортируем хвост списка, исключив из рассмотрения уже отсортированные элементы.

Нужно обратить внимание, что данная реализация является неустойчивой сортировкой, но в рамках данного задания это не появляет на результаты работы программы.

Разбил решение на следующие функции:
- `input_array` - ввод массива
- `output_array` - вывод массива
- `selection_sort` - сортировка массива

### Тестирование.
Написал тесты для задачи и произвел тестирование. Провел покрытие кода решения тестами.
```
$ gcov main.c
File 'main.c'
Lines executed:100.00% of 12
Creating 'main.c.gcov'

$ gcov untils.c 
File 'untils.c'
Lines executed:91.18% of 34
Creating 'untils.c.gcov'
```
Не удалось достичь 100% покрытия кода. Рассмотрим результаты работы `gcov`.
```
        -:    0:Source:untils.c
        -:    0:Graph:untils.gcno
        -:    0:Data:untils.gcda
        -:    0:Runs:7
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        -:    2:#include "untils.h"
        -:    3:
        7:    4:int input_array(long long *array, int *lenght)
        -:    5:{
        7:    6:    if (!array || !lenght)
    #####:    7:        return POINTER_ERROR;
        -:    8:    
        7:    9:    int err = INPUT_SUCCESS;
        -:   10:
        7:   11:    printf("Input lenght of array: ");
        7:   12:    if (scanf("%d", lenght) != 1 || *lenght <= 0 || *lenght > MAX_ARRAY_SIZE)
        3:   13:        err = INPUT_ERROR;
        7:   14:    if (!err)
        4:   15:        printf("Input array elements: ");
        -:   16:    
       40:   17:    for (int i = 0; i < (*lenght) && !err; i++)
        -:   18:    {
       33:   19:        if (scanf("%lld", array + i) != 1)
        1:   20:            err = INPUT_ERROR; 
        -:   21:    }
        -:   22:    
        7:   23:    return err;
        -:   24:}
        -:   25:
        3:   26:int output_array(long long *array, int lenght)
        -:   27:{
        3:   28:    if (!array)
    #####:   29:        return POINTER_ERROR;
        -:   30:    
        3:   31:    printf("Your array is \n");
       33:   32:    for (int i = 0; i < lenght; i++)
       30:   33:        printf("%lld ", array[i]);
        3:   34:    printf("\n");
        -:   35:
        3:   36:    return 0;
        -:   37:}
        -:   38:
        3:   39:int selection_sort(long long *array, const int lenght)
        -:   40:{
        3:   41:    if (!array)
    #####:   42:        return POINTER_ERROR;
        -:   43:    
       30:   44:    for (int i = 0; i < lenght - 1; i++)
        -:   45:    {
       27:   46:        long long min_element = array[i];
       27:   47:        int min_position = i;
        -:   48:        
      162:   49:        for (int j = i + 1; j < lenght; j++)
        -:   50:        {
      135:   51:            if (min_element > array[j])
        -:   52:            {
       50:   53:                min_element = array[j];
       50:   54:                min_position = j;
        -:   55:            }            
        -:   56:        }
        -:   57:
       27:   58:        array[min_position] = array[i];
       27:   59:        array[i] = min_element;
        -:   60:    }
        -:   61:
        3:   62:    return 0;
        -:   63:}

```
Не достигаюся только строки кода, отвечающие за обработку нулевых указателей.

## Задача 5.
### Условие.
Выполните обработку массива указанным образом:
Вычислить значение `x[0]*y[0] + x[1]*y[1] + ... + x[k]*y[k]`, где `x[i]` – отрицательные элементы массива `a` из `n` элементов, взятые в порядке их следования; `y[i]` – положительные элементы этого массива, взятые в обратном порядке; `k = min(p,q)`, где `p` – количество положительных элементов массива `a`, `q` – количество отрицательных элементов этого массива.

При решении пятой задачи в методических целях нельзя использовать выражение вида `a[i]` и вообще квадратные скобки. Вместо указанного выражения используется выражение `*pa`, где `pa` - указатель на `i`-ый элемент массива (именно на `i`-ый элемент, а не выражение вида `*(pa + i)`). Также нельзя передавать как аргумент размер массива в элементах. Вместо этого предлагается использовать пару указателей: на первый элемент массива и на элемент массива, расположенный за последним. Ситуация, когда эти указатели совпадают, означает пустоту обрабатываемого массива.
### Решение.

Опишу алгоритм обработки массива. Беру два указателя, один указывает на начало (далее `A`) массива, другой на конец (далее `B`). Смещаю `A` вправо пока не встречу отрицательный элемент, далее смещаю `B` влево, пока не встречу положительный элемент, повторяю данные смещения пока `A` или `B` не выйдут за границы массива.   

Разбил решение на следующие функции:
- `input_array` - ввод массива
- `process_array` - обработка массива согласно условию
- `print_result` - вывод результата
### Тестирование.
Написал тесты для задачи и произвел тестирование. Провел проверку покрытия кода решения тестами.
```
$ gcov main.c
File 'main.c'
Lines executed:100.00% of 13
Creating 'main.c.gcov'

$ gcov untils.c
File 'untils.c'
Lines executed:94.12% of 34
Creating 'untils.c.gcov'
```
Не удалось достичь 100% покрытия кода. Рассмотрим результаты работы `gcov`.
```
        -:    0:Source:untils.c
        -:    0:Graph:untils.gcno
        -:    0:Data:untils.gcda
        -:    0:Runs:8
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        -:    2:#include "untils.h"
        -:    3:
        8:    4:int input_array(long long *array, long long **end)
        -:    5:{
        8:    6:    if (!array || !end)
    #####:    7:        return POINTER_ERROR;
        -:    8:    
        8:    9:    int err = INPUT_SUCCESS;
        -:   10:
        8:   11:    int lenght = 0;
        -:   12:
        8:   13:    printf("Input lenght of array: ");
        -:   14:
        8:   15:    if (scanf("%d", &lenght) != 1 || lenght <= 0 || lenght > MAX_ARRAY_SIZE)
        3:   16:        err = INPUT_ERROR;
        -:   17:    
        8:   18:    if (!err)
        5:   19:        printf("Input array elements: ");
        -:   20:    
        8:   21:    *end = array + lenght;
        -:   22:    
       38:   23:    for (long long *i = array; i != *end && !err; i++)
        -:   24:    {
       30:   25:        if (scanf("%lld", i) != 1)
        1:   26:            err = INPUT_ERROR; 
        -:   27:    }
        -:   28:    
        8:   29:    return err;
        -:   30:}
        -:   31:
        4:   32:int process_array(long long *array, long long *end, long long *result)
        -:   33:{
        4:   34:    if (!array || !end || !result)
    #####:   35:        return POINTER_ERROR;
        -:   36:    
        4:   37:    *result = 0;
        -:   38:
        4:   39:    long long *i = array;
        4:   40:    long long *j = end - 1;
        -:   41:
       22:   42:    while (i < end && j > array)
        -:   43:    {        
       45:   44:        while (*i >= 0 && i < end) 
       17:   45:            i++;
       39:   46:        while (*j <= 0 && j > array) 
       11:   47:            j--;
        -:   48:        
       14:   49:        if (i < end && j > array)
       10:   50:            *result += (*i) * (*j);
        -:   51:        
       14:   52:        i++;
       14:   53:        j--;
        -:   54:    }
        -:   55:    
        4:   56:    return *result == 0;
        -:   57:}
        -:   58:
        3:   59:void print_result(long long result)
        -:   60:{
        3:   61:    printf("Result is %lld\n", result);
        3:   62:}

```
Не достигаюся только строки кода, отвечающие за обработку нулевых указателей.
### Возникшие проблемы.
Не понял из условия задания, что массив нулевых элементов является исключительной ситуацей. Исправил решение в ревизии 8380141069d5c1b4bc82d8498f1284ea18d12489 и тесты в ревизии 1f2b3f934b1941f0508d675f819580c9f9117989.
## Задача 6.
### Условие.
На основе задачи 5 проведите сравнение производительности разных способов работы с
элементами массива
- использование операции индексации `a[i]`;
- формальная замена операции индексации на выражение `*(a + i)`;
- использование указателей для работы с массивом.
### Решение.
Ознакомился с работой функции `gettimeofday` из библиотеки `<sys/time.h>`. Повторил стандарт оформления таблиц в Markdown для их автоматической генерации. Ознакомился функциями `rand`, `srand` библиотеки `<stdlib.h>` для генерации псевдослучайных массивов.

Переписал функцию, изменив способ обращения к массиву. Написал функции тестирования каждого способа. Решение разбито на следующие функции:
- Первый метод идексации с помощью `a[i]`
  - `process_1` - нахождение результата
  - `test_process_1` - тестирование функции
- Второй метод идексации с помощью  `*(a + i)`
  - `process_2` - нахождение результата
  - `test_process_2` - тестирование функции
- Третий метод идексации, использую указатели.
  - `process_3` - нахождение результата
  - `test_process_3` - тестирование функции
- Вывод таблицы
  - `print_table_header` - печать заголовка таблицы
  - `print_table_row` - печать строки таблицы
- Работа с генератором псевдослучайных чисел
  - `init_random_generator` - сброс генератора
  - `random_array` - заполнения массива случайными значениями
- Работа с массивами
  - `copy_array` - копирования массива в другую область памяти
  - `output_array` - вывод содержимого массива
 
### Тестирование. 

Для достижения более объективных результатов тестирования, использовал виртуальную машину со следующими характеристиками:
- CPU: 1 виртуальное ядро Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz
- RAM: 512 MB DDR3 1600 MHz
- Виртулизация: Hyper-V
- ОС:  Ubuntu 19.10 (GNU/Linux 5.3.0-18-generic x86_64)
  
> В следущей задаче буду ссылаться  на данную сборку.

Провел тестирование, привожу результаты с включенной оптимизацией компиляции и выключенной.

**Таблица 1. Тестирование с включенной оптимизацией компилятора `gcc`**

|Repeats|   Size|   a[i]| *(a+i)|Pointer|
|-------|-------|-------|-------|-------|
|     10|     10|     50|     54|     52|
|     10|    100|     67|     60|     64|
|     10|    500|     90|     83|     81|
|     10|   1000|    272|    120|    110|
|    100|     10|    683|    564|    545|
|    100|    100|    703|    620|    594|
|    100|    500|   1142|    978|    968|
|    100|   1000|   2073|   1216|   1169|
|    500|     10|   3669|   3809|   3630|
|    500|    100|   3400|   2910|   3246|
|    500|    500|   7689|   4976|   4755|
|    500|   1000|  10208|   6701|   6793|
|   1000|     10|   6123|   6554|   6011|
|   1000|    100|   7350|   6468|  10068|
|   1000|    500|  14422|  10400|  11466|
|   1000|   1000|  19898|  13782|  13574|
|  10000|     10|  66971|  60695|  65082|
|  10000|    100|  68703|  79796|  64733|
|  10000|    500| 121940|  99124| 109348|
|  10000|   1000| 178541| 143954| 130838|
| 100000|     10| 604342| 598117| 597620|
| 100000|    100| 727283| 668063| 667098|
| 100000|    500|1118172| 987837| 933543|
| 100000|   1000|1692489|1433616|1285605|

**Таблица 2. Тестирование без оптимизаций компилятора**

|Repeats|   Size|   a[i]| *(a+i)|Pointer|
|-------|-------|-------|-------|-------|
|     10|     10|     66|     65|     67|
|     10|    100|     66|     66|     63|
|     10|    500|    295|     98|     84|
|     10|   1000|    147|    148|    126|
|    100|     10|    609|    522|    514|
|    100|    100|    737|    814|    954|
|    100|    500|    998|   1033|    955|
|    100|   1000|   3187|   1687|   1414|
|    500|     10|   3291|   3415|   2922|
|    500|    100|   3896|   3155|   3331|
|    500|    500|   6852|   5061|   5217|
|    500|   1000|   9676|   8137|   7013|
|   1000|     10|   6478|   6427|   6074|
|   1000|    100|   8543|   7179|   6560|
|   1000|    500|  15227|  10956|  10276|
|   1000|   1000|  20738|  17018|  14030|
|  10000|     10|  62789|  63287|  63125|
|  10000|    100|  76243|  67858|  67356|
|  10000|    500| 125126| 106430|  95977|
|  10000|   1000| 170570| 151215| 127776|
| 100000|     10| 606538| 592828| 591332|
| 100000|    100| 714777| 685026| 658594|
| 100000|    500|1234805|1094469| 964170|
| 100000|   1000|2252282|1733109|1472254|


### Ответы на вопросы.
1. На что влияет размер массива?
    
    Так как данный алгоритм линейный, время выполнения программы линейно зависимо от  размер массива. С бо́льшим количеством элементов массива более явно видны различия методов.

2. Почему приходится выполнять не один замер, а несколько?
    
    На малых количествах повторений разница между разнымими способами работы с массивом минимальна (особенно с включенной оптимизацией), чтобы эта разница была больше погрешности измерения, необходимо произвести бо́льшее количество измерений.

3. Какой способ работы с элементами массива оказался самым производительным? Как вы объясняете этот результат?
    
    Способ работы с указателями оказался самым производительным, потому что в нём опускаются арифметические операции по нахождению адреса памяти для нужного элемента массива. При хранении номера элемента, а не его адреса, выполняется сложение адреса начала массива и номера нужного элемента, умножего на размер одной ячейки.

## Задача 7.
### Условие.
Проведите профилирование программы, написанной для решения задачи 4. Проанализируйте полученные данные профилирования. Часть этих данных приведите в отчете.
### Внесенные правки и особенности решения.
Изменил количество выделяемой памяти до 20 000 элементов. (исправил константу)

Тестированиее проводил на виртуальной машине, характеристики которой описал в задаче 6.
### Ответы на вопросы.
1. **Совпадают ли ваши представления о времени работы той или иной функции с тем, что вы получили на практике? Если нет, то для какой функции и почему?**
    
Мои представления совпадают.

2. **Увеличьте количество элементов в массиве до 10000, выполните профилирование. Что
изменилось? В ответе приведите как сами данные, так и объяснение полученных
результатов.**

```Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
100.85      0.71     0.71        1   705.95   705.95  selection_sort
  0.00      0.71     0.00        1     0.00     0.00  input_array
  0.00      0.71     0.00        1     0.00     0.00  output_array
```

Ввод и вывод массива выполняются практически мгновенно, из-за того, что их сложность линейна относительно размера массива $`O(n)`$. Сортировка занимает бо́льшую часть времени, так как её сложность, как минимум $`O(n!)`$.

3. **Уменьшите количество элементов до 10, выполните профилирование. Что изменилось?
В ответе приведите как сами данные, так и объяснение полученных результатов.**

```
%   cumulative   self              self     total
time   seconds   seconds    calls  Ts/call  Ts/call  name
0.00      0.00     0.00        1     0.00     0.00  input_array
0.00      0.00     0.00        1     0.00     0.00  output_array
0.00      0.00     0.00        1     0.00     0.00  selection_sort
```
Произвести профилирование не удалось из-за очень быстрой работы алгоритма.

4. **Изучите, что делают ключи “-O1”, “-O2”, “-O3”. Выполните профилирование вашей
программы, увеличив размер массива до 10000 элементов, для каждого из этих ключей.
Проанализируйте полученные результаты, сделайте выводы.**

Тестирование произвожу на 20 000 элементов. Хочу приложить отрывок [статьи](https://wiki.gentoo.org/wiki/GCC_optimization/ru#-O)

>>>
Давайте исследуем каждый уровень оптимизации:

- `-O0`: Этот уровень (буква "O" и ноль за ней) отключает оптимизацию полностью и является уровнем по умолчанию, если никакого уровня с префиксом `-O` не указано в переменных `CFLAGS` или `CXXFLAGS`. Это сокращает время компиляции и может улучшить данные для отладки, но некоторые приложения не будут работать должным образом без оптимизации. Эта опция не рекомендуется, за исключением использования в целях отладки.
- `-O1`: Это наиболее простой уровень оптимизации. Компилятор попытается сгенерировать быстрый, занимающий меньше объема код, без затрачивания наибольшего времени компиляции. Он достаточно простой, но должен всегда выполнять свою работу.
- `-O2`: Шаг вперед от `-O1`. *Рекомендуемый* уровень оптимизации, до тех пор пока не понадобится что-то особенное. `-O2` активирует несколько дополнительных флагов вдобавок к флагам, активированных `-O1`. С параметром `-O2`, компилятор попытается увеличить производительность кода без нарушения размера, и без затрачивания большого количества времени компиляции. На этом уровне могут быть использованы SSE и AVX, но YMM-регистры не будут использоваться пока не будет включена опция `-ftree-vectorize`.
- `-O3`: Это наибольший возможный уровень оптимизации. Включает оптимизации, являющейся дорогостоящей с точки зрения времени компиляции и потребления памяти. Компиляция с `-O3` не является гарантированным способом повышения производительности, и на самом деле во многих случаях может привести к замедлению системы из-за больших двоичных файлов и увеличения потребления памяти. `-O3` известен также тем, что ломает несколько пакетов. Использование `-O3` не рекомендуется. Хотя, это также включает `-ftree-vectorize`, и циклы в коде векторизируются и используют регистры AVX YMM.
- `-Os`: На этом уровне код будет оптимизирован по объему. Он активирует все параметры `-O2`, которые не приводят к увеличению размера генерируемого кода. Он может быть полезным на компьютерах, которые обладают чрезвычайно ограниченным пространством жесткого диска и/или процессоры с небольшим размером кэша.
- `-Og`: В GCC 4.8 был введен новый общий уровень оптимизации `-Og`. Он удовлетворяет потребность в быстрой компиляции и имеет превосходные возможности для отладки, обеспечивая при этом приемлемый уровень производительности во время выполнения. Общий опыт разработки должен быть лучше, чем с уровнем оптимизации по умолчанию `-O0`. Обратите внимание, что `-Og` не означает `-g`, он просто отключает оптимизацию кода, которая может помешать отладке.
- `-Ofast`: Новое в GCC 4.7, состоит из `-O3` плюс `-ffast-math`, `-fno-protect-parens`, и  `-fstack-arrays`. Этот параметр нарушает строгое соответствие стандарту, и не рекомендуется для использования.

Как упомянуто ранее, параметр `-O2` - рекомендуемый уровень оптимизации. Если компиляция пакета выдает сообщение об ошибке и не используется параметр `-O2`, то попробуйте перекопилировать с этой опцией. В качестве выхода, попробуйте установить переменные `CFLAGS` и `CXXFLAGS` на наименьший уровень оптимизации, такой как `-O1`, или даже `-O0 -g2 -ggdb` (для сообщения об ошибках и проверки возможных проблем).
>>>


0. Без оптимизации (Ключ компиляции `-O0`)

    ```
      %   cumulative   self              self     total
      time   seconds   seconds    calls   s/call   s/call  name
    100.85      2.71     2.71        1     2.71     2.71  selection_sort
      0.00      2.71     0.00        1     0.00     0.00  input_array
      0.00      2.71     0.00        1     0.00     0.00  output_array
    ```

1. Оптимизация (Ключ компиляции `-O1`)
    ```
    Each sample counts as 0.01 seconds.
      %   cumulative   self              self     total
      time   seconds   seconds    calls  ms/call  ms/call  name
    100.97      0.97     0.97        1   969.32   969.32  selection_sort
      0.00      0.97     0.00        1     0.00     0.00  input_array
      0.00      0.97     0.00        1     0.00     0.00  output_array
    ```
2. Оптимизация (Ключ компиляции `-O2`)

    ```
    Each sample counts as 0.01 seconds.
      %   cumulative   self              self     total
      time   seconds   seconds    calls  Ts/call  Ts/call  name
    101.17      1.90     1.90                             selection_sort
    ```
3. Оптимизации с применением эксперементальных методов  (Ключ компиляции `-O3`)

    ```
    Each sample counts as 0.01 seconds.
      %   cumulative   self              self     total
      time   seconds   seconds    calls  Ts/call  Ts/call  name
    101.17      1.88     1.88                             selection_sort
    ```
### Некоторые выводы.

Из результатов сборки программы с разными параметрами оптимизации можем сделать некоторые выводы:
- опитимизация может сильно увеличить скорость программы (в наших примерах на 170% быстрее с ключем `-O1`, по сравнению с отключенной оптимизацией)
- применения избыточных оптимизаций компилятора может наоборот снизить скорость работы программы, особенно для реализации стандартных алгоритмов
- применение некоторых оптимизаций может повлечь за собой не работоспособность программы
