Функция random — генератор псевдослучайных чисел
Бывают ситуации, когда требуется, чтобы результат работы программы был случайным в определенных пределах. Для реализации такой возможности во многих языках программирования присутствуют встроенные функции, код которых выдает случайные числа. На самом деле числа не совсем случайные, а псевдослучайные. Дело в том, что искусственно реализовать случайность невозможно. Обычно берется некоторый коэффициент и с его помощью вычисляется каждое последующее «случайное» число.
В языке программирования Pascal для генерации псевдослучайных чисел в заданных диапазонах используется функция random.
Перед ее использованием обычно выполняется процедура инициализации датчика случайных чисел — randomize; иначе программа всегда будет выдавать один и тот же результат. Randomize задает начальное значение последовательности, от которого вычисляются все последующие. При каждом запуске программы это значение будет разным, а значит и результат работы функции random будет различным.
Вызов функции random() без аргументов возвращает вещественное случайное число в диапазоне от нуля (включительно) до единицы, то есть [0, 1).
Если в скобках функции random() указан параметр, то она возвращает целое число от 0 до указанного в скобках (не включая само значение). Так выражение random(10) говорит о том, что будет получено любое число в диапазоне [0, 10).
Если требуется получать значения в каком-либо другом диапазоне (не от нуля), то прибегают к математической хитрости. Например, чтобы получить случайное число от -100 до 100 достаточно записать такое выражение: random(200) — 100 . В результате его выполнения сначала будет получено число из диапазона [0, 199], а затем из него будет вычтена сотня. И если случайное число было меньше 100, то результат выражения будет отрицательным.
В программе ниже сначала с помощью процедуры randomize инициализируется датчик случайных чисел. Далее переменной n присваивается случайное значение в диапазоне [5, 12). Значение n используется для определения количества повторов цикла for. В цикле for генерируются случайные числа в диапазоне [-50, 49) и выводятся на экран.
Рассмотрим более сложную задачу. Допустим, надо сгенерировать случайное целое число в пределах диапазона, границы которого вводит пользователь с клавиатуры. Аналогичным образом требуется получить случайное вещественное число и случайный символ. Введем переменные:
Pascal: Занятие № 5. Одномерные массивы в Паскале
Массивы в Паскале используются двух типов: одномерные и двумерные.
Определение одномерного массива в Паскале звучит так: одномерный массив — это определенное количество элементов, относящихся к одному и тому же типу данных, которые имеют одно имя, и каждый элемент имеет свой индекс — порядковый номер.
Описание массива в Паскале (объявление) и обращение к его элементам происходит следующим образом:
var dlina: array [1..3] of integer; begin dlina[1]:=500; dlina[2]:=400; dlina[3]:=150; .
Объявить размер можно через константу:
Инициализация массива
Кроме того, массив может быть сам константным, т.е. все его элементы в программе заранее определены. Описание такого массива выглядит следующим образом:
const a:array[1..4] of integer = (1, 3, 2, 5);
Заполнение последовательными числами:
var a: array of integer; var n:=readInteger; a:=new integer[n];
var a: array of integer; var n:=readInteger; SetLength(a,n); // устанавливаем размер
begin var a: array of integer; a := new integer[3]; a[0] := 5; a[1] := 2; a[2] := 3; end.
или в одну строку:
begin var a: array of integer; a := new integer[3](5,2,3); print(a) end.
Ввод с клавиатуры:
writeln (‘введите кол-во элементов: ‘); readln(n); for i := 1 to n do begin write(‘a[‘, i, ‘]=’); read(a[i]); . end; .
✍ Пример результата:
var a:=ReadArrInteger(5); // целые var a:=ReadArrReal(5); // вещественные
Вывод элементов массива
var a: array[1..5] of integer; i: integer; begin a[1]:=2; a[2]:=4; a[3]:=8; a[4]:=6; a[5]:=3; writeln(‘Массив A:’); for i := 1 to 5 do write(a[i]:2); end.
Для работы с массивами чаще всего используется в Паскале цикл for с параметром, так как обычно известно, сколько элементов в массиве, и можно использовать счетчик цикла в качестве индексов элементов.
[Название файла: taskArray0.pas ]
В данном примере работы с одномерным массивом есть явное неудобство: присваивание значений элементам.
for var i:=0 to a.Length-1 do a[i] += 1;
Проход по элементам (только для чтения):
Пример:
foreach var x in a do Print(x)
Функция Random в Pascal
Для того чтобы постоянно не запрашивать значения элементов массива используется генератор случайных чисел в Паскаль, который реализуется функцией Random . На самом деле генерируются псевдослучайные числа, но суть не в этом.
Диапазон в Паскале тех самых случайных чисел от a до b задается формулой:
var f: array[1..10] of integer; i:integer; begin randomize; for i:=1 to 10 do begin f[i]:=random(10); write(f[i],’ ‘); end; end.
Для вещественных чисел в интервале [0,1]:
var x: real; . x := random(0.0,1.0);;
или с дополнительными параметрами (диапазон [5;15]):
[Название файла: taskArray1.pas ]
Числа Фибоначчи в Паскале
Наиболее распространенным примером работы с массивом является вывод ряда чисел Фибоначчи в Паскаль. Рассмотрим его.
Получили формулу элементов ряда.
var i:integer; f:array[0..19]of integer; begin f[0]:=1; f[1]:=1; for i:=2 to 19 do begin f[i]:=f[i-1]+f[i-2]; writeln(f[i]) end; end.
На данном примере, становится понятен принцип работы с числовыми рядами. Обычно, для вывода числового ряда находится формула определения каждого элемента данного ряда. Так, в случае с числами Фибоначчи, эта формула-правило выглядит как f[i]:=f[i-1]+f[i-2] . Поэтому ее необходимо использовать в цикле for при формировании элементов массива.
[Название файла: taskArray2.pas ]
Максимальный (минимальный) элемент массива
Псевдокод:
Поиск максимального элемента по его индексу:
// … var (min, minind) := (a[0], 0); for var i:=1 to a.Length-1 do if a[i]<min then (min, minind) := (a[i], i); Result := (min, minind);
// … var (min, minind) := (real.MaxValue, 0); for var i:=0 to a.Length-1 do if a[i]<min then (min, minind) := (a[i], i); Result := (min, minind);
begin var a := new integer[5]; a := arrRandomInteger(5); // [86,37,41,45,76] print(a.Min,a.IndexMin); // 37 1 end.
[Название файла: taskArray_min.pas ]
[Название файла: taskArray4.pas ]
[Название файла: taskArray5.pas ]
[Название файла: taskArray6.pas ]
Пример:
[Название файла: taskArray7.pas ]
Поиск в массиве
Рассмотрим сложный пример работы с одномерными массивами:
Для решения поставленной задачи понадобится оператор break — выход из цикла.
Решение Вариант 1. Цикл for:
var f: array[1..10] of integer; flag:boolean; i,c:integer; begin randomize; for i:=1 to 10 do begin f[i]:=random(10); write(f[i],’ ‘); end; flag:=false; writeln(‘введите образец’); readln(c); for i:=1 to 10 do if f[i]=c then begin writeln(‘найден’); flag:=true; break; end; if flag=false then writeln(‘не найден’); end.
begin var a := new integer[10]; a := arrRandomInteger(5,0,5); //[1,3,5,4,5] print(a.IndexOf(3)) // 1 end.
или метод a.Contains(x) наравне с x in a :
begin var a := new integer[10]; a := arrRandomInteger(5,0,5); //[1,3,5,4,5] print(a.Contains(3)); // True print(3 in a)// True end.
Рассмотрим эффективное решение:
Задача: найти в массиве элемент, равный X , или установить, что его нет.
Алгоритм:
- начать с 1-го элемента ( i:=1 );
- если очередной элемент ( A[i] ) равен X , то закончить поиск иначе перейти к следующему элементу.
решение на Паскале Вариант 2. Цикл While:
Поиск элемента в массиве
Предлагаем посмотреть подробный видео разбор поиска элемента в массиве (эффективный алгоритм):
Пример:
[Название файла: taskArray8.pas ]
Циклический сдвиг
Пример: сдвинуть элементы массива влево на 1 позицию, первый элемент становится на место последнего.
Решение:
Программа:
// … var v := a[0]; for var i:=0 to a.Length-2 do a[i] := a[i+1]; a[a.Length-1] := v;
// … var v := a[a.Length-1]; for var i:=a.Length-1 downto 1 do a[i] := a[i-1]; a[0] := v;
[Название файла: taskArray9.pas ]
Перестановка элементов в массиве
Рассмотрим, как происходит перестановка или реверс массива.
Пример: переставить элементы массива в обратном порядке
Решение:
Алгоритм:
alt=»алгоритм перестановки элементов массива» width=»500″ height=»81″ />
Псевдокод:
alt=»2″ width=»500″ height=»66″ />
Программа:
begin var a: array of integer := (1,3,5,7); var n := a.Length; for var i:=0 to n div 2 — 1 do Swap(a[i],a[n-i-1]); End.
Решение 2 (стандартная процедура Reverse() ):
begin var a:=new integer[10]; a:=arrRandomInteger(10); print(a);// [41,81,84,63,12,26,88,25,36,72] Reverse(a); print(a) //[72,36,25,88,26,12,63,84,81,41] end.
[Название файла: taskArray10.pas ]
Выбор элементов и сохранение в другой массив
Пример: найти в массиве элементы, удовлетворяющие некоторому условию (например, отрицательные), и скопировать их в другой массив
Решение:
Вывод массива B:
writeln(‘Выбранные элементы’); for i:=1 to count-1 do write(B[i], ‘ ‘)
// . for var i := 0 to a.length — 1 do if a[i] < 0 then begin b[j] := a[i]; j += 1; end; SetLength(b, j);
[Название файла: taskArray11.pas ]
Сортировка элементов массива
- В таком типе сортировок массив представляется в виде воды, маленькие элементы — пузырьки в воде, которые всплывают наверх (самые легкие).
- При первой итерации цикла элементы массива попарно сравниваются между собой:предпоследний с последним, пред предпоследний с предпоследним и т.д. Если предшествующий элемент оказывается больше последующего, то производится их обмен.
- При второй итерации цикла нет надобности сравнивать последний элемент с предпоследним. Последний элемент уже стоит на своем месте, он самый большой. Значит, число сравнений будет на одно меньше. То же самое касается каждой последующей итерации.
for i:=1 to N-1 do begin for j:=N-1 downto i do if A[j] > A[j+1] then begin с := A[j]; A[j] := A[j+1]; A[j+1] := с; end; end;
for var i := 0 to arr.High — 1 do for var j := arr.High — 1 downto i do if arr[j] > arr[j + 1] then Swap(arr[j], arr[j + 1]);
[Название файла: taskArray12.pas ]
- в массиве ищется минимальный элемент и ставится на первое место (меняется местами с A[1]);
- среди оставшихся элементов также производится поиск минимального, который ставится на второе место (меняется местами с A[2]) и т.д.
for i := 1 to N-1 do begin min:= i ; for j:= i+1 to N do if A[j] < A[min] then min:=j; if min <> i then begin c:=A[i]; A[i]:=A[min]; A[min]:=c; end; end;
for var i := 0 to a.High-1 do begin var (min,imin) := (a[i],i); for var j := i + 1 to a.High do if a[j] < min then (min,imin) := (a[j],j); Swap(a[imin],a[i]); end;
[Название файла: taskArray13.pas ]
- Выбирается и запоминается средний элемент массива (присвоим X):
Рубрики:
7 комментариев
Bronislav
См. пузырьковая сортировка.
При второй итерации цикла (согласно вашим рисункам и коду ) нет надобности сравнивать первый элемент со вторым. Снова вы всех путаете =)
admin
Именно поэтому в коде : for j:=N-1 downto i do
downto i — то есть мы доходим сначала до первого элемента, потом до второго и т.д.
Bronislav
Смотрите. Ваш код работает. Но работает не так, как вы пишете перед этим. Он просеивает минимальный элемент с конца через весь массив до первой позиции (первого индекса если хотите). А не так как вы пишете: «При второй итерации цикла нет надобности сравнивать последний элемент с предпоследним. Последний элемент уже стоит на своем месте, он самый большой.» Соответственно вашему коду и вашим рисункам на второй итерации не сравнивается первый элемент (минимальный) со вторым, а не последний (который вообще не факт что максимальный) с предпоследним. Вот об чем речь. Или код меняйте или описание алгоритма перед кодом.
Владимир
А как насчёт странного способа поменки оандомням образом, конечно это долго , но все таки есть
Var
A: array[1..10] of integer;
I,e,r,r1: integer;
Begin
While i < 10 do begin
I+=1;
A[i]:=random(10);
Write(a[i]:3);
End;
While e = 0 do begin
R:=random(10)+1;
R1:=random(10)+1;
Swap(a[r], a[r1]);
E:=1
I:=0;
// Проверка отсортированности если все хорошо то е равен одному и в следующий раз из цикла выйдется а если не отсортированности то ставится на нуль и ещё раз
While i < 9 do begin
I+=1;
If a[i] < a[i+1] then e:=0;
End;
End;
End.
В сохранении в другой массив ошибка. Надо поменять местами счётчик и команду сохранения. В массиве В нет элемента 0.
Aurangzeb
А как заполнить случайными числами (из файла!) такой массив: Type mass=array[1..n] of smallint; var A:array[1..n] of mass… В файле они введены, допустим, квадратно! Потом её нужно перевернуть и записать в выходной файл! Подумайте!
Random и Randomize
Функция Random генерирует и возвращает случайное число. Синтаксис функции следующий:
Функция возвращает случайное число большее или равное 0 и строго меньше L (то есть L не входит в диапазон возвращаемых значений). Если параметр опущен (последний вариант из трёх приведённых выше), то возвращается вещественное число между 0 и 1 (0 включительно, 1 не входит в диапазон возвращаемых значений).
Математически это можно записать так:
ПРИМЕЧАНИЕ
FreePascal использует в процедуре Random имитацию случайностей Мерсенна Твистера. Эта реализация имеет большее статистическое распределение, чем, например, алгоритм Линейного Конгруэнтного генератора, но работает значительно медленнее, чем последний. Если скорость выполнения программы критична, то должны быть рассмотрены альтернативные генераторы случайных чисел.
Процедура Randomize в Паскале запускает генератор случайных чисел. Синтаксис:
Процедура Randomize инициализирует генератор случайных чисел FreePascal, задавая значение переменной Randseed, вычисленное с помощью системных часов.
Как запустить генератор случайных чисел в Паскале
Пример программы, где используются разные варианты получения случайных чисел, приведён ниже:
ВАЖНО!
Перед использованием функции Random надо обязательно вызвать процедуру Randomize, чтобы запустить генератор случайных чисел. Иначе функция Random будет возвращать НЕ случайное число.
Процедура Randomize вызывается ТОЛЬКО ОДИН РАЗ в начале программы. Типичная ошибка новичков заключается в том, что они вызывают Randomize перед каждым вызовом Random. Этого делать не надо.
Что такое Randseed
Давайте сначала попробуем не использовать процедуру Randomize. Например, так:
В этом примере функция Random будет возвращать какое-то значение, но оно НЕ будет случайным числом. Сколько бы раз вы не запускали программу, она всегда будет выводить одинаковые числа.
В моём случае это были числа 54 и 59. В вашем случае это могут быть другие числа, но суть не в этом, а в том, что они будут всегда одинаковыми.
Теперь попробуем сделать так:
Теперь числа будут другими. В моём случае 69 и 7. Правда, они тоже не будут изменяться, то есть не будут случайными.
Однако эти числа изменились. Потому что мы изменили значение глобальной переменной Randseed.
Переменная Randseed — это глобальная предопределённая переменная в FreePascal. Она также есть и в Делфи. Так что всё сказанное будет справедливо и для Делфи.
Эта переменная задаёт начальное значение для генератора случайных чисел. Опираясь на это значение функция Random генерирует случайное число. Но, если значение переменной Randseed будет всегда одинаковым, то никаких случайных чисел мы не получим.
Поэтому при запуске программы надо хотя бы один раз вызвать процедуру Randomize, которая устанавливает начальное значение переменной Randseed, получая системное время и из этих данных формируя значение для переменной Randseed.
Так как программа запускается в какое-то случайное время, то и значение переменной Randseed будет случайным. А, следовательно, и функция Random будет возвращать случайные значения.
Давайте попробуем написать свою процедуру Randomize. Она может быть, например, такой:
Я не буду в подробностях разъяснять работу процедуры DecodeTime. Скажу только, то она возвращает, час, минуту, секунду и миллисекунду текущего времени компьютера. Мы используем миллисекунду, значение которой и присваиваем переменной Randseed.
Можете попробовать использовать эту процедуру вместо стандартной процедуры Randomize и убедиться, что функция Random возвращает случайные значения. Не забудьте подключить к программе модуль SysUtils, в котором объявлена процедура DecodeTime, иначе программа не откомпилируется.
ПРИМЕЧАНИЕ
Исходя из того, что процедура Randomize задаёт начальное значение переменной Randseed на основе текущего времени компьютера, можно предположить, что, например, если запустить программу сегодня в 12:00:00 и завтра в это же время, то функция Random вернёт одинаковые числа.
К сожалению, проверить это очень трудно, так как запустить программу в одно и то же время с точностью до миллисекунды будет практически невозможно.
Generating Random Numbers
Random numbers are important resources for a diverse field of applications, including scientific analysis, technology, medicine, economy, education, game development and visualization. They play a key role in numeric simulation.
Algorithm-generated random numbers are pseudo-random numbers. They belong to a (large) set of repeating numbers, whose sequence is impossible or at least difficult to predict. Unlike Delphi, that uses a linear congruential generator.(See Delphi compatible LCG Random), Free Pascal uses a MersenneTwister algorithm for its standard random function as defined in RTL. Before its first use, FPC’s random number generator has to be initialized with a single call of the randomize function, which sets the seed of the generator. Preferably this is done in the launch phase of the program.
Alternatively, on Unix- and Linux-based systems, the virtual devices /dev/random and /dev/urandom are available. They generate (pseudo) random numbers based on hardware.
A third option is to use random numbers from external sources, either from specialised hardware devices or from public sources, e.g. based on radioactive decay data.
Contents
Uniform Distribution
The continuous uniform distribution (also referred to as rectangular distribution) represents a family of symmetric probability distributions. Here, for each member of the family all intervals of the same length on the distribution’s support are equally probable.
The standard RTL function random generates random numbers that fulfill a uniform distribution. If called without parameter random delivers a floating point pseudorandom number in the interval [0, 1), i.e. 0 <= result < 1. if random is called with a longint argument L it delivers a longint random in the interval [0, L).
A further set of uniformly distributed random number generators is presented in Marsaglia’s pseudo random number generators.
Uniformly distributed random numbers are not useful for every application. In order to create random numbers of other distributions special algorithms are necessary:
Normal (Gaussian) Distribution
One of the more common algorithms to produce normally distributed random numbers from uniformly distributed random numbers is the Box-Müller approach. The following function calculates Gaussian-distributed random numbers:
The same algorithm is used by the randg randg function from the RTL math unit:
Exponential Distribution
An exponential distribution occurs frequently in real-world problems. A classical example is the distribution of waiting times between independent Poisson-random events, e.g. the radioactive decay of nuclei [Press et al. 1989].
The following function delivers a single real random number out of an exponential distribution. Rate is the inverse of the mean, and the constant RESOLUTION determines the granularity of generated random numbers.
Gamma Distribution
The gamma distribution is a two-parameter family of continuous random distributions. It is a generalization of both the exponential distribution and the Erlang distribution. Possible applications of the gamma distribution include modelling and simulation of waiting lines, or queues, and actuarial science.
The following function delivers a single real random number out of a gamma distribution. The shape of the distribution is defined by the parameters a, b and c. The function makes use of the function randomExp as defined above.
Erlang Distribution
The Erlang distribution is a two parameter family of continuous probability distributions. It is a generalization of the exponential distribution and a special case of the gamma distribution, where c is an integer. The Erlang distribution has been first described by Agner Krarup Erlang in order to model the time interval between telephone calls. It is used for queuing theory and for simulating waiting lines.
Poisson Distribution
The Poisson distribution applies to integer values. It represents the probability of k successes, when the probability of a success in each trial is small and the rate of occurrence (the mean value) is constant.
t Distribution
The t distribution (also referred to a Student’s t distribution, since it was published by William Sealy Gosset in 1908 under the pseudonym Student) is a continuous probability distribution. Its shape is defined by one parameter, the degrees of freedom (df). In statistics, many estimators are t distributed. Therefore, Student’s t-distribution plays a major role in a number of widely used statistical analyses, including Student’s t-test for assessing the statistical significance of the difference between two sample means, the construction of confidence intervals for the difference between two population means, and in linear regression analysis. The t-distribution also arises in Bayesian analysis of data from a normal family.
The following algorithm depends on the RTL function random and on the randomChisq function
Chi Squared Distribution
The chi squared distribution is a continuous distribution of random numbers with df degrees of freedom. It is the distribution of a sum of the squares of df independent standard normal random variables. The chi squared distribution has numerous applications in inferential statistics, e.g. in estimating variances and for chi-squared tests. It is a special gamma distribution with c = df/ 2 and b = 2. Therefore the following function depends on the function randomGamma.
F Distribution
The F distribution, also referred to as Fisher-Snedecor distribution, is a continuous probability distribution. It is used for F Test and ANOVA. It has two degrees of freedom that serve as shape parameters v and w and that are positive integers. The following function randomF makes use of randomChisq.