Назад Вперед Зміст

Випадкові числа. Клас Random у C#

Що таке випадкові числа

Випадкове число — це число, яке неможливо передбачити заздалегідь. У програмуванні найчастіше використовують так звані псевдовипадкові числа: комп'ютер обчислює їх за математичною формулою від початкового значення (seed), тому послідовність виглядає випадковою, але насправді є детермінованою.

Де це потрібно

  • ігри (кидок кубика, перемішування карт, поведінка ворогів);
  • тестування програм (генерація тестових даних);
  • моделювання та статистика (метод Монте-Карло);
  • криптографія (але для неї є окремий клас RandomNumberGenerator);
  • навчальні задачі: заповнення масивів, матриць, вибір випадкового елемента.
Важливо розуміти Клас Random з простору імен System генерує псевдовипадкові числа. Для задач, де потрібна справжня криптографічна стійкість (паролі, ключі шифрування), використовують System.Security.Cryptography.RandomNumberGenerator.

Створення об'єкта Random

Щоб скористатися генератором, спочатку створюють екземпляр класу Random. Найпростіший конструктор не приймає параметрів і використовує початкове значення, що базується на системному часі.

using System;   // обов'язково підключаємо простір імен System

class Program
{
    static void Main()
    {
        // Створюємо ОДИН екземпляр генератора на всю програму
        Random rnd = new Random();

        // Далі через rnd отримуємо випадкові числа
        int n = rnd.Next(1, 101);   // число від 1 до 100
        Console.WriteLine(n);
    }
}

Конструктор із зерном (seed)

Другий конструктор приймає ціле число — початкове значення. Якщо задати однакове зерно, то послідовність чисел буде однаковою при кожному запуску. Це корисно для відтворюваних тестів і налагодження.

// Фіксоване зерно → однакова послідовність при кожному запуску
Random rnd = new Random(12345);

for (int i = 0; i < 5; i++)
{
    Console.Write(rnd.Next(1, 100) + " ");
}
// Результат завжди буде одним і тим самим, наприклад: 68 51 34 90 12
Сумісність версій .NET У .NET 6+ з’явилася зручна властивість Random.Shared — готовий потокобезпечний екземпляр, який не потрібно створювати вручну. Однак у старіших платформах (.NET Framework, Mono 4.x) її немає. Тому для універсальності радимо завжди створювати екземпляр класу Random явно.
// Універсальний варіант, що працює скрізь (включно з Mono 4.5)
Random rnd = new Random();
int number = rnd.Next(1, 101);
Console.WriteLine(number);

Основні методи класу Random

Метод Що повертає Діапазон
Next() ціле число int від 0 до int.MaxValue (2 147 483 647)
Next(max) ціле число int від 0 включно до max не включно
Next(min, max) ціле число int від min включно до max не включно
NextDouble() дробове double від 0.0 включно до 1.0 не включно
NextInt64() ціле long задається аналогічно до Next (.NET 6+)
NextBytes(buffer) нічого (void) заповнює масив byte[] випадковими байтами
Головне правило! Верхня межа у методах Next(...) не входить у діапазон. Щоб отримати число від 1 до 100, треба писати rnd.Next(1, 101), а не rnd.Next(1, 100).

NextDouble() — дробові числа

Метод NextDouble() завжди повертає значення в діапазоні [0.0; 1.0). Щоб отримати дробове число у власному діапазоні, використовують формулу:

min + rnd.NextDouble() * (max - min)

Random rnd = new Random();

for (int i = 0; i < 5; i++)
{
    // Базовий варіант: число від 0.0 до 1.0
    double x = rnd.NextDouble();
    Console.WriteLine($"{x:F4}");
}

// Дробове число в діапазоні [5.0; 10.0)
double y = 5.0 + rnd.NextDouble() * 5.0;
Console.WriteLine($"Випадкове значення: {y:F2}");

NextBytes() — заповнення масиву байтів

Random rnd = new Random();

byte[] buffer = new byte[8];   // масив із 8 байтів
rnd.NextBytes(buffer);          // заповнюємо його випадковими значеннями 0..255

