Що таке випадкові числа
Випадкове число — це число, яке неможливо передбачити заздалегідь. У програмуванні найчастіше використовують так звані псевдовипадкові числа: комп'ютер обчислює їх за математичною формулою від початкового значення (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 12Random.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)Практичні завдання
- Вивести 25 випадкових чисел у діапазоні від 10 до 99 та знайти серед них максимальне.
- Згенерувати масив із 30 елементів (діапазон −50..50) і підрахувати кількість від'ємних.
- Заповнити матрицю 5×5 випадковими числами та знайти суму елементів головної діагоналі.
- Написати програму, яка кидає два кубики, поки сума не дорівнюватиме 12, і виводить кількість спроб.
- Згенерувати 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).