Try   HackMD

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 - вывод значения периметра

Использовал следующие математические формулы:

  • (x1x2)2+(y1y2)2
    для вычисления длины вектора по двум точкам
  • a+b+c
    для вычисления периметра треугольника по трём сторонам

Задача 3.

Условие.

Три сопротивления R1, R2, R3 соединены параллельно. Найти сопротивление соединения.

Решение.

Выделил следующие смысловые блоки:

  • Работа с координатами (resistence.h)
    • parallel_resistance - подсчёт сопротивления для 3-х соеденённых резистров
  • Модуль ввода/вывода (io_module.h)
    • input_resistence - ввод сопротивления
    • output_resistence - вывод сопротивления

Использовал следующие математические преобразования:

1R=1R1+1R2+1R3 | для трёх резистров, соеденных параллельно

1R=R1R2+R2R3+R1R3R1R2R3 | Привёл к общему знаменателю

R=R1R2R3R1R2+R2R3+R1R3 | Выразил нужное нам значение

Важное замечание, если сопротивление любого резистра стремится к нулю, то и общее сопротивление стремится к нулю

Задача 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 - подсчёт количества разрядов числа

Вывожу число по-разрадно от большего к меньшему разряду с помощью операций целочисленного деления на

10n1 (где
n
- номер выводимого разряд) и операции остатка от деления на
10
.

Возникшие проблемы

Неправильный вывод при работе с большими числами. Проблема заключалась в том, что возведение в степень в библиотеке math выполняется с погрешностью (

enln10), что привело к неправильному вычислению
10n
, где
n
- количество разрядов числа. Происходило целочисленное округление до
10n1
, что нарушает работу алгоритма. Исправил, возводя в степень с помощью циклического умножения на число, то есть
i=1n10

Тестирование

Написал тесты. Для простоты тестирования написал программу которая парсит мой файл с тестами 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. Где нашёл объяснение математического решения моей задачи.

Задача №6

Определить пересекаются ли два отрезка.

Решение

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

Рисунок 1.

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

[P1P2,P1M2]>0,
[P1P2,P1M1]<0
=>
[P1P2,P1M2][P1P2,P1M1]<0
. Аналогично
[M1M2,M1P1][M1M2,M1P2]<0
. Вы наверно думаете, почему не меньше либо равно. А потому, что возможен следующий случай, при котором векторное произведение как раз и равно нулю, но отрезки не пересекаются:

Рисунок 2.

Поэтому нам необходимо сделать еще одну проверку, а именно: принадлежит ли хотя бы один конец каждого отрезка другому (принадлежность точки отрезку). Эту задачу мы уже решали.

Итак, для того чтобы отрезки имели общие точки необходимо и достаточно:

  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);
− абсолютную

f(x)s(x) и относительную
f(x)s(x)f(x)
ошибки приближенного значения.

f(x)=1sqrt(1x2)

s(x)=1+1x22+13x424+135x6246+...

Вывод рекурентной формулы:

sn(x)=(2n1)!x2n(2n)!

s0(x)=1

sn(x)=sn1(x)(2n1)x22n

Решение

Разбил решение на следующие смысловые блоки:

  • модуль работы с вводом/выводом (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:

Не покрыты тестами участки кода, возвращающие ошибку нулевого указателя.