foreach (byte b in buffer)
{
    Console.Write($"{b:X2} ");   // X2 — шістнадцятковий формат із двома цифрами
}

Приклади з циклами

Найчастіше випадкові числа генерують у циклі — щоб отримати не одне значення, а цілу послідовність. Розглянемо типові конструкції.

Приклад 1. Цикл for: вивести 10 чисел

using System;

class Program
{
    static void Main()
    {
        // Екземпляр Random створюємо ОДИН раз — перед циклом!
        Random rnd = new Random();

        // i = 0, 1, 2, ... 9 — усього 10 ітерацій
        for (int i = 0; i < 10; i++)
        {
            // Next(1, 101) → ціле число від 1 до 100 (101 не входить)
            int number = rnd.Next(1, 101);

            // Інтерполяція рядків: {$"...{вираз}..."}
            Console.WriteLine($"Спроба {i + 1}: {number}");
        }
    }
}

Приклад 2. Сума та середнє арифметичне

using System;

class Program
{
    static void Main()
    {
        Random rnd = new Random();

        int sum = 0;      // накопичувальна змінна для суми
        int count = 20;   // скільки чисел генеруємо

        for (int i = 0; i < count; i++)
        {
            int n = rnd.Next(1, 51);   // випадкове число від 1 до 50
            Console.Write(n + " ");
            sum += n;                  // sum = sum + n
        }

        Console.WriteLine();   // перехід на новий рядок

        // Увага: (double) обов'язковий, інакше буде цілочисельне ділення!
        double average = (double)sum / count;

        Console.WriteLine($"Сума: {sum}");
        Console.WriteLine($"Середнє: {average:F2}");   // F2 — два знаки після коми
    }
}
Типова пастка Якщо написати double avg = sum / count; без приведення типів, C# спочатку виконає цілочисельне ділення і лише потім перетворить результат у double. Дрібна частина буде втрачена.

Приклад 3. Від'ємний діапазон

Метод Next(min, max) спокійно працює і з від'ємними числами.

Random rnd = new Random();

Console.WriteLine("Температура за 15 днів:");

for (int i = 0; i < 15; i++)
{
    // від -10 включно до 11 НЕ включно → фактично -10..10
    int t = rnd.Next(-10, 11);

    // {t,4} — вирівнювання по правому краю в полі шириною 4 символи
    Console.Write($"{t,4}");
}

Console.WriteLine();

Приклад 4. Цикл do-while: кидок кубика

do-while гарантує хоча б одне виконання тіла циклу, бо умова перевіряється після ітерації.

Random rnd = new Random();

int dice;          // результат кидка
int rolls = 0;     // кількість кидків

do
{
    // Next(1, 7) → 1, 2, 3, 4, 5 або 6
    dice = rnd.Next(1, 7);
    rolls++;

    Console.WriteLine($"Кидок {rolls}: випало {dice}");
}
while (dice != 6);   // кидаємо, поки не випаде шістка

Console.WriteLine($"Шістка випала на {rolls}-му кидку.");

Приклад 5. Заповнення масиву + foreach

Для заповнення масиву використовують for (потрібен індекс), а для перегляду — зручніший foreach.

Random rnd = new Random();

int[] temperatures = new int[7];   // масив на 7 елементів

// Заповнення: тут потрібен індекс i
for (int i = 0; i < temperatures.Length; i++)
{
    temperatures[i] = rnd.Next(-15, 36);   // від -15 до 35 °C
}

// Виведення: індекс не потрібен, тому foreach
Console.WriteLine("Температура за тиждень:");
foreach (int t in temperatures)
{
    Console.Write($"{t}°C  ");
}

Console.WriteLine();

Приклад 6. Підрахунок парних і непарних

Random rnd = new Random();

int even = 0;   // парних
int odd = 0;    // непарних

for (int i = 0; i < 50; i++)
{
    int n = rnd.Next(1, 1000);

    // Оператор % повертає остачу від ділення.
    // Якщо остача 0 — число парне.
    if (n % 2 == 0)
        even++;
    else
        odd++;
}

Console.WriteLine($"Парних: {even}, непарних: {odd}");

Приклад 7. Вкладені цикли: генерація матриці

