C случайное число от 0 до 100. Генерация (псевдо)случайных чисел

У нас есть последовательность чисел, состоящая из практически независимых элементов, которые подчиняются заданному распределению. Как правило, равномерному распределению.

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

Функция случайного числа в Excel

  1. Функция СЛЧИС возвращает случайное равномерно распределенное вещественное число. Оно будет меньше 1, больше или равно 0.
  2. Функция СЛУЧМЕЖДУ возвращает случайное целое число.

Рассмотрим их использование на примерах.

Выборка случайных чисел с помощью СЛЧИС

Данная функция аргументов не требует (СЛЧИС()).

Чтобы сгенерировать случайное вещественное число в диапазоне от 1 до 5, например, применяем следующую формулу: =СЛЧИС()*(5-1)+1.

Возвращаемое случайное число распределено равномерно на интервале .

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

  1. Щелкаем по ячейке со случайным числом.
  2. В строке формул выделяем формулу.
  3. Нажимаем F9. И ВВОД.

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


Диапазон вертикальных значений – частота. Горизонтальных – «карманы».



Функция СЛУЧМЕЖДУ

Синтаксис функции СЛУЧМЕЖДУ – (нижняя граница; верхняя граница). Первый аргумент должен быть меньше второго. В противном случае функция выдаст ошибку. Предполагается, что границы – целые числа. Дробную часть формула отбрасывает.

Пример использования функции:

Случайные числа с точностью 0,1 и 0,01:

Как сделать генератор случайных чисел в Excel

Сделаем генератор случайных чисел с генерацией значения из определенного диапазона. Используем формулу вида: =ИНДЕКС(A1:A10;ЦЕЛОЕ(СЛЧИС()*10)+1).

Сделаем генератор случайных чисел в диапазоне от 0 до 100 с шагом 10.

Из списка текстовых значений нужно выбрать 2 случайных. С помощью функции СЛЧИС сопоставим текстовые значения в диапазоне А1:А7 со случайными числами.

Воспользуемся функцией ИНДЕКС для выбора двух случайных текстовых значений из исходного списка.

Чтобы выбрать одно случайное значение из списка, применим такую формулу: =ИНДЕКС(A1:A7;СЛУЧМЕЖДУ(1;СЧЁТЗ(A1:A7))).

Генератор случайных чисел нормального распределения

Функции СЛЧИС и СЛУЧМЕЖДУ выдают случайные числа с единым распределением. Любое значение с одинаковой долей вероятности может попасть в нижнюю границу запрашиваемого диапазона и в верхнюю. Получается огромный разброс от целевого значения.

Нормальное распределение подразумевает близкое положение большей части сгенерированных чисел к целевому. Подкорректируем формулу СЛУЧМЕЖДУ и создадим массив данных с нормальным распределением.

Себестоимость товара Х – 100 рублей. Вся произведенная партия подчиняется нормальному распределению. Случайная переменная тоже подчиняется нормальному распределению вероятностей.

При таких условиях среднее значение диапазона – 100 рублей. Сгенерируем массив и построим график с нормальным распределением при стандартном отклонении 1,5 рубля.

Используем функцию: =НОРМОБР(СЛЧИС();100;1,5).

Программа Excel посчитала, какие значения находятся в диапазоне вероятностей. Так как вероятность производства товара с себестоимостью 100 рублей максимальная, формула показывает значения близкие к 100 чаще, чем остальные.

Перейдем к построению графика. Сначала нужно составить таблицу с категориями. Для этого разобьем массив на периоды:

На основе полученных данных сможем сформировать диаграмму с нормальным распределением. Ось значений – число переменных в промежутке, ось категорий – периоды.

Приветствую всех, кто заскочил. В это короткой заметке будет пара слов о генерации псевдослучайных чисел на C/C++. В частности о том, как работать с самой простой функцией генерации — rand().

Функция rand()

