#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` для обработки возможных исключений, особенно при работе с пользовательским вводом и парсингом данных. *Заключение* В целом, код выполняет свои функции, но требует улучшений в области обработки ошибок, читаемости и структуры. Рекомендуется внести изменения, чтобы сделать код более безопасным, масштабируемым и удобным для чтения. === Выводы. В ходе проделанной работы, я изучил и приобрел навыки использования управляющих конструкций для организации вычислений.