Практика 2.1. Классы Math и Random


Математические функции, случайные числа и разобранные задачи

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

2.1.1. Площадь и диагональ прямоугольника

Напишите программу, которая получает два положительных целых числа — длину и ширину прямоугольника — и выводит:

  • площадь прямоугольника;
  • длину диагонали, вычисленную по теореме Пифагора.

Считайте ввод корректным. Выберите понятные имена переменных. Проверьте программу на нескольких примерах, в том числе на прямоугольнике со сторонами 3 и 4: площадь должна быть 12, диагональ — 5.

На будущее: вариант с методом
  1. Напишите метод static void RectangleAnalysis(int width, int height), который получает размеры прямоугольника и выводит его площадь и диагональ. Метод не возвращает значение.
  2. В Main получите случайные положительные размеры с помощью Random и передайте их методу из первого пункта.

2.1.2. Разница в росте и меньший рост

Напишите программу, которая получает рост двух учеников как вещественные числа и выводит:

  • модуль разности их роста;
  • меньший из двух ростов.

Используйте методы класса Math: для модуля — Math.Abs, для меньшего значения — Math.Min. Подпишите сообщения ввода и вывода и используйте одинаковые единицы измерения для обоих значений.

На будущее: вариант с методами
  1. Напишите метод, который получает два значения роста и возвращает модуль их разности.
  2. Напишите второй метод с такими же параметрами, который возвращает меньший рост.
  3. Покажите Main, вызывающий оба метода и выводящий результаты.

2.1.3. Случайные числа, квадратные корни и округление

Получите три случайных целых числа от 20 до 40 включительно. Выведите:

  • все три числа;
  • наибольшее из них;
  • квадратный корень каждого числа, округлённый до целого;
  • сообщение, если хотя бы у двух чисел округлённые корни совпали.

Используйте Random и методы Math.

Последний пункт использует условия. Если вы ещё не изучали if, выполните первые три пункта сейчас и вернитесь к сравнению после главы 3.

Решение с методом и двумя вариантами проверки

Поле rnd и оба метода разместите внутри класса Program. Две проверки совпадений показывают альтернативные способы решения: в своей программе выберите один, чтобы не выводить сообщение дважды.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public static Random rnd = new Random();

/// <summary>
/// Случайный выбор, максимум, округление корней и сравнение.
/// </summary>
public static void Q213()
{
    int num1 = rnd.Next(20, 41);
    int num2 = rnd.Next(20, 41);
    int num3 = rnd.Next(20, 41);
    Console.WriteLine($"Числа: {num1}, {num2}, {num3}");

    int max = Math.Max(num1, num2);
    max = Math.Max(max, num3);
    // Тот же результат одной инструкцией:
    max = Math.Max(num3, Math.Max(num1, num2));
    Console.WriteLine($"Максимум: {max}");

    double sqr1 = Math.Round(Math.Sqrt(num1));
    double sqr2 = Math.Round(Math.Sqrt(num2), 0);
    double sqr3 = Math.Round(Math.Sqrt(num3), 0);
    Console.WriteLine($"Округлённые корни: {sqr1}, {sqr2}, {sqr3}");

    // Первый вариант: цепочка if / else if
    if (sqr1 == sqr2)
        Console.WriteLine("Хотя бы два округлённых корня совпадают.");
    else if (sqr2 == sqr3)
        Console.WriteLine("Хотя бы два округлённых корня совпадают.");
    else if (sqr3 == sqr1)
        Console.WriteLine("Хотя бы два округлённых корня совпадают.");

    // Второй вариант: составное условие
    if (sqr1 == sqr2 || sqr1 == sqr3 || sqr2 == sqr3)
        Console.WriteLine("Хотя бы два округлённых корня совпадают.\n" +
            "\tПроверено составным условием.");
}

public static void Main()
{
    Q213();
}

Math.Round(value) и Math.Round(value, 0) здесь округляют до целого. Перенос строки в исходном коде между строковыми литералами не создаёт переноса в выводе: для этого используется \n, а \t вставляет табуляцию.

2.1.4. Значение функции

Получите от пользователя целое число \(x\) и выведите значение:

\[y = x^3 + 6x - 10\]

Используйте Math.Pow для возведения в степень.

На будущее: вариант с методом
  1. Напишите метод static double CalcY(int x), который возвращает значение выражения \(x^3 + 6x - 10\). Тип double соответствует результату Math.Pow.
  2. В Main получите x, вызовите метод и выведите возвращённое значение.

2.1.5. Трёхзначное число Армстронга

Получите положительное трёхзначное целое число. Проверьте, равно ли оно сумме кубов своих цифр. Такое число называют числом Армстронга; например:

\[153 = 1^3 + 5^3 + 3^3\]

Используйте методы Math для степеней, целочисленное деление и остаток от деления для выделения цифр, условие — для вывода результата.

Это задание использует условия и оператор % из главы 3.

На будущее: вариант с методом
  1. Напишите метод static bool IsTriNumber(int num). Для положительного трёхзначного числа он возвращает true, если число равно сумме кубов своих цифр, и false в противном случае.
  2. В Main получите число, вызовите метод и выведите результат.

Дополнительные задачи

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

2.1.6. Сколько вожатых нужно лагерю: Math.Ceiling

2.1.6. Округление количества групп вверх

По условию задачи на каждых десять участников летнего лагеря нужен один вожатый. Неполная группа тоже требует вожатого:

  • от 1 до 10 участников — один вожатый;
  • от 11 до 20 — два;
  • от 21 до 30 — три;
  • и так далее.

