#set text(size: 1.3em)

#show raw.where(block: false): box.with(
  fill: luma(240),
  inset: (x: 3pt, y: 0pt),
  outset: (y: 3pt),
  radius: 2pt,
)

#show raw.where(block: true): block.with(
  fill: luma(240),
  inset: 10pt,
  radius: 4pt,
)
    
// title
    
#align(center)[Санкт-Петербургский национальный исследовательский университет информационных технологий, механики и оптики]
\
\
\
#align(center)[Факультет инфокоммуникационных технологий]
#align(center)[Направление подготовки 11.03.02]
\
\
#align(center)[Лабораторная работа №3]
#align(center)[Использование выражений]
\
\
\ //#align(center)[Вариант 19]
\
\
\
\
\
\
\
#align(right)[Выполнил:]
#align(right)[Дощенников Никита Андреевич]
#align(right)[Группа: К3221]
#align(right)[Проверил:]
#align(right)[Иванов Сергей Евгеньевич]
\
\
#align(center)[Санкт-Петербург]
#align(center)[2025]

#pagebreak()
    
=== Цель работы: 

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

=== Упражнение 1. Реализация операторов выбора.

==== Задание 1. Применение конструкции if-else-if.

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

#align(center)[#image("assets/1.png")]

```cs 
using System;

public class Program
{
    static void Main(string[] args)
    {
        Console.Write("x = ");
        float x = float.Parse(Console.ReadLine());

        Console.Write("y = ");
        float y = float.Parse(Console.ReadLine());

        if (x * x + y * y < 9 && y > 0)
        {
            Console.WriteLine("внутри");
        } 
        else if (x * x + y * y > 9 || y < 0) 
        {
            Console.WriteLine("вне");
        }
        else
        {
            Console.WriteLine("на границе");
        }

    }
}
```

Пример работы: 

#align(center)[#image("assets/2.png")]
#align(center)[#image("assets/3.png")]
#align(center)[#image("assets/4.png")]

==== Задание 2. Применение оператора switch.

Я создал программу моделирующую работу калькулятора. Пользователем вводится первый операнд, требуемую операцию и второй операнд. Затем производится расчет результата.

```cs
using System;

public class Program
{
    static void Main(string[] args)
    {
        Console.Write("A = ");
        double a = double.Parse(Console.ReadLine());
        Console.Write("OP = ");
        char op = char.Parse(Console.ReadLine());
        Console.Write("B = ");
        double b = double.Parse(Console.ReadLine());


        bool ok = true;
        double res = 0;

        switch (op) 
        {
            case '+': res = a + b; break;
            case '-': res = a - b; break;
            case '*': res = a * b; break;
            case '/':
            case ':':
                      res = a / b; break;
            default: ok = false; break;
        }

        if (ok)
        {
            Console.WriteLine("{0} {1} {2} = {3}", a, op, b, res);
        }
        else
        {
            Console.WriteLine("Операция не определена");
        }
    }
}
```

Пример работы: 

1) c правильными значениями: 

#align(center)[#image("assets/5.png")]

2) при делении на нуль: 

#align(center)[#image("assets/6.png")]

Бесконечность, так как в стандарте IEEE-754 прописан такой результат.

3) при делении нуль на нуль:

#align(center)[#image("assets/7.png")]

NaN, опять же в соответствии со стандартом.

4) при неправильной операции: 

#align(center)[#image("assets/8.png")]

Мы проваливаемся к значению по умолчанию.

==== Задание 3. Определение високосного года. 

Программа, по введенному натуральному числу, определяет, является ли год с номером, равным этому числу, високосным.

```cs
using System;

public class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("input a year: ");
        int year = int.Parse(Console.ReadLine());

        if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
        {
            Console.WriteLine("YES");
        }
        else
        {
            Console.WriteLine("NO");
        }
    }
}
```

Пример работы: 

#align(center)[#image("assets/9.png")]
#align(center)[#image("assets/10.png")]

=== Упражнение 2. Реализация циклов при работе с данными размерных типов.

==== Задание 1. Использование операторов цикла while, do while и for. 

Я написал программу, которая выводит на экран последовательность целых нечетных чисел в строчку через пробел с помощью трех операторов цикла `while`, `do while` и `for`.

```cs 
using System;

public class Program
{
    public static void Main(string[] args)
    {
        Console.Write("n = ");
        int n = int.Parse(Console.ReadLine());

        // while
        Console.Write("\nwhile: \t\t");
        int i = 1;
        while (i <= n)
        {
            Console.Write(" " + i);
            i += 2;
        }

        // do-while
        Console.Write("\ndo while: \t");
        i = 1;
        do
        {
            Console.Write(" " + i);
            i += 2;
        }
        while (i <= n);

        // for:
        Console.Write("\nfor: \t\t");
        for (i = 1; i<=n; i+=2)
        {
            Console.Write(" " + i);
        }
    }
}
```

