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