forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Болтовня (http://forum.boolean.name/forumdisplay.php?f=25)
-   -   Rnd... (http://forum.boolean.name/showthread.php?t=189)

Diplomat 11.10.2005 21:17

Забавная задачка:
Используя генератор Rnd, написать ф-ю, которая возвращала бы значения 1, 2 или 3 с равной вероятностью.
Код для подсчета вероятностей можно использовать вроде этого:
Код:

Dim Value(4)
For q=0 To 10000
 X=Rnd(3)
 Value(X)=Value(X)+1
Next
For q=0 To 4
 Print q+" возвращалось приблизительно в "+ Value(q)/100+"% случаев..."
Next
WaitKey()
End

P.S. Я не свихнулся, попробуйте сами. :lol:

SubZer0 11.10.2005 22:09

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

есть кривая (не помню какого ученого) показывающая, что числа в середине промежутка выпадают чаще, чем по краям, это уже давно всем известно... :rolleyes:

Diplomat 12.10.2005 00:06

Цитата:

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

В выводе формулы и заключалась задачка.:lol:
Формулу надо бы по идее вписать вместо "Rnd(3)"

Цитата:

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

Вот заче-е-ем было это говори-и-ить? Вот всю интригу испо-о-ортил! :'((
:lol:

Ладно, раз номер не прошел, тогда так:
Создать, на основе Rnd() ф-ю, которая возвращала бы 1,2 или 3 с близкой вероятностью.

P.S. Сядьте и потестите варианты; не зря ведь говорю, не просто прикалываюсь: последовательности вероятностей можно получить очень интригующие. ;)

SubZer0 12.10.2005 00:26

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

Код:

Dim Value(4)
For q=0 To 10000
 X=aRnd(1,4)
 Value(X)=Value(X)+1
Next
For q=0 To 4
 Print q+" возвращалось приблизительно в "+ Value(q)/100+"% случаев..."
Next
WaitKey()
End


function arnd%(b%,e%)

b1%=-b%*10
e1%=e%*10

repeat

 r%=rnd(b1%,e1%)

until r%>=b% and r%<=e%

return r%

end function

вот, накидал в броузере... хз пойдет или нет... но алгоритм думаю ясен...

в алгоритме есть охренительный недостаток... будет очень медленно работать...

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

pax 12.10.2005 00:36

Ну если использовать счетчики как в первом примере, то можно найти в них наибольщую и наименьшую вероятность и если они отличаются друг от друга больше ну скажем чем на заданную величину (например 5%) то возвращать число которое соответствует наименьшей вероятности, а если разница меньше заданной то использовать оператор Rand()

Больше ничего в голову не лезет :)

SubZer0 12.10.2005 00:48

ага, придумал как график рвать:

Код:

Dim Value(4)
For q=0 To 10000
X=aRnd(1,4)
Value(X)=Value(X)+1
Next
For q=0 To 4
Print q+" возвращалось приблизительно в "+ Value(q)/100+"% случаев..."
Next
WaitKey()
End


function arnd%(b%,e%)

r%=rnd(b%,e%*2)

if r>e then r=r-e

return r%
end function

по скорости работы побыстрей и график гораздо ровнее чем в простом rnd :rolleyes:

надо теперь совместить два метода и все. ;)

Diplomat 12.10.2005 00:54

Вах, хитрые методы! У меня всё намного прозаичнее, даже стыдно становится выкладывать свою идею...
Давайте, еще подожду пару идей- и раскроюсь, если не отгадаете...
А если придумаете лучше- выдам за свою идею!/шутка/:))

P.S. Задачка хоть и прикол, но ИМХО вопрос довольно важен. Многое делается с помощью псевдослучайных чисел Rnd(), и важно, чтоб они были действительно хоть и псевдо-, но случайными... :)

SubZer0 12.10.2005 00:54

совместив два метода получил следующий:
Код:

Dim Value(4)
For q=0 To 10000
X=aRnd(1,4)
Value(X)=Value(X)+1
Next
For q=0 To 4
Print q+" возвращалось приблизительно в "+ Value(q)/100+"% случаев..."
Next
WaitKey()
End


