Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.02.17;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.5 MB
Время: 0.008 c
1-53522
turonix
2004-02-04 16:17
2004.02.17
Проблемы с компилятором


1-53505
Goblinus
2004-02-05 21:20
2004.02.17
Получение доступа к свойствам формы по её имени


3-53421
SerKom
2004-01-26 11:35
2004.02.17
округление в MS Access


1-53518
Genry
2004-02-05 15:43
2004.02.17
Зарегистрирован ли COM-объект ?


14-53697
MBo
2004-01-30 08:00
2004.02.17
Inventor of Ctrl-Alt-Delete combo is retiring from IBM





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский