Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.02.17;
Скачать: CL | DM;

Вниз

Генератор случайных чисел   Найти похожие ветки 

 
Norfolk ©   (2004-02-07 12:19) [0]

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


 
Randomizer   (2004-02-07 12:32) [1]

Покажи, что ты сделал и тебе укажут на ошибку.

Другого способа так сразу и не предложишь...


 
Начинающий веб-дизайнер ©   (2004-02-07 12:33) [2]

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

3. Динамический массив заполняешь числами в порядке возрастания.
По нажатию на кнопку генерируешь случайное число в диапазоне индексов массива, выводишь соответствующий элемент массива на экран, после чего удаляешь его из массива. Как только длина массива станет равной 0 значит числа кончились


 
Norfolk ©   (2004-02-07 13:36) [3]


> Покажи, что ты сделал и тебе укажут на ошибку.

Сделал я примерно так:

var
TestIndex: array [0..49] of byte;
i, j: byte;
...
...
procedure TTesterForm.NextBtnClick(Sender: TObject);
var
k: byte;
begin
Randomize;
i := Random(49);{Здесь немного не так, вместо 49 стоит значение из файла}
for k:=0 to j do
begin
if TestIndex[k]=i then
i := Random(49);
end;
j := j+1;
...{В этой строчке выводим результат}
end;
...

Собственно в чём ошибка я понял. В цикле снова генерируется случайное число если был найден элемент массива равный сгенерированному ранее числу. Но число сгенерированное в цикле далее не проверяется с элементами массива, стоящими до текущего.
Следующим моим шагом было создание вложенного цикла, чтобы проверка происходила сначала цикла несколько раз, но и это не помогло, просто частота появления одинаковых чисел немного уменьшилась:

for p := 0 to 10 do
for k := 0 to i do


 
Norfolk ©   (2004-02-07 13:39) [4]


> 2. Заполняешь статический массив числами равными индексу,
> потом хорошенько перемешиваешь этот массив, потом берёшь
> из него элементы по порядку, как дойдёшь до конца массива
> - всё.

Если сделать так, то при каждом запуске программы будет одна и таже последовательность числел, что нехорошо.
А за ответ спасибо.


 
Anatoly Podgoretsky ©   (2004-02-07 13:49) [5]

Нет последовательность будет каждый раз разная, вот только уточни, что может быть вместо Random(49)


 
Norfolk ©   (2004-02-07 13:58) [6]


> что может быть вместо Random(49)

Вместо Random(49) у меня Random(Test[0].Many) Где Test[0].Many массив типа записи, взятый из файла. Для конкретного файла эта величина постоянная, но программе приходиться работать с разными файлами.


 
Начинающий веб-дизайнер ©   (2004-02-07 14:03) [7]


> Если сделать так, то при каждом запуске программы будет
> одна и таже последовательность числел, что нехорошо.

- всё зависит от того как перемешивать.

Как то я делал такое, тоже заносил сгенерированные числа в массив, там примерно такой алгоритм

function ЧИСЛОЕСТЬВМАССИВЕ(ЧИСЛО): boolean;
begin
Result:= False;
for i:= 0 to Count-1 do
begin
Result:= ЧИСЛО = Массив[i];
if Result then Break
end;
end;

procedure ГЕНЕРАЦИЯЧИСЛА
begin
if ДЛИНАМАССИВА=ДИАПАЗОН then
ВЫХОД
else
begin
ЧИСЛО:= Random(ДИАПАЗОН);
while ЧИСЛОЕСТЬВМАССИВЕ(ЧИСЛО)
ЧИСЛО:= Random(ДИАПАЗОН);
ДОБАВИТЬВМАССИВ(ЧИСЛО);
ВЫВЕСТИ(ЧИСЛО);
end;
end;


 
Начинающий веб-дизайнер ©   (2004-02-07 14:10) [8]

Но при больших диапазонах будет долго думать, или вообще функция RANDOM может не выдать нужного числа, лучше способы 2 или 3


 
Norfolk ©   (2004-02-08 13:55) [9]


> Как то я делал такое, тоже заносил сгенерированные числа
> в массив, там примерно такой алгоритм

Вот то, что я написал по представленному Вами алгоритму:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ActnList;

function NumArray(Num: byte): boolean;

type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
ActionList1: TActionList;
Action1: TAction;
procedure Button1Click(Sender: TObject);
procedure Action1Execute(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
Arr: array of byte;

implementation

{$R *.dfm}

function NumArray(Num: byte): boolean;
var
i: byte;
begin
Result := False;
for i := 0 to Length(Arr) do
begin
Result := Num=Arr[i];
if Result then Break
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
Num: byte;
begin
if Length(Arr)=10 then
Close
else
begin
Randomize;
Num := Random(9);
while NumArray(Num) do
Num := Random(9);
SetLength(Arr, Length(Arr)+1);
Arr[Length(Arr)] := Num;
Edit1.Text := IntToStr(Num);
end;
end;

procedure TForm1.Action1Execute(Sender: TObject);
begin
SetLength(Arr,1);
end;

end.

Программа работает, только вот числа всё равно повторяются, кроме того программа при закрытии выдаёт ошибку RunTime error и какой-то номер.


 
Ilg   (2004-02-08 14:51) [10]

Скорее всего ошибку создает строка
Arr[Length(Arr)] := Num;,
т. к. номера массива идут с 0.
Если ты хочешь, присваивать значение последнему элементу - делай так:
Arr[High(Arr)] := Num;


 
MBo ©   (2004-02-08 14:53) [11]

http://mbo88.narod.ru/RND.ZIP


 
Mihey ©   (2004-02-08 16:14) [12]

Заполнение массива случайными неповторяющимися числами:

procedure FillArray(var A: array of Integer);
var
I, S, R: Integer;
begin
for I := 0 to High(A) do A[I] := I;
for i := High(A) downto 0 do begin
R := Random(I);
S := A[R]; A[R] := A[I]; A[I] := S;
end;
end;

Быстрои сердито, безо всяких сравнений.


 
Fenik ©   (2004-02-08 16:27) [13]

>Mihey © (08.02.04 16:14) [12]

По-моему, это не совсем случайные числа будут.


 
MBo ©   (2004-02-08 16:41) [14]

>Fenik
числа от 0 до N-1 будут перемешаны.
Другое дело, что набор возможных комбинаций будет не абсолютно равномерным, но это обычно допустимо.


 
Fenik ©   (2004-02-08 16:47) [15]

Вот, что выдал алгоритм Михея:
0 - 3
1 - 2
2 - 4
3 - 5
4 - 7
5 - 9
6 - 8
7 - 6
8 - 0
9 - 1


А если мне нужно массив [0..9] заполнить неповторяющимися случайными числами из отрезка [1500..100000]?


 
MBo ©   (2004-02-08 16:54) [16]

>Fenik
для отрезка N...M
Rnd = N+(M-N)*MiheyNumber/10+Random((M-N)/10)


 
Fenik ©   (2004-02-08 17:12) [17]

>MBo © (08.02.04 16:54) [16]
>Rnd = N+(M-N)*MiheyNumber/10+Random((M-N)/10)

Нифига.
Результат:
<cite>0 - 16
1 - 22
2 - 10
3 - 12
4 - 16
5 - 20
6 - 14
7 - 24
8 - 18
9 - 23

Код:

procedure FillArray(var A: array of Integer);
var
I, S, R: Integer;
begin
for I := 0 to High(A) do A[I] := I;
for i := High(A) downto 0 do begin
R := Random(I);
S := A[R]; A[R] := A[I]; A[I] := S;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const n = 10;
m = 25;
var A: array of Integer;
i, rnd: Integer;
begin
Randomize;
SetLength(A, 10);
FillArray(A);
for i := 0 to High(A) do begin
rnd := Round(N+(M-N)*A[i]/10+Random(Round((M-N)/10)));
Memo1.Lines.Add(Format("%d - %d", [i, Rnd]));
end;
end;</cite>


 
MBo ©   (2004-02-08 17:22) [18]

И что значит >Нифига. ?
Получено 10 неповторяющихся чисел в диапазоне 10-25, как и нужно было.
недостаток - предложенный примитивный метод дает равномерное распределение.


 
Fenik ©   (2004-02-08 17:27) [19]

>MBo © (08.02.04 17:22) [18]

:))
Галюцинации у меня, однако. Минуту назад я видел там две пары повторяющихся.. А сейчас их нет.


 
Fenik ©   (2004-02-08 19:01) [20]

Аааааа!! Блин, теперь точно вижу!

0 - 16
1 - 22
2 - 10
3 - 12
4 - 16


 
Mihey ©   (2004-02-08 20:17) [21]

2 Fenik:

Весьма странно. Алгоритм я проверял так:

procedure TForm1.Button1Click(Sender: TObject);
var a: array [0..30] of Integer;
i, k, l: Integer;
begin
Randomize;
for l := 1 to 50000 do
begin
for i := 0 to High(a) do
begin
a[i] := 0;
end;
FillArray(a);
for i := 0 to High(a) do
begin
for k := 0 to High(a) do
begin
If (a[i] = a[k]) and (i <> k) then
begin
ShowMessage("You are a big bad niggar!!!!");
Abort;
end;
end;
end;
end;
ShowMessage("Finished");
end;

Раз десять, ни разу совпадения.


 
Думкин ©   (2004-02-08 21:26) [22]

> [20] Fenik © (08.02.04 19:01)

Это из-за округлений. Для однозначности надо написать несколько иначе - МВо привел лишь схему.



Страницы: 1 вся ветка

Текущий архив: 2004.02.17;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.021 c
4-53812
Kinder
2003-12-08 22:16
2004.02.17
нажимаем кнопку Windows


8-53646
kvp
2003-10-20 12:52
2004.02.17
Повернуть элипс на произвольный угол


8-53650
Raph
2003-10-16 12:22
2004.02.17
Помогите с opengl


6-53672
MaG
2003-12-12 18:07
2004.02.17
Скачивание файлов


8-53645
Leon Crom
2003-10-17 11:34
2004.02.17
сжатие AVI