Находится в стандартной библиотеке С++(stdlib.h). Генерирует и возвращает псевдослучайное число в диапазоне от 0 до RAND_MAX . Эта константа может отличаться в зависимости от компилятора или архитектуры процессора, в основном, это максимальное значение типа данных unsigned int . Параметров не принимает и никогда не принимала.

Для того, чтобы генерация свершилась, нужно выставить семя(seed) с помощью вспомогательной функции из той же библиотеки — srand() . Она принимает число и ставит его в качестве отправной точки в генерации случайного числа. Если семя не выставить, то при каждом запуске программы, мы будет получать одинаковые случайные числа. Самым очевидным решением является отправить туда текущее системное время. Сделать это можно с помощью функции time(NULL). Эта функция находится в библиотеке time.h .

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

Пример использования функции генерации случайных чисел rand()

#include #include #include using namespace std; int main() { srand(time(NULL)); for(int i = 0; i < 10; i++) { cout << rand() << endl; } return 0; }

Ранд нагенерировал нам 10 случайных чисел. В том, что они случайные вы можете убедиться, запуская программу вновь и вновь. Но этого недостаточно, поэтому нужно поговорить о диапазоне.

Выставить границы диапазона для rand()

Чтобы сгенерировать число в диапазоне от A до B включительно, нужно написать так:

A + rand() % ((B + 1) - A);

Значения границ могут быть в том числе и отрицательными, что позволяет генерировать отрицательное случайное число, посмотрим пример.

#include #include #include using namespace std; int main() { srand(time(NULL)); int A = -2; int B = 8; for(int i = 0; i < 100; i++) { cout << A + rand() % ((B + 1) - A) << endl; } return 0; }

Очень часто в программах возникает необходимость использования случайных чисел - от заполнения массива до криптографии. Для получения последовательности случайных чисел в языке C# имеется класс Random . Этот класс предусматривает два конструктора:

  • Random () - инициализирует экземпляр класса Random с помощью начального значения, зависящего от текущего времени. Как известно, время может быть представлено в тиках - 100-наносекундных импульсах, начиная с 1 января 0001 года. И значение времени в тиках представляет собой 64-битное целое число, которое и будет использоваться для инициализации экземпляра генератора случайных чисел.
  • Random (Int32 ) - инициализирует экземпляр класса Random с помощью указанного начального значения. Такая инициализация генератора случайных чисел может быть удобна на этапе отладки программы, поскольку в этом случае при каждом запуске программы будут генерироваться одни и те же "случайные" числа.
Основным методом данного класса является метод Next() , позволяющий получить случайное число и имеющий ряд перегрузок:
  • Next() - возвращает случайное целое неотрицательное число формата Int32 .
  • Next(Int32 ) - возвращает случайное целое неотрицательное число, которое меньше указанного значения.
  • Next(Int32 min, Int32 max) - возвращает случайное целое число в указанном диапазоне. При этом должно соблюдаться условие min
