# C: Отчёт по первой лабораторной работе
## Оглавление
[[_TOC_]]
## Задача 1.
Необходимо познакомьтесь с сообщениями, которые выдает компилятор во время компиляции
программы с синтаксическими ошибками
### Ошибка 1
#### Сборка
```
$ make
gcc -Wall -Wextra -Werror -o main.out main.c
main.c:1:1: error: unknown type name ‘include’
include studio.h
^~~~~~~
main.c:1:15: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘.’ token
include studio.h
^
main.c:4:2: error: expected identifier or ‘(’ before ‘int’
int s;
^~~
Makefile:10: recipe for target 'all' failed
make: *** [all] Error 1
```
#### Описание ошибки и исправление
Неправильно указана команда препроцессора, команды препроцессора должны начинаться
с символа `#`. Исправим добавив этот символ.
```
$git diff
diff --git a/lab_01_1_2/main.c b/lab_01_1_2/main.c
index 3bd3685..44357fa 100644
--- a/lab_01_1_2/main.c
+++ b/lab_01_1_2/main.c
@@ -1,4 +1,4 @@
-include studio.h
+#include studio.h
main{}
(
int s;
```
### Ошибка 2
#### Сборка
```
$ make
gcc -Wall -Wextra -Werror -o main.out main.c
main.c:1:10: error: #include expects "FILENAME" or <FILENAME>
#include studio.h
^~~~~~
main.c:2:5: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
main{}
^
main.c:4:2: error: expected identifier or ‘(’ before ‘int’
int s;
^~~
Makefile:10: recipe for target 'all' failed
make: *** [all] Error 1
```
#### Описание ошибки и исправление
Для команды препроцесора `#include` необходимо указывать имя
подключаемого файла в формате `<FILENAME>` для библиотек и `"FILENAME"` для внутренних файлов. Исправим на `<stdio.h>`,
так как данная библиотека стандартная.
```
$ git diff
diff --git a/lab_01_1_2/main.c b/lab_01_1_2/main.c
index 44357fa..4295654 100644
--- a/lab_01_1_2/main.c
+++ b/lab_01_1_2/main.c
@@ -1,4 +1,4 @@
-#include studio.h
+#include <stdio.h>
main{}
(
int s;
```
### Ошибка 3
#### Сборка
```
$ make
gcc -Wall -Wextra -Werror -o main.out main.c
main.c:2:5: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
main{}
^
main.c:4:2: error: expected identifier or ‘(’ before ‘int’
int s;
^~~
Makefile:10: recipe for target 'all' failed
make: *** [all] Error 1
```
#### Описание ошибки и исправление
Неправильное описание функции. Функции должны объявляется
следующим образом.
```
int demofunc(void)
{
// тело функции
}
```
Исправим код в соответствие выше указанным примером.
```
$ git diff
diff --git a/lab_01_1_2/main.c b/lab_01_1_2/main.c
index 4295654..ecfdeaa 100644
--- a/lab_01_1_2/main.c
+++ b/lab_01_1_2/main.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-main{}
-(
+int main()
+{
int s;
s: = 56;
print (Year has s weeks)
-)
+}
```
### Ошибка 4
#### Сборка
```
$ make
gcc -Wall -Wextra -Werror -o main.out main.c
main.c: In function ‘main’:
main.c:5:5: error: expected expression before ‘=’ token
s: = 56;
^
main.c:6:2: error: implicit declaration of function ‘print’; did you mean ‘printf’? [-Werror=implicit-function-declaration]
print (Year has s weeks)
^~~~~
printf
main.c:6:9: error: ‘Year’ undeclared (first use in this function); did you mean ‘char’?
print (Year has s weeks)
^~~~
char
main.c:6:9: note: each undeclared identifier is reported only once for each function it appears in
main.c:6:14: error: expected ‘)’ before ‘has’
print (Year has s weeks)
^~~
main.c:7:1: error: expected ‘;’ before ‘}’ token
}
^
main.c:5:2: error: label ‘s’ defined but not used [-Werror=unused-label]
s: = 56;
^
main.c:4:6: error: unused variable ‘s’ [-Werror=unused-variable]
int s;
^
cc1: all warnings being treated as errors
Makefile:10: recipe for target 'all' failed
make: *** [all] Error 1
```
#### Описание ошибки и исправление
Неправильное присваивание переменной значения. Исправим убрав символ `:`
```
$ git diff
diff --git a/lab_01_1_2/main.c b/lab_01_1_2/main.c
index ecfdeaa..cc42c2a 100644
--- a/lab_01_1_2/main.c
+++ b/lab_01_1_2/main.c
@@ -2,6 +2,6 @@
int main()
{
int s;
- s: = 56;
+ s = 56;
print (Year has s weeks)
}
```
### Ошибка 5
#### Сборка
```
$ make
gcc -Wall -Wextra -Werror -o main.out main.c
main.c: In function ‘main’:
main.c:6:2: error: implicit declaration of function ‘print’; did you mean ‘printf’? [-Werror=implicit-function-declaration]
print (Year has s weeks)
^~~~~
printf
main.c:6:9: error: ‘Year’ undeclared (first use in this function); did you mean ‘char’?
print (Year has s weeks)
^~~~
char
main.c:6:9: note: each undeclared identifier is reported only once for each function it appears in
main.c:6:14: error: expected ‘)’ before ‘has’
print (Year has s weeks)
^~~
main.c:7:1: error: expected ‘;’ before ‘}’ token
}
^
main.c:4:6: error: variable ‘s’ set but not used [-Werror=unused-but-set-variable]
int s;
^
cc1: all warnings being treated as errors
Makefile:10: recipe for target 'all' failed
make: *** [all] Error 1
```
#### Описание ошибки и исправление
Использование необъявлённой функции `print`. Необходимо исправить название функции
на `printf`.
```
$ git diff
diff --git a/lab_01_1_2/main.c b/lab_01_1_2/main.c
index cc42c2a..b594fa3 100644
--- a/lab_01_1_2/main.c
+++ b/lab_01_1_2/main.c
@@ -3,5 +3,5 @@ int main()
{
int s;
s = 56;
- print (Year has s weeks)
+ printf (Year has s weeks)
}
```
### Ошибка 6
#### Сборка
```
make
gcc -Wall -Wextra -Werror -o main.out main.c
main.c: In function ‘main’:
main.c:6:10: error: ‘Year’ undeclared (first use in this function); did you mean ‘char’?
printf (Year has s weeks)
^~~~
char
main.c:6:10: note: each undeclared identifier is reported only once for each function it appears in
main.c:6:15: error: expected ‘)’ before ‘has’
printf (Year has s weeks)
^~~
main.c:7:1: error: expected ‘;’ before ‘}’ token
}
^
main.c:4:6: error: variable ‘s’ set but not used [-Werror=unused-but-set-variable]
int s;
^
cc1: all warnings being treated as errors
Makefile:10: recipe for target 'all' failed
make: *** [all] Error 1
```
#### Описание ошибки и исправление
Неправильное оформление строки. Строки в Си указываются в двойных ковычках `"some_text"`
```
$ git diff
diff --git a/lab_01_1_2/main.c b/lab_01_1_2/main.c
index b594fa3..3b61c9a 100644
--- a/lab_01_1_2/main.c
+++ b/lab_01_1_2/main.c
@@ -3,5 +3,5 @@ int main()
{
int s;
s = 56;
- printf (Year has s weeks)
+ printf ("Year has s weeks")
}
```
### Ошибка 7
#### Сборка
```
$ make
gcc -Wall -Wextra -Werror -o main.out main.c
main.c: In function ‘main’:
main.c:7:1: error: expected ‘;’ before ‘}’ token
}
^
main.c:4:6: error: variable ‘s’ set but not used [-Werror=unused-but-set-variable]
int s;
^
cc1: all warnings being treated as errors
Makefile:10: recipe for target 'all' failed
make: *** [all] Error 1
```
#### Описание ошибки и исправление
Пропущен символ `;`, обозначающий конец операции. Исправим добавив его.
```
$ git diff
diff --git a/lab_01_1_2/main.c b/lab_01_1_2/main.c
index 3b61c9a..6fad082 100644
--- a/lab_01_1_2/main.c
+++ b/lab_01_1_2/main.c
@@ -3,5 +3,5 @@ int main()
{
int s;
s = 56;
- printf ("Year has s weeks")
+ printf ("Year has s weeks");
}
```
### Ошибка 8
#### Сборка
```
$ make
gcc -Wall -Wextra -Werror -o main.out main.c
main.c: In function ‘main’:
main.c:4:6: error: variable ‘s’ set but not used [-Werror=unused-but-set-variable]
int s;
^
cc1: all warnings being treated as errors
Makefile:10: recipe for target 'all' failed
make: *** [all] Error 1
```
#### Описание ошибки и исправление
Объявление неиспользуемой переменной. Это предупреждение возникло из-за неправильного
использования форматированного вывода.
```
$ git diff
diff --git a/lab_01_1_2/main.c b/lab_01_1_2/main.c
index 6fad082..f4ad78d 100644
--- a/lab_01_1_2/main.c
+++ b/lab_01_1_2/main.c
@@ -3,5 +3,5 @@ int main()
{
int s;
s = 56;
- printf ("Year has s weeks");
+ printf ("Year has %d weeks", s);
}
```
### Исправления стиля кода
```
$ CodeChecker main.c
main.c(4,2): Incorrect indent, (1, but expeted 4)
main.c(5,2): Incorrect indent, (1, but expeted 4)
main.c(6,2): Incorrect indent, (1, but expeted 4)
main.c(6,9): Incorrect spaces count before lexema (1, but expected 0)
$ git diff
diff --git a/lab_01_1_2/main.c b/lab_01_1_2/main.c
index f4ad78d..6e66687 100644
--- a/lab_01_1_2/main.c
+++ b/lab_01_1_2/main.c
@@ -1,7 +1,7 @@
#include <stdio.h>
int main()
{
- int s;
- s = 56;
- printf ("Year has %d weeks", s);
+ int s;
+ s = 56;
+ printf("Year has %d weeks", s);
}
```
## Задача 2.
### Условие.
Треугольник задан координатами своих вершин. Найти периметр треугольника.
### Решение
Выделил следующие смысловые блоки:
- Работа с координатами (`coord.h`)
- `vector_lenght` - вычисляет длину вектора (отрезка) по двум точкам
- `count_perimeter` - вычисляет переметр треугольника по трём сторонам
- Модуль ввода/вывода (`io_module.h`)
- `input_point` - ввод координат точки
- `output_perimeter` - вывод значения периметра
Использовал следующие математические формулы:
- $`\sqrt{(x_1-x_2)^2 + (y_1-y_2)^2}`$ для вычисления длины вектора по двум точкам
- $`a+b+c`$ для вычисления периметра треугольника по трём сторонам
## Задача 3.
### Условие.
Три сопротивления R1, R2, R3 соединены параллельно. Найти сопротивление соединения.
### Решение.
Выделил следующие смысловые блоки:
- Работа с координатами (`resistence.h`)
- `parallel_resistance` - подсчёт сопротивления для 3-х соеденённых резистров
- Модуль ввода/вывода (`io_module.h`)
- `input_resistence` - ввод сопротивления
- `output_resistence` - вывод сопротивления
Использовал следующие математические преобразования:
$`{1 \over R} = {1 \over R_1} + {1 \over R_2} + {1 \over R_3}`$ | для трёх резистров, соеденных параллельно
$`{1 \over R} = {R_1 R_2 + R_2 R_3 + R_1 R_3 \over R_1 R_2 R_3}`$ | Привёл к общему знаменателю
$`{R} = {R_1 R_2 R_3 \over R_1 R_2 + R_2 R_3 + R_1 R_3 }`$ | Выразил нужное нам значение
Важное замечание, если сопротивление любого резистра стремится к нулю, то и общее сопротивление стремится к нулю
## Задача 4.
### Условие.
Задано время в секундах. Перевести в часы, минуты, секунды.
### Решение.
Выделил следующий смысловой блок:
- работа со временем (`time_module.h`)
- `input_seconds` - ввод времени в секундах
- `output_formated_time` - вывод преобразованного формата (Ч:М:С)
- `convert_time` - преобразование секундного представления в формат (Ч:М:С)
Использовал целочисленное деление и остаток от деления при преобразование согласно следующим зависимостям:
- 1 минута = 60 секунд
- 1 час = 60 минут = 3600 секунд
## Задача 5.
### Условие.
Функцию `printf("%d", i)` можно вызывать лишь при `i` = 0, 1, 2, ..., 9. Составить программу, печатающую десятичную запись заданного
натурального числа n > 0.
### Решение.
Выделил следующий смысловой блок:
- работа с числами (`numeric.h`)
- `input_number` - ввод числа и проверка на корректность ввода
- `print_number` - вывод числа
- `get_digits_of_number` - подсчёт количества разрядов числа
Вывожу число по-разрадно от большего к меньшему разряду с помощью операций целочисленного деления на $`10^{n - 1}`$ (где $`n`$ - номер выводимого разряд) и операции остатка от деления на $`10`$.
### Возникшие проблемы
Неправильный вывод при работе с большими числами. Проблема заключалась в том, что возведение в степень в библиотеке `math` выполняется с погрешностью ($`e^{n * \ln10}`$), что привело к неправильному вычислению $`10^n`$, где $`n`$ - количество разрядов числа. Происходило целочисленное округление до $`10^n - 1`$, что нарушает работу алгоритма. Исправил, возводя в степень с помощью циклического умножения на число, то есть $`\prod_{i=1}^{n}10`$
### Тестирование
Написал тесты. Для простоты тестирования написал программу которая парсит мой файл с тестами tests.txt и тестирует программу.
**Ссылка на репозиторий**: https://git.iu7.bmstu.ru/lvn19u232/auto_test
```
$ ./auto_test ../lab_01_5_5/test.out ../lab_01_5_5/tests.txt
TEST № 1 CORRECT
TEST № 2 CORRECT
TEST № 3 CORRECT
TEST № 4 CORRECT
TEST № 5 CORRECT
TEST № 6 CORRECT
6/6 doned
```
Проверил покрытие для каждого файла.
```
$ gcov main.c
File 'main.c'
Lines executed:100.00% of 7
Creating 'main.c.gcov'
$ gcov numeric.c
File 'numeric.c'
Lines executed:100.00% of 26
Creating 'numeric.c.gcov'
```
## Задача 6.
### Условие.
Определить пересекаются ли два отрезка.
### Решение.
Обратился к статье [Вычислительная геометрия, или как я стал заниматься олимпиадным программированием. Часть 2](https://habr.com/ru/post/148325/). Где нашёл объяснение математического решения моей задачи.
>>>
**Задача №6**
Определить пересекаются ли два отрезка.
**Решение**
Вот эта задача мне, действительно, нравится. Отрезки пересекаются тогда, когда, концы каждого отрезка лежат по разные стороны от другого отрезка. Посмотрим на рисунок:

Итак, нам нужно проверить, чтобы концы каждого из отрезков лежали по разные стороны относительного концов другого отрезка. Пользуемся косым произведением векторов. Посмотрите на первый рисунок: $`[P_1P_2, P_1M_2] > 0`$, $`[P_1P_2, P_1M_1] < 0`$ => $`[P_1P_2, P_1M_2] * [P_1P_2, P1M1] < 0 `$. Аналогично
$`[M_1M_2, M_1P_1] * [M_1M_2, M_1P_2] < 0 `$. Вы наверно думаете, почему не меньше либо равно. А потому, что возможен следующий случай, при котором векторное произведение как раз и равно нулю, но отрезки не пересекаются:

Поэтому нам необходимо сделать еще одну проверку, а именно: принадлежит ли хотя бы один конец каждого отрезка другому (принадлежность точки отрезку). Эту задачу мы уже решали.
Итак, для того чтобы отрезки имели общие точки необходимо и достаточно:
1. Концы отрезков лежат по разные стороны относительно другого отрезка.
2. Хотя бы один из концов одного отрезка принадлежит другому отрезку.
>>>
Ознакомившись со статьёй, разбил решение на следующие смысловые блоки:
- модуль ввода/вывода (`io_module.h`)
- `input_point` - ввод координат точки
- `input_segment` - ввод отрезка по двум точкам
- `output_intersect` - вывод результат пересечения
- модуль работы с векторами (`vectors.h`)
- `points_is_equal` - проверка точек на совпадение
- `create_segment` - создание отрезка по двум точкам
- `segment_to_vector` - преобразования отрезка в вектор
- `create_vector` - создание вектора по двум точкам
- `scalar_product` - функция скалярного произведения векторов
- `vector_product` - функция векторного произведения (здесь косового, так как используется вычисления на плоскости $`xy`$)
- `is_belongs_to_segment` - проверка на принадлежность точки отрезку
- `is_segments_intersect` - проверка на пересечение двух отрезков
Возникли проблемы с проблемы с прохождением тестов. Опишу их:
- Если хотя бы один из концов одного отрезка принадлежит другому отрезку, то отрезки не пересекаются, но имеют общие точки.
Исправил, убрав проверку на принадлежность концов одного отрезку другому.
- Отрезок нулевой длины, не является отрезком.
Исправил, добавив проверку точек на совпадение (функция `points_is_equal`).
### Тестирование
Написал тесты и произвёл тестирование.
```
$ ./auto_test ../lab_01_5_6/test.out ../lab_01_5_6/tests.txt
TEST № 1 CORRECT
TEST № 2 CORRECT
TEST № 3 CORRECT
TEST № 4 CORRECT
TEST № 5 CORRECT
TEST № 6 CORRECT
TEST № 7 CORRECT
TEST № 8 CORRECT
8/8 doned
```
Проверил покрытие тестами.
```
$ gcov main.c
File 'main.c'
Lines executed:70.59% of 17
Creating 'main.c.gcov'
$ gcov vectors.c
File 'vectors.c'
Lines executed:55.17% of 29
Creating 'vectors.c.gcov'
$ gcov io_module.c
File 'io_module.c'
Lines executed:91.30% of 23
Creating 'io_module.c.gcov'
```
Не удалось достичь 100% покрытия. Разбираем участки кода, не покрытые тестами.
`main.c`
```
-: 0:Source:main.c
-: 0:Graph:main.gcno
-: 0:Data:main.gcda
-: 0:Runs:25
-: 0:Programs:1
-: 1:/*
-: 2:Определить пересекаются ли два отрезка.
-: 3:Ввод:
-: 4:x1 y1 x2 y2 x3 y3 x4 y4
-: 5:Вывод:
-: 6:0 (не пересекаются)
-: 7:1 (пересекаются)
-: 8:*/
-: 9:#include <stdio.h>
-: 10:#include "io_module.h"
-: 11:#include "vectors.h"
-: 12:
-: 13:
25: 14:int main()
-: 15:{
-: 16: segment_t first_segment;
-: 17: segment_t second_segment;
-: 18:
25: 19: int err = input_segment(&first_segment);
25: 20: if (!err)
10: 21: err = input_segment(&second_segment);
-: 22:
25: 23: switch (err)
-: 24: {
10: 25: case INPUT_SUCCESS:
10: 26: output_intersect(is_segments_intersect(first_segment, second_segment));
10: 27: break;
15: 28: case INPUT_ERROR:
15: 29: printf("Input error \n");
15: 30: break;
#####: 31: case POINTER_ERROR:
#####: 32: printf("Pointer error \n");
#####: 33: break;
#####: 34: default:
#####: 35: printf("Undefined error \n");
-: 36: }
-: 37:
25: 38: return err;
-: 39:}
```
Не достигается вывод ошибки о нулевом указателе и неизвестной ошибке. Данных ошибок не возможно достичь в рамках правильно работающей программы.
`io_module.c`
```
-: 0:Source:io_module.c
-: 0:Graph:io_module.gcno
-: 0:Data:io_module.gcda
-: 0:Runs:25
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:#include "io_module.h"
-: 3:
67: 4:int input_point(point_t *point)
-: 5:{
67: 6: if (!point)
#####: 7: return POINTER_ERROR;
-: 8:
67: 9: int err = INPUT_SUCCESS;
-: 10:
67: 11: printf("Input x and y of the point: ");
-: 12:
67: 13: if (scanf("%lf %lf", &point->x, &point->y) != 2)
6: 14: err = INPUT_ERROR;
-: 15:
67: 16: return err;
-: 17:}
-: 18:
35: 19:int input_segment(segment_t *segment)
-: 20:{
35: 21: if (!segment)
#####: 22: return POINTER_ERROR;
-: 23:
35: 24: printf("Inputing segment \n");
-: 25:
35: 26: int err = input_point(&segment->begin);
35: 27: if (err == INPUT_SUCCESS)
32: 28: err = input_point(&segment->end);
35: 29: if (err == INPUT_SUCCESS && points_is_equal(segment->begin, segment->end))
9: 30: err = INPUT_ERROR;
-: 31:
35: 32: return err;
-: 33:}
-: 34:
10: 35:void output_intersect(int is_intersect)
-: 36:{
10: 37: if (is_intersect)
3: 38: printf("Intersects 1 \n");
-: 39: else
7: 40: printf("doesn't intersect 0 \n");
10: 41:}
```
Не достигается возврат ошибки нулевого указателя.
`vectors.c`
```
-: 0:Source:vectors.c
-: 0:Graph:vectors.gcno
-: 0:Data:vectors.gcda
-: 0:Runs:25
-: 0:Programs:1
-: 1:#include "vectors.h"
-: 2:
29: 3:int points_is_equal(point_t first_point, point_t second_point)
-: 4:{
29: 5: return first_point.x == second_point.x && first_point.y == second_point.y;
-: 6:}
-: 7:
#####: 8:segment_t create_segment(point_t begin_point, point_t end_point)
-: 9:{
-: 10: segment_t segment;
-: 11:
#####: 12: segment.begin = begin_point;
#####: 13: segment.end = end_point;
-: 14:
#####: 15: return segment;
-: 16:}
-: 17:
30: 18:vector_t create_vector(point_t begin_point, point_t end_point)
-: 19:{
-: 20: vector_t vector;
-: 21:
30: 22: vector.x = end_point.x - begin_point.x;
30: 23: vector.y = end_point.y - begin_point.y;
-: 24:
30: 25: return vector;
-: 26:}
-: 27:
10: 28:vector_t segment_to_vector(segment_t segment)
-: 29:{
10: 30: return create_vector(segment.begin, segment.end);
-: 31:}
-: 32:
20: 33:double vector_product(vector_t vector1, vector_t vector2)
-: 34:{
20: 35: return vector1.x * vector2.y - vector1.y * vector2.x;
-: 36:}
-: 37:
#####: 38:double scalar_product(vector_t vector1, vector_t vector2)
-: 39:{
#####: 40: return vector1.x * vector2.x + vector1.y * vector2.y;
-: 41:}
-: 42:
#####: 43:int is_belongs_to_segment(point_t point, segment_t segment)
-: 44:{
#####: 45: vector_t vector_s1_s2 = segment_to_vector(segment);
#####: 46: vector_t vector_s1_p = create_vector(segment.begin, point);
-: 47:
#####: 48: vector_t vector_p_s1 = create_vector(point, segment.begin);
#####: 49: vector_t vector_p_s2 = create_vector(point, segment.end);
-: 50:
-: 51: return
#####: 52: vector_product(vector_s1_s2, vector_s1_p) == 0 &&
#####: 53: scalar_product(vector_p_s1, vector_p_s2) <= 0;
-: 54:}
-: 55:
10: 56:int is_segments_intersect(segment_t first_segment, segment_t second_segment)
-: 57:{
10: 58: vector_t vector_f1_f2 = segment_to_vector(first_segment);
-: 59:
10: 60: vector_t vector_f1_s2 = create_vector(first_segment.begin, second_segment.end);
10: 61: vector_t vector_f1_s1 = create_vector(first_segment.begin, second_segment.begin);
-: 62:
-: 63: return
20: 64: vector_product(vector_f1_f2, vector_f1_s2) *
20: 65: vector_product(vector_f1_f2, vector_f1_s1) < 0 /*||
-: 66: is_belongs_to_segment(first_segment.begin, second_segment) ||
-: 67: is_belongs_to_segment(first_segment.end, second_segment)*/;
-: 68:}
-: 69:
-: 70:
```
Здесь тестами выявлены неиспользуемые функции:
- `create_segment` - создание отрезка по двум точками
- `scalar_product` скалярное произведение векторов
- `is_belongs_to_segment` принадлежность точки отрезку
Данные функции стали неиспользуемыми по мере разработки программы. Принял решение оставить данные функции, так как они имеют своё логическое наличие в рамкох модуля работы с векторами.
## Задача 7.
### Условие задачи.
Вычислить с точность eps:
− приближенное значение функции s(x);
− точное значение функции f(x);
− абсолютную $`\mid{f(x) - s(x)}\mid`$ и относительную $`\mid{{f(x) - s(x)}\over f(x)}\mid`$ ошибки приближенного значения.
$`f(x) = {1 \over sqrt(1-x^2)}`$
$`s(x) = 1 + {1*x^2 \over 2} + {1*3*x^4 \over 2*4} + {1*3*5*x^6 \over 2*4*6} + ... `$
### Вывод рекурентной формулы:
$`s_n(x) = {(2n - 1)! * x^{2n} \over (2n)!}`$
$` s_0(x) = 1 `$
$`s_n(x) = {s_{n-1}(x) * (2n - 1) * x^2 \over 2n}`$
### Решение
Разбил решение на следующие смысловые блоки:
- модуль работы с вводом/выводом (`io_module.h`)
- `input_value` - ввод значения ($`x`$)
- `input_eps` - ввод точности ($`eps`$)
- `output_absolute_value` - вывод абсолютного значения функции
- `output_relative_value` - вывод приблизительного значения функции
- `output_absolute_difference` - вывод абсолютной погрешности
- `output_relative_difference` - вывод относительной погрешности
- модуль работы с рядами (`untils.h`)
- `f` - функция f по условию
- `s` - функция члена s, представленная в рекурентном виде
- `find_with_precision` - функция поиска суммы ряда с точность eps
- `get_absolute_difference` - подсчёт абсолютной погрешности
- `get_relative_difference` - подсчёт относительной погрешности
### Тестирование
Написал тесты и произвёл тестирование программы.
```
./auto_test ../lab_01_5_7/test.out ../lab_01_5_7/tests.txt
TEST № 1 CORRECT
TEST № 2 CORRECT
TEST № 3 CORRECT
TEST № 4 CORRECT
4/4 doned
```
Проверяю покрытие тестами.
```
$ gcov main.c
File 'main.c'
Lines executed:100.00% of 18
Creating 'main.c.gcov
$ gcov untils.c
File 'untils.c'
Lines executed:100.00% of 22
Creating 'untils.c.gcov'
$ gcov io_module.c
File 'io_module.c'
Lines executed:92.86% of 28
Creating 'io_module.c.gcov'
```
Не удалось достичь 100% покрытия. Разбираем участки кода, не покрытые тестами.
`io_module.c`
```
-: 0:Source:io_module.c
-: 0:Graph:io_module.gcno
-: 0:Data:io_module.gcda
-: 0:Runs:4
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:#include "io_module.h"
-: 3:
4: 4:int input_value(double *value)
-: 5:{
4: 6: int err = INPUT_SUCCESS;
4: 7: if (!value)
-: 8: {
#####: 9: err = POINTER_ERROR;
-: 10: }
-: 11: else
-: 12: {
4: 13: printf("Input value of parameter (x): ");
-: 14:
4: 15: if (scanf("%lf", value) != 1 || *value >= 1 || *value <= -1)
1: 16: err = INPUT_ERROR;
-: 17: }
4: 18: return err;
-: 19:}
-: 20:
3: 21:int input_eps(double *eps)
-: 22:{
3: 23: int err = INPUT_SUCCESS;
3: 24: if (!eps)
-: 25: {
#####: 26: err = POINTER_ERROR;
-: 27: }
-: 28: else
-: 29: {
3: 30: printf("Input precision: ");
-: 31:
3: 32: if (scanf("%lf", eps) != 1 || *eps <= 0 || *eps >= 1)
2: 33: err = INPUT_ERROR;
-: 34: }
3: 35: return err;
-: 36:}
-: 37:
-: 38:
1: 39:void output_absolute_value(double value)
-: 40:{
1: 41: printf("Absolute value is %lf \n", value);
1: 42:}
-: 43:
1: 44:void output_relative_value(double value)
-: 45:{
1: 46: printf("Relative value is %lf \n", value);
1: 47:}
-: 48:
1: 49:void output_absolute_difference(double difference)
-: 50:{
1: 51: printf("Absolute difference is %lf \n", difference);
1: 52:}
-: 53:
1: 54:void output_relative_difference(double difference)
-: 55:{
1: 56: printf("Relative difference is %lf \n", difference);
1: 57:}
-: 58:
```
Не покрыты тестами участки кода, возвращающие ошибку нулевого указателя.