Напишите программу, которая получает положительное количество участников и выводит необходимое число вожатых. Решите задачу без if, используя Math.Ceiling.

Решение и порядок вычислений
1
2
3
4
5
6
7
static void Main(string[] args)
{
    Console.Write("Введите количество участников: ");
    int num1 = int.Parse(Console.ReadLine());
    int result = (int)Math.Ceiling((double)num1 / 10);
    Console.WriteLine($"Нужно вожатых: {result}");
}

Разберём ту же программу по шагам:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static void Main(string[] args)
{
    // 1. Приглашение к вводу
    Console.Write("Введите количество участников: ");

    // 2. Чтение строки
    string input = Console.ReadLine();

    // 3. Преобразование строки в целое число
    int num1 = int.Parse(input);

    // 4. Преобразование в double, чтобы сохранить дробную часть при делении
    double num1Double = (double)num1;

    // 5. Деление на размер группы
    double division = num1Double / 10;

    // 6. Округление вверх
    double ceilingValue = Math.Ceiling(division);

    // 7. Приведение результата к int
    int result = (int)ceilingValue;

    // 8. Вывод результата
    Console.WriteLine(result);
}

Например, для 21 участника деление даёт 2.1, округление вверх — 3. Приведение к int после округления меняет тип результата.

Можно записать вычисление короче. Каждый из следующих фрагментов — отдельный вариант:

Console.Write("Введите количество участников: ");
Console.WriteLine(Math.Ceiling(
    double.Parse(Console.ReadLine()) / 10));
Console.Write("Введите количество участников: ");
Console.WriteLine(Math.Ceiling(
    int.Parse(Console.ReadLine()) / 10.0));

Число 10.0 обеспечивает вещественное деление. Если сначала выполнить целочисленное деление, дробная часть потеряется ещё до округления.

2.1.7. Дни в феврале без условий: округление вверх

2.1.7. Февраль по юлианскому календарю

В этой задаче используется юлианский календарь: если номер года делится на 4 без остатка, в феврале 29 дней, иначе — 28. Получите положительный номер года и выведите число дней в феврале без условного оператора.

Это правило юлианского календаря. Для современного григорианского календаря нужны дополнительные проверки: они приведены в задаче 3.2.1.

Решение
Console.Write("Введите год: ");
int year = int.Parse(Console.ReadLine());
int extra = (int)Math.Ceiling(year / 4.0) - year / 4;
Console.WriteLine($"В феврале {year} года {29 - extra} дней");

Если год делится на 4, вещественное и целочисленное деление дают одинаковое целое значение. Получаем extra = 0, значит, дней 29.

Если остаток ненулевой, округление вещественного частного вверх даёт на единицу больше, чем целочисленное деление. Получаем extra = 1, значит, дней 28.

2.1.8. Дни в феврале без условий и Math.Ceiling

2.1.8. Сведение задачи к значениям 0 и 1

Решите предыдущую задачу для положительного номера года без if и без Math.Ceiling. Можно использовать остаток от деления.

Попробуйте сначала получить 0 для годов, делящихся на 4, и 1 для остальных. Затем используйте 29 - zeroOr1.

Такой подход — сведение задачи к более простой: вместо прямого вычисления количества дней сначала строим удобное промежуточное значение.

Решение: отображение в 0 и 1
static void Main(string[] args)
{
    Console.Write("Введите год: ");
    int year = int.Parse(Console.ReadLine());
    int zeroOr1 = (year % 4 + 3) / 4;
    Console.WriteLine($"Году {year} соответствует {zeroOr1}");
    Console.WriteLine($"В феврале {29 - zeroOr1} дней");
}

Остатки 0, 1, 2, 3 после прибавления трёх превращаются в 3, 4, 5, 6. Целочисленное деление на 4 даёт соответственно 0, 1, 1, 1.

2.1.9. Случайный выбор одного из месяцев 1, 2, 10, 11, 12

2.1.9. Равновероятный выбор без условий

Получите случайным образом одно из пяти чисел \(1, 2, 10, 11, 12\) — номера первых двух и последних трёх месяцев года.

  • Используйте одну инструкцию присваивания int n = ...;.
  • Не используйте условия или массивы в самом выражении выбора.
  • Каждый из пяти месяцев должен иметь одинаковую вероятность выбора: \(\frac{1}{5} = 0.2\).
Решение и проверка распределения — после изучения циклов и массивов

Один вариант:

int n = rnd.Next(9, 14) % 12 + 1;

Генератор выбирает одно из пяти чисел 9, 10, 11, 12, 13. Остаток от деления на 12 и прибавление единицы превращают их в 10, 11, 12, 1, 2. Каждому месяцу соответствует ровно один исходный вариант.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
static Random rnd = new Random();
static void Main()
{
    int[] arr = new int[13];
    for (int i = 0; i < 10000000; i++)
    {
        int n = rnd.Next(9, 14) % 12 + 1;
        arr[n]++;
    }

    for (int i = 0; i < arr.Length; i++)
        Console.WriteLine($"Месяц {i}: доля {arr[i] / 10000000.0}");
}

Доли месяцев 1, 2, 10, 11, 12 должны быть близки к 0.2, остальные — равны нулю. Проверка помогает обнаружить ошибку; объяснение соответствия пяти исходов показывает, почему выбор равновероятен.

Следующие шаги

Глава 3: условия и логические выражения →

Вернуться к объяснению Math и Random · Содержание курса