# 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** Определить пересекаются ли два отрезка. **Решение** Вот эта задача мне, действительно, нравится. Отрезки пересекаются тогда, когда, концы каждого отрезка лежат по разные стороны от другого отрезка. Посмотрим на рисунок: ![Рисунок 1.](https://hsto.org/storage2/a03/5b4/ffa/a035b4ffa74057e35428196b55a4154b.png) Итак, нам нужно проверить, чтобы концы каждого из отрезков лежали по разные стороны относительного концов другого отрезка. Пользуемся косым произведением векторов. Посмотрите на первый рисунок: $`[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 `$. Вы наверно думаете, почему не меньше либо равно. А потому, что возможен следующий случай, при котором векторное произведение как раз и равно нулю, но отрезки не пересекаются: ![Рисунок 2.](https://hsto.org/storage2/b7d/062/6c5/b7d0626c5fbfad31dc46d162ad596a56.png) Поэтому нам необходимо сделать еще одну проверку, а именно: принадлежит ли хотя бы один конец каждого отрезка другому (принадлежность точки отрезку). Эту задачу мы уже решали. Итак, для того чтобы отрезки имели общие точки необходимо и достаточно: 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: ``` Не покрыты тестами участки кода, возвращающие ошибку нулевого указателя.