Пример работы: 

#align(center)[#image("assets/11.png")]

Была написана программа, которая печатает таблицу синусов и их аргументов с периодом 0.01 от `x1` до `x2`.

```cs 
using System;

public class Program
{
    static void Main(string[] args)
    {
        double x, x1, x2, y;

        Console.WriteLine("input x1:");
        x1 = double.Parse(Console.ReadLine());
        Console.WriteLine("input x2:");
        x2 = double.Parse(Console.ReadLine());

        Console.WriteLine("x\t\t sin(x)");
        Console.WriteLine("--------------------------");

        x = x1;
        do
        {
            y = Math.Sin(x);
            Console.WriteLine($"{x:F2}\t {y:F6}");
            x = x + 0.01;
        }
        while (x <= x2);
    }
}
```

Пример работы: 

#align(center)[#image("assets/12.png")]

```cs
using System;
using System.Globalization;

class Program
{
    static void FuncWhile()
    {
        var ci = CultureInfo.InvariantCulture;
        double x1 = double.Parse(Console.ReadLine(), ci);
        double x2 = double.Parse(Console.ReadLine(), ci);
        double h = double.Parse(Console.ReadLine(), ci);
        double x = x1;
        while (x <= x2 + 1e-12)
        {
            double y = Math.Sin(x);
            Console.WriteLine($"while: {x.ToString(ci)} {y.ToString(ci)}");
            x += h;
        }
    }

    static void FuncDoWhile()
    {
        var ci = CultureInfo.InvariantCulture;
        double x1 = double.Parse(Console.ReadLine(), ci);
        double x2 = double.Parse(Console.ReadLine(), ci);
        double h = double.Parse(Console.ReadLine(), ci);
        double x = x1;
        if (h <= 0) return;
        do
        {
            double y = Math.Sin(x);
            Console.WriteLine($"do-while: {x.ToString(ci)} {y.ToString(ci)}");
            x += h;
        } while (x - h < x2 + 1e-12);
    }

    static int GcdWhile(int a, int b)
    {
        a = Math.Abs(a);
        b = Math.Abs(b);
        while (b != 0)
        {
            int temp = a % b;
            a = b;
            b = temp;
        }
        return a;
    }

    static int GcdDoWhile(int a, int b)
    {
        a = Math.Abs(a);
        b = Math.Abs(b);
        int temp;
        if (b == 0) return a;
        do
        {
            temp = a % b;
            a = b;
            b = temp;
        } while (b != 0);
        return a;
    }

    static void Main()
    {
        Console.WriteLine("=== Функция с while ===");
        FuncWhile();

        Console.WriteLine("=== Функция с do-while ===");
        FuncDoWhile();

        Console.WriteLine("Введите два числа для НОД (while):");
        int a = int.Parse(Console.ReadLine());
        int b = int.Parse(Console.ReadLine());
        Console.WriteLine($"НОД (while): {GcdWhile(a, b)}");

        Console.WriteLine("Введите два числа для НОД (do-while):");
        a = int.Parse(Console.ReadLine());
        b = int.Parse(Console.ReadLine());
        Console.WriteLine($"НОД (do-while): {GcdDoWhile(a, b)}");
    }
}
```

- *while* подходит, когда важно проверять условие до входа в цикл (может выполниться 0 раз).

- *do…while* удобен, когда тело должно выполниться минимум один раз.

- Для функций на интервале *do…while* проще гарантирует вывод крайней точки.

- Для алгоритма Евклида оба варианта дают одинаковый результат; *while* короче, *do…while* более наглядно выражает шаг алгоритма.

==== Задание 2. Расчет суммы, используя операторы перехода.

Составлена программа, которая реализует сумму

$
s = sum_(i = 1)^(100) i, 
$

для $i$, находящихся от $1$ до $k$ и от $m$ до $100$.

```cs 
using System;

class Program
{
    static void Main()
    {
        Console.Write("Введите k: ");
        int k = int.Parse(Console.ReadLine());
        Console.Write("Введите m: ");
        int m = int.Parse(Console.ReadLine());

        int s = 0;
        for (int i = 1; i <= 100; i++)
        {
            if (i > k && i < m) continue;
            s += i;
        }

        Console.WriteLine("Сумма = " + s);
    }
}
```

Пример работы:

#align(center)[#image("assets/13.png")]

==== Задание 3. Стрельба по мишени.

Разработа программа, имитирующая стрельбу по мишени.