Для двовимірних структур використовують вкладений цикл: зовнішній проходить по рядках, внутрішній — по стовпцях.

Random rnd = new Random();

int rows = 4;   // кількість рядків
int cols = 5;   // кількість стовпців

// Зовнішній цикл — рядки
for (int i = 0; i < rows; i++)
{
    // Внутрішній цикл — стовпці
    for (int j = 0; j < cols; j++)
    {
        // Двозначне число 10..99, вирівняне у полі шириною 4
        Console.Write($"{rnd.Next(10, 100),4}");
    }

    Console.WriteLine();   // після кожного рядка — новий рядок
}

Приклад 8. Випадковий елемент масиву

Random rnd = new Random();

string[] students = { "Олена", "Ігор", "Марія", "Богдан", "Софія" };

// Індекс масиву лежить у межах [0; students.Length - 1],
// тому верхня межа для Next — це students.Length
int index = rnd.Next(students.Length);

Console.WriteLine($"Відповідає: {students[index]}");
Запам'ятайте шаблон Випадковий індекс масиву завжди отримують так: rnd.Next(array.Length). Метод Next не включає верхню межу, тому Length дає саме потрібний діапазон 0 .. Length-1.

Типові помилки

❌ Помилка 1. Створення Random усередині циклу

Якщо створювати new Random() на кожній ітерації, генератор щоразу ініціалізується одним і тим самим системним часом — і всі числа вийдуть однаковими.

// ❌ НЕПРАВИЛЬНО — усі 5 чисел будуть однакові
for (int i = 0; i < 5; i++)
{
    Random bad = new Random();
    Console.WriteLine(bad.Next(1, 100));
}

// ✅ ПРАВИЛЬНО — один екземпляр перед циклом
Random good = new Random();
for (int i = 0; i < 5; i++)
{
    Console.WriteLine(good.Next(1, 100));
}

❌ Помилка 2. Забути про невключну верхню межу

Random rnd = new Random();

// Хочемо отримати 1..6 (як на кубику)

int wrong = rnd.Next(1, 6);    // ❌ дасть 1..5, шістка НІКОЛИ не випаде
int right = rnd.Next(1, 7);    // ✅ дасть 1..6

Console.WriteLine($"{wrong} / {right}");

❌ Помилка 3. Цілочисельне ділення при обчисленні середнього

int sum = 137;
int count = 20;

double wrong = sum / count;            // ❌ 137 / 20 = 6 (дробова частина втрачена)
double right = (double)sum / count;    // ✅ 6.85

❌ Помилка 4. Спроба задати діапазон у NextDouble()

Random rnd = new Random();

// ❌ Такого перевантаження не існує — код не скомпілюється
// double x = rnd.NextDouble(5, 10);

// ✅ Правильно: масштабуємо базове значення [0;1)
double x = 5 + rnd.NextDouble() * 5;   // результат у [5;10)

Практичні завдання

  1. Вивести 25 випадкових чисел у діапазоні від 10 до 99 та знайти серед них максимальне.
  2. Згенерувати масив із 30 елементів (діапазон −50..50) і підрахувати кількість від'ємних.
  3. Заповнити матрицю 5×5 випадковими числами та знайти суму елементів головної діагоналі.
  4. Написати програму, яка кидає два кубики, поки сума не дорівнюватиме 12, і виводить кількість спроб.
  5. Згенерувати 10 дробових чисел у діапазоні від −1.5 до 1.5 і вивести їх із двома знаками після коми.
Показати підказку до завдання 2

Створіть масив int[] arr = new int[30];, заповніть його циклом for значеннями rnd.Next(-50, 51), а потім окремим циклом перевірте кожен елемент умовою if (arr[i] < 0) negative++;.

Показати підказку до завдання 3

Головна діагональ — це елементи, у яких індекс рядка дорівнює індексу стовпця (i == j). Тобто замість вкладеного циклу достатньо одного: for (int i = 0; i < 5; i++) sum += matrix[i, i];

Показати підказку до завдання 4

Використайте цикл do-while. Умова продовження: while (d1 + d2 != 12); Кожен кубик — rnd.Next(1, 7).

Назад Вперед Зміст