А также методы
  • NextBytes(Byte ) - заполняет элементы указанного массива байтов случайными числами.
  • NextDouble() - возвращает случайное число с плавающей запятой, в диапазоне )
    break ; // совпадение найдено, элемент не подходит
    }
    if (j == i)
    { // совпадение не найдено
    a[i] = num; // сохраняем элемент
    i++; // переходим к следующему элементу
    }
    }
    for (int i = 0; i < 100; i++)
    {

    if (i % 10 == 9)
    Console .WriteLine();
    }
    Console .ReadKey();
    }
    }
    }

    Однако чем ближе к концу массива, тем больше генераций необходимо производить для получения неповторяющегося значения.
    Следующий пример отображает количество вызовов метода Next() для получения каждого элемента, а также общее количество сгенерированных случайных чисел для заполнения массива из 100 элементов неповторяющимися значениями.

    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53

    using System;
    namespace MyProgram
    {
    class Program
    {
    static void Main(string args)
    {
    Random rnd = new Random ();
    int a = new int ; // массив элементов
    int count = new int ; // массив количества генераций
    a = rnd.Next(0, 101);
    int c = 0; // счетчик количества генераций
    count = 1; // a генерируется только 1 раз
    for (int i = 1; i < 100;)
    {
    int num = rnd.Next(0, 101);
    c++; // сгенерировали элемент еще один раз
    int j;
    for (j = 0; j < i; j++)
    {
    if (num == a[j])
    break ;
    }
    if (j == i)
    {
    a[i] = num; i++;
    count[i] = c; c = 0; // сохраняем количество генераций
    }
    }
    // Вывод значений элементов
    Console .WriteLine("Значения элементов" );
    for (int i = 0; i < 100; i++)
    {
    Console .Write("{0,4} " , a[i]);
    if (i % 10 == 9)
    Console .WriteLine();
    }
    Console .WriteLine();
    // Вывод количества генераций
    Console .WriteLine("Количество генераций элементов" );
    int sum = 0;
    for (int i = 0; i < 100; i++)
    {
    sum += count[i];
    Console .Write("{0,4} " , count[i]);
    if (i % 10 == 9)
    Console .WriteLine();
    }
    Console .WriteLine("Общее количество генераций - {0}" , sum);
    Console .ReadKey();
    }
    }
    }

    void Main(string args)
    {
    Random rnd = new Random ();
    int a = new int ;
    for (int i = 0; i < 100; i++)
    a[i] = i;
    for (int i = 0; i < 50; i++)
    {
    int i1 = rnd.Next(0, 100); // первый индекс
    int i2 = rnd.Next(0, 100); // второй индекс
    // обмен значений элементов с индексами i1 и i2
    int temp = a;
    a = a;
    a = temp;
    }
    Console .WriteLine("Значения элементов" );
    for (int i = 0; i < 100; i++)
    {
    Console .Write("{0,4} " , a[i]);
    if (i % 10 == 9)
    Console .WriteLine();
    }
    Console .ReadKey();
    }
    }
    }

    Перемешивание значений является более эффективным если диапазон значений совпадает с их количеством (или близок к нему), поскольку в этом случае значительно сокращается количество генераций случайных элементов.

    Функция, генерирующая псевдослучайные числа, имеет прототип в файле библиотеки stdlib.h :

    1
    2
    3
    4
    5
    6

    unsigned long int next = 1;
    int rand(void )
    {
    next = next * 1103515245;
    return ((unsigned int )(next / 65536) * 2768);
    }


    Функция rand() не принимает аргументов, а оперирует переменной next с глобальной областью видимости.

    Если необходимо сгенерировать последовательность в диапазоне , то используется формула:

    Number = rand()%(M2-M1+1) + M1;

    где Number – генерируемое число. M2-M1+1 – полный диапазон представления чисел. M1 – смещение указанного диапазона относительно 0; % — остаток от деления .

    Например, если требуется сгенерировать последовательность в диапазоне [-10;10], то вызов функции будет выглядеть как

    Number = rand()%(10+10+1)-10

    Number = rand()%(21)-10

    В результате получения остатка от деления на 21 имеем число от 0 до 20. Вычитая из полученного числа 10, получим число в искомом диапазоне [-10;10].

    Однако генерируемая функцией rand() последовательность будет иметь один и тот же вид при каждом запуске программы.

    Для генерации различных последовательности при каждом запуске программы необходимо проинициализировать глобальную переменную next значением, отличным от 1. С этой целью используется функция
    void srand(unsigned int seed)
    { next = seed; }

    Чтобы инициализация next при каждом запуске программы была различной в качестве аргумента seed чаще всего используется текущее время.

    Пример Заполнить массив из 20 элементов случайными числами в диапазоне от 0 до 99.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    #include
    #include
    #include
    #define SIZE 20
    int main() {
    int a;
    srand(time(NULL ));
    for (int i = 0; i {
    a[i] = rand() % 100;
    printf("%d " , a[i]);
    }
    getchar();
    return 0;
    }


    Результат выполнения

    Часто возникает задача расставить уже имеющийся набор значений в произвольном порядке. С этой целью также используется генератор псевдослучайных чисел. При этом создается массив и заполняется значениями.
    Сама процедура перемешивания происходит следующим образом. Генерируется два значения индексов массива случайным образом, и значения элементов с полученными индексами меняются местами. Процедура повторяется не менее N раз, где N - количество элементов массива.
    В качестве примера рассмотрим перемешивание 20 значений (от 1 до 20) и повторим процедуру 20 раз.

    Реализация на Си

    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

    #include
    #include
    #include
    #define SIZE 20
    int main() {
    int a;
    srand(time(NULL ));

    for (int i = 0; i < SIZE; i++)
    {
    a[i] = i + 1;
    printf("%2d " , a[i]);
    }
    for (int i = 0; i < SIZE; i++)
    {
    // Генерируем случайно два индекса элементов
    int ind1 = rand() % 20;
    int ind2 = rand() % 20;
    // и меняем местами элементы с этими индексами
    int temp = a;
    a = a;
    a = temp;
    }
    printf("\n" );

    for (int i = 0; i < SIZE; i++)
    printf("%2d " , a[i]);
    getchar();
    return 0;
    }


    Результат выполнения


    Часто возникает задача произвольного выбора ранее заданных элементов массива. Причем необходимо предусмотреть отсутствие повторений в выборе этих элементов.
    Алгоритм такого выбора состоит в следующем:

    • Выбираем произвольно индекс элемента массива
    • Если элемент с таким индексом уже был ранее выбран, двигаемся вправо, пока не дойдём до следующего не выбранного элемента. При этом следим за тем, чтобы "движение вправо" не вышло за границы массива. Если фиксируется выход за границы массива, начинаем просмотр элементов массива с начала.
    • Выбираем элемент
    • Фиксируем элемент как выбранный
    • Повторяем указанные действия для всех остальных элементов

    Реализации на Си
    В результате получаем новый массив b , сформированный произвольной выборкой элементов массива a .

    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

    #include
    #include
    #include
    #define SIZE 20
    int main() {
    int a;
    int b; // результирующий массив
    srand(time(NULL ));
    // Заполняем массив последовательными значениями от 1 до 20
    for (int i = 0; i < SIZE; i++)
    {
    a[i] = i + 1;
    printf("%2d " , a[i]);
    }

    for (int i = 0; i < SIZE; i++)
    {
    int ind = rand() % 20; // выбираем произвольный индекс
    while (a == -1) // пока элемент "выбран"
    {
    ind++; // двигаемся вправо
    ind %= 20; // если дошли до правой границы, возвращаемся в начало
    }
    b[i] = a; // записываем следующий элемент массива b
    a = -1; // отмечаем элемент массива a как "выбранный"
    }
    printf("\n" );
    // Выводим получившийся массив
    for (int i = 0; i < SIZE; i++)
    printf("%2d " , b[i]);
    getchar();
    return 0;
    }


    Результат выполнения

    В языках программирования обычно предусмотрены функции, позволяющие генерировать случайные числа в определенном по умолчанию диапазоне. На самом деле генерируются не случайные, а так называемые псевдослучайные числа; они выглядят случайно, но вычисляются по вполне конкретной формуле. Но для простоты далее мы все равно будем называть их случайными.

    В языке программирования C получить случайное число можно с помощью функции rand() , которая входит в стандартную библиотеку языка. Эта функция не принимает никакие параметры.

    Задание
    Напишите программу, в которой целочисленной переменной присваивается результат выполнения функции rand() . Выведите значение переменной на экран.

    Функция rand() возвращает целое число от 0 до значения присвоенного константе RAND_MAX. Значение RAND_MAX зависит от системы и определено в заголовочном файле stdlib.h. Так, например, оно может быть равно 32767 (двухбайтовое целое) или 2147483647 (четырехбайтовое целое).

    Задание
    Определите значение RAND_MAX в вашей системе. Для этого не забудьте подключить к файлу исходного кода заголовочный файл stdlib.h.

    Код ниже выводит на экран 50 случайных чисел:

    #include #include main () { char i; for (i = 1 ; i <= 50 ; i++ ) { printf ("%15d" , rand () ) ; if (i % 5 == 0 ) printf ("\n " ) ; } }

    В теле цикла осуществляется переход на новую строку после каждых выведенных на экран пяти чисел. Для этого используется выражение, в котором находится остаток от деления i на 5, результат сравнивается с 0. Чтобы после первого числа не происходил переход на новую строку, iсначала присваивается единица, а не ноль (т.к. 0 делится на 5 без остатка).

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

    Вы должны были заметить, что при каждом запуске программы числа остаются одинаковыми. Даже если вы перекомпилируете программу, результат не изменится. Данный эффект связан с тем, что начальное (инициализирующее) число, которое подставляется в формулу вычисления первого и последующих псевдослучайных чисел, для каждой системы всегда одно и то же. Однако это начальное число можно изменить с помощью функции srand() , которой в качестве параметра передается любое целое число. Понятно, что если вы зададите конкретный аргумент для функции, например, srand(1000) , то от вызова к вызову программы числа будут также одни и те же. Хотя и не те, что были бы без srand() . Поэтому появляется проблема, как сделать так, чтобы аргумент для srand() был тоже случайным? Получается замкнутый круг.

    Задание
    Переделайте программу, выводящую на экран 50 случайных чисел так, чтобы сначала у пользователя запрашивалось любое целое число с помощью scanf() , которое передавалось бы в функцию srand() .

    Пользователь программы сам может задавать инициализирующее значение. Но чаще всего это не является полноценным выходом из ситуации. Поэтому инициализирующее значение привязывают к какому-либо процессу, протекающему в операционной системе, например, к часам. Время (учитывая не только время суток, но и дату) никогда не бывает одинаковым. Значит значение для srand() , преобразованное в целое из системного времени, будет различным.

    Текущее время можно узнать с помощью функции time() , прототип которой описан в файле time.h. Передав time() в качестве параметра NULL, мы получим целое число, которое можно передать в srand() :
    srand(time(NULL));

    Задание
    Переделайте вашу программу так, чтобы инициализирующее значение зависело от системного времени.

    Получение целых случайных чисел в заданных диапазонах

    Функция rand() выдает случайное число от 0 до значения RAND_MAX. Что делать, если требуется получать случайные числа в иных диапазонах, например, от 100 до 999?

    Сначала рассмотрим более простую ситуацию: получить случайные числа от 0 до 5. Если любое целое число попытаться разделить на 5 нацело, то можно получить как 0 (когда число делится на 5 без остатка), так и 1, 2, 3, 4. Например, rand() вернула число 283. Применяя к этому числу операцию нахождения остатка от деления на 5, получим 3. Т.е. выражение rand() % 5 дает любое число в диапазоне ? Логично предположить, что следует найти остаток от деления на 6. При этом более грамотным будет следующее рассуждение: надо находить остаток от деления на размер диапазона. В данном случае он равен шести значениям: 0, 1, 2, 3, 4, 5. Чтобы найти размер диапазона надо из допустимого максимума вычесть допустимый минимум и прибавить единицу: max - min + 1. Будьте внимательны: если, например, требуется, чтобы указанный в задаче максимум не входил в диапазон, то единицу прибавлять не надо или надо вычитать единицу из максимума.

    Задание
    Напишите программу, выдающую 50 случайных чисел от 0 до 99 включительно.

    Итак, мы знаем формулу получения длины диапазона: max - min + 1. Если требуется получить число от 6 до 10 включительно, то длина диапазона будет равна 10 - 6 + 1 = 5. Выражение rand()% 5 даст любое число от 0 до 4 включительно. Но нам надо от 6 до 10. В таком случае достаточно к полученному случайному остатку прибавить 6, т.е. минимум. Другими словами, надо выполнить сдвиг. Действительно для приведенного примера:

    • если остаток был равен 0, то добавляя 6, получаем 6;
    • остаток 1, добавляем 6, получаем 7;
    • остаток 4, прибавляем 6, получаем 10;
    • остатка больше 4 не может быть.

    В таком случае формула для получения случайного числа в диапазоне выглядит так:

    Rand() % длина_диапазона + сдвиг

    где длина_диапазона вычисляется как b - a + 1, сдвиг является значением a.

    В эту формулу также вписываются случаи, когда необходимо получить случайное число от 0 до N, т.е. они являются ее частными случаями.

    Задание
    Выведите на экран ряд случайных чисел, принадлежащих диапазону от 100 до 299 включительно.

    С таким же успехом можно получать случайные отрицательные числа. Действительно, если диапазон задан как [-35, -1], то его длина будет равна -1 - (-35) + 1 = 35, что соответствует действительности; выражение получения случайного числа будет выглядеть так:

    rand() % 35 - 35

    Так, если остаток от деления составил 0, то мы получим -35, а если 34, то -1. Остальные остатки дадут значения в промежутке от -35 до -1.

    Задание
    Выведите на экран ряд случайных чисел, принадлежащих диапазону от -128 до 127 включительно.

    Получение вещественных случайных чисел

    Ситуация с вещественными числами выглядит несколько по-иному. Во-первых, мы не можем получить остаток от деления, если делимое или делитель дробное число. Во вторых при вычислении длины диапазона нельзя прибавлять единицу.

    Поясним вторую причину. Допустим диапазон задан как . Он состоит не из определенного количества чисел (как в случае целых), а из неопределенного (можно сказать, бесконечного) числа значений, т.к. вещественные числа можно представлять с различной степенью точности. Позже выполняя округление все равно будет шанс получить максимальную границу диапазона, поэтому для вычисления длины диапазона достаточно из максимума вычесть минимум.

    Если разделить случайное число, преобразованное к вещественному типу, которое выдала функция rand() , на значение константы RAND_MAX, то получится вещественное случайное число от 0 до 1. Теперь, если это число умножить на длину диапазона, то получится число, лежащее в диапазоне от 0 до значения длины диапазона. Далее если прибавить к нему смещение к минимальной границе, то число благополучно впишется в требуемый диапазон. Таким образом формула для получения случайного вещественного числа выглядит так:

    (float) rand() / RAND_MAX * (max - min) + min

    Задание
    Заполните массив случайными числами в диапазоне от 0.51 до 1.00. Выведите значение элементов массива на экран.

    Равновероятные случайные числа

    Функция rand() генерирует любое случайное число от 0 до RAND_MAX с равной долей вероятности. Другими словами, у числа 100 есть такой же шанс выпасть, как и у числа 25876.

    Чтобы доказать это, достаточно написать программу, подсчитывающую количество выпадений каждого из значений. Если выборка (количество "испытуемых") будет достаточно большой, а диапазон (разброс значений) маленьким, то мы должны увидеть, что процент выпадений того или иного значения приблизительно такой же как у других.

    #include #include #define N 500 main () { int i; int arr[ 5 ] = { 0 } ; srand (time (NULL) ) ; for (i= 0 ; i < N; i++ ) switch (rand () % 5 ) { case 0 : arr[ 0 ] ++; break ; case 1 : arr[ 1 ] ++; break ; case 2 : arr[ 2 ] ++; break ; case 3 : arr[ 3 ] ++; break ; case 4 : arr[ 4 ] ++; break ; } for (i= 0 ; i < 5 ; i++ ) printf ("%d - %.2f%%\n " , i, ((float ) arr[ i] / N) * 100 ) ; }

    В приведенной программе массив из пяти элементов сначала заполняется нулями. Случайные числа генерируются от 0 до 4 включительно. Если выпадает число 0, то увеличивается значение первого элемента массива, если число 1, то второго, и т.д. В конце на экран выводится процент выпадения каждого из чисел.