```cs
using System;

class Program
{
    static int VariantFromStudentNumber(int n) => (n % 2 != 0) ? 1 : 2;

    static int ScoreVariant1(double x, double y)
    {
        var r = Math.Sqrt(x * x + y * y);
        if (r <= 1) return 10;
        if (r <= 2) return 5;
        if (r <= 3) return 2;
        return 0;
    }

    static int Sector(double x, double y)
    {
        var a = Math.Atan2(y, x);
        if (a > Math.PI / 4 && a <= 3 * Math.PI / 4) return 1;
        if (a > -Math.PI / 4 && a <= Math.PI / 4) return 5;
        if (a > -3 * Math.PI / 4 && a <= -Math.PI / 4) return 2;
        return 3;
    }

    static int ScoreVariant2(double x, double y)
    {
        var r = Math.Sqrt(x * x + y * y);
        if (r <= 1) return 10;
        if (r <= 3) return Sector(x, y);
        return 0;
    }

    static void Main()
    {
        Console.Write("Номер по списку: ");
        int student = int.Parse(Console.ReadLine());
        int variant = VariantFromStudentNumber(student);

        Console.Write("Сколько выстрелов: ");
        int n = int.Parse(Console.ReadLine());

        Console.Write("Случайный центр? (y/n): ");
        bool rndCenter = Console.ReadLine().Trim().ToLower() == "y";

        Console.Write("Случайная помеха? (y/n): ");
        bool noise = Console.ReadLine().Trim().ToLower() == "y";

        var rnd = new Random();
        double cx = 0, cy = 0;
        if (rndCenter)
        {
            cx = rnd.NextDouble() * 2 - 1;
            cy = rnd.NextDouble() * 2 - 1;
        }

        int sum = 0;
        for (int i = 0; i < n; i++)
        {
            Console.Write($"Выстрел {i + 1} (x y): ");
            var parts = Console.ReadLine().Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
            double x = double.Parse(parts[0]);
            double y = double.Parse(parts[1]);

            if (noise)
            {
                x += (rnd.NextDouble() * 0.2 - 0.1);
                y += (rnd.NextDouble() * 0.2 - 0.1);
            }

            x -= cx;
            y -= cy;

            int s = variant == 1 ? ScoreVariant1(x, y) : ScoreVariant2(x, y);
            sum += s;
            Console.WriteLine($"Очки: {s}, сумма: {sum}");
        }

        Console.WriteLine($"Итоговая сумма: {sum}");
    }
}
```

Пример работы: 

#align(center)[#image("assets/14.png")]

=== Code review. (by #link("https://zzzcode.ai")[zzzcode.ai])

*Резюме*

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

*Ошибка*

В коде отсутствует обработка исключений при парсинге пользовательского ввода. Это может привести к сбоям программы, если пользователь введет некорректные данные. Рекомендуется использовать TryParse для безопасного парсинга.

*Стиль кода*

Стиль кода в целом соответствует стандартам C\#. Однако, в некоторых местах можно улучшить читаемость, добавив комментарии и более описательные имена переменных. Например, вместо `x1`, `x2` можно использовать `startX`, `endX`.

*Структура кода*

Код разбит на несколько классов, что хорошо для организации. Однако, каждый класс содержит метод `Main`, что не является хорошей практикой. Рекомендуется создать один класс с единственным методом `Main`, а остальные функции вынести в отдельные методы.

`Читаемость`

Читаемость кода можно улучшить, добавив комментарии, объясняющие логику выполнения. Также стоит использовать более понятные имена переменных и методов, чтобы другие разработчики могли быстрее понять, что делает код.

`Производительность`

Код выполняется достаточно быстро для небольших входных данных. Однако, в случае больших объемов данных, стоит рассмотреть возможность оптимизации, например, путем использования более эффективных алгоритмов.
Масштабируемость

Код не очень масштабируем, так как он жестко привязан к конкретным задачам. Рекомендуется использовать более модульный подход, чтобы можно было легко добавлять новые функции без изменения существующего кода.

`Безопасность`

Безопасность кода можно улучшить, добавив обработку исключений и проверку входных данных. Это поможет избежать потенциальных уязвимостей, связанных с некорректным вводом.

`Обработка ошибок`

Обработка ошибок в коде отсутствует. Рекомендуется использовать конструкции `try-catch` для обработки возможных исключений, особенно при работе с пользовательским вводом и парсингом данных.

*Заключение*

В целом, код выполняет свои функции, но требует улучшений в области обработки ошибок, читаемости и структуры. Рекомендуется внести изменения, чтобы сделать код более безопасным, масштабируемым и удобным для чтения.

=== Выводы. 

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