function arnd%(b%,e%)



b1%=-b%*10
e1%=e%*20

repeat

r%=rnd(b1%,e1%)

until r%>=b% and r%<=e%

if r>e then r=r-e

return r%
end function

результат - супер! скорость работы - подбирается коэффициентами умножения... тут типа движок <Скорость> -----0----- <Ровнее график> чемто надо жертвовать..

pax 12.10.2005 01:04

А вот что я придумал :
Код:

Dim Value(4)
For q=0 To 1000000
X=arnd(1,4)
Value(X)=Value(X)+1
Next
For q=0 To 4
Print q+" возвращалось приблизительно в "+ Value(q)/100+"% случаев..."
Next
WaitKey()
End


Function arnd%(b%,e%)
If Rand(0,1) Then
        Return Rnd(b%,e%/2)
Else
        Return Rnd(e%/2+1,e%)
EndIf
End Function

На большом количестве испытаний показывает почти одинаковые результаты :)

Jet 12.10.2005 08:41

последние коды - в ФАК однозначно!

alcosholik 12.10.2005 09:43

http://community.boolean.name/index.php?ac...&st=0#entry1582 :ok:

Diplomat 12.10.2005 13:13

1. Прост до глупости. Работает соответственно. :)
Код:

Dim Value(4)
For q=0 To 100000
 X=Rnd(3000)
 X=X/1000+1
 Value(X)=Value(X)+1
Next
For q=0 To 4
 Print q+" возвращалось приблизительно в "+ Value(q)/1000+"% случаев..."
Next
WaitKey()

2. Работает на основе исправления "глюков" округления
Код:

Dim Value(4)
For q=0 To 10000
 X=aRnd(2)+1
 Value(X)=Value(X)+1
Next
For q=0 To 4
 Print q+" возвращалось приблизительно в "+ Value(q)/100+"% случаев..."
Next
WaitKey()

Function aRnd(RndValue#)
        RndCounter=Rnd(RndValue+1)
        If RndCounter=RndValue+1 Then RndCounter=0
        Return RndCounter
End Function

Вот такие пироги... ;)

pax 12.10.2005 22:14

По моему вообже не надо никаких новых функций, до этого мы еще вчера с SubZer0 додумались, надо просто вызывать функцию Rnd следующим образом:

Код:

Rnd(0.5,3.5)
или
Rand(1,3)

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

Просто в твоем первом примере на числа 1 и 2 отводился промежуток в два раза меньше, чем на 2 (от 1 до 1.5 - для единици, от 1.5 до 2.5 - для двойки и 2.5 до 3 для тройки).

SubZer0 12.10.2005 23:49

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

попробуйте запустить вот такой код...

Код:

seedrnd millisecs()

Dim Value(20)
For q=0 To 10000
X=Rnd(20)
Value(X)=Value(X)+1
Next
For q=0 To 20
Print q+" возвращалось приблизительно в "+ Value(q)/100+"% случаев..."
Next
WaitKey()
end

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

Diplomat 13.10.2005 00:20

:))
Не считая крайних, он и не дает. Но на малом диапазоне эти крайние могут сильно портить нервы, если не юзать "хитрометоды". Зато теперь таких приемов предостаточно: и больше никто не будет ломать голову и ценное оборудование. :ok:

Кстати, если генератор случайных, работающий в заданом узком диапазоне, вызывается изредка и асинхронно (к примеру, для выбора фразы-ответа юнита или там анимации падения врага), то проще вообще юзать что то подобное:
Код:

Dim Value(4)
While q<10000
 RndCounter= RndCounter+1
 If RndCounter>3 Then RndCounter=1
 If Rnd(10)<2 Then;эта строка иммитирует асинхронные вызовы.
 q=q+1
 X=RndCounter
 Value(X)=Value(X)+1
 EndIf
Wend
For q=0 To 4
Print q+" возвращалось приблизительно в "+ Value(q)/100+"% случаев..."
Next
WaitKey()

P.S. Потому я задачку и называл "забавной" и поселил в Болтовню, что в ней мирно уживаются два маленьких подвоха. ;)


Часовой пояс GMT +4, время: 07:09.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot