Вот набросал тут реализацию на коленке.
Код на Blitz3D. Прошу комментариев и конструктивнйо критики. Осбенно, с точки зрения ТеорВер-а (т.к. вариант - первый, что пришёл в голову, вполне возможно, я что-то не учёл).
;генератор ДСВ, заданной таблицей от impersonalis (icq 11-999-51-51)
Function ImpRnd_DRVBankCreate%(PBankHandle%,turncnt%)
Local diskret#=PeekFloat(PBankHandle,0)
Local i%,j%,k%,t%
Local v#
For i=4 To BankSize(PBankHandle)-1 Step 4
v=PeekFloat(PBankHandle,i)
If v<diskret
diskret=v
EndIf
Next
Local diskret_cnt%=Ceil(1/diskret)
Local map%=CreateBank(diskret_cnt*4)
k=0
t=0
For i=0 To BankSize(PBankHandle)-1 Step 4
v=Floor(PeekFloat(PBankHandle,i)/diskret)
For j=1 To v
PokeInt(map,k,t)
k=k+4
Next
t=t+1
Next
For t=1 To turncnt
i=Rand(0,diskret_cnt-1)*4
j=Rand(0,diskret_cnt-1)*4
k=PeekInt(map,i)
PokeInt(map,i,PeekInt(map,j))
PokeInt(map,j,k)
Next
Return map
End Function
Function ImpRnd_DRVGet#(DRVBankHandle%,ValBankHandle%)
Local diskret_cnt%=BankSize(DRVBankHandle)/4
Local RINDX%=Rand(0,diskret_cnt-1)*4
Local CaseID%=PeekInt(DRVBankHandle,RINDX)
Return PeekFloat(ValBankHandle,CaseID*4)
End Function
Собственно, пример решения задачи:
Есть четрые числа: 12, 11.1, 56, 78. Необходимо: случайным образом возвращать числа из набора, учитывая, что веротяность выпадения чисел разная, а именно: 20%, 30%, 40% и 10% соотвественно.
Для наглядности, демо-код, слегка говнокоден:
SeedRnd MilliSecs()
Local A#=12
Local S#=11.1
Local D#=56
Local F#=78
Local B%=CreateBank(16)
PokeFloat(B,0,0.2)
PokeFloat(B,4,0.3)
PokeFloat(B,8,0.4)
PokeFloat(B,12,0.1)
Local V%=CreateBank(16)
PokeFloat(V,0,A)
PokeFloat(V,4,S)
PokeFloat(V,8,D)
PokeFloat(V,12,F)
Local prob%[4]
Local EXPCNT%=100
Local DRVB%=ImpRnd_DRVBankCreate(B,15)
For i=1 To EXPCNT
Local w#=ImpRnd_DRVGet(DRVB,V)
Select w
Case A
prob[0]=prob[0]+1
Case S
prob[1]=prob[1]+1
Case D
prob[2]=prob[2]+1
Case F
prob[3]=prob[3]+1
End Select
Next
For i=0 To 3
DebugLog Str(i+1)+"# "+prob[i]+" ~ "+Int(prob[i]*10/Float(EXPCNT))*0.1
Next
FreeBank(DRVB)
FreeBank(V)
FreeBank(B)
Function
ImpRnd_DRVBankCreate%(PBankHandle%,turncnt%)
PBankHandle - дескриптор банка, содержащего нормированные вероятности событий. Т.е., в нашем случае, 0.2, 0.3, 0.4 и 0.1.
turncnt - количество перестановок. Вообще говоря, от балды. Т.к.
Возвращает - сгенерированный банк для функции ImpRnd_DRVGet
Function
ImpRnd_DRVGet#(DRVBankHandle%,ValBankHandle%)
DRVBankHandle% - банк, сгенерированный функцией ImpRnd_DRVBankCreate
ValBankHandle% - банк, характеризующий каждое событие числом. В наше случае, это 12, 11.1, 56, 78.
Возвращает одно из чисел, указанных в ValBankHandle, с частотой, соотвествующей его веротяности.
Результаты выполнения демо-кода:
1# 23 ~ 0.2
2# 33 ~ 0.3
3# 37 ~ 0.4
4# 7 ~ 0.1
Как видим, каждое число вернулось нужное количество раз.
Аналогичную задачу проверёнм на другой таблице (0.01 0.5 0.09 0.4)
Скорректируем округление в выоде и получим:
для
1000 итераций:
1# 7 ~ 0.01
2# 498 ~ 0.5
3# 84 ~ 0.08
4# 411 ~ 0.41
для
10 000 итераций:
1# 95 ~ 0.01
2# 4964 ~ 0.5
3# 846 ~ 0.08
4# 4095 ~ 0.41
для
100 000 итераций:
1# 991 ~ 0.01
2# 50078 ~ 0.5
3# 8983 ~ 0.09
4# 39948 ~ 0.4