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

Модератор: push0ret

Ответить
Аватара пользователя
push0ret
Набирающий обороты
Сообщения: 23
Зарегистрирован: Вс дек 29, 2024 2:48 pm
Благодарил (а): 12 раз
Поблагодарили: 22 раза

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

Сообщение push0ret »

Hello, world!

Решил рассказать немного о генерации псевдослучайных чисел. Почему псевдослучайных? Потому что все "случайные" числа в компьютере получают с помощью математических выражений, у процессора нет понятия "случайный", т.к. это устройство, которое работает по своим, строго заданным, правилам.

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

Есть множество алгоритмов генерации псевдослучайных чисел (XorShift, линейный конгруэнтный генератор, перемешанный конгруэнтный генератор и т.д.), они имеют разную скорость генерации чисел, также у генераторов псевдослучайных чисел есть математическая (через некоторое количество сгенерированных чисел, числа начнут повторяться), а также, зная алгоритм, можно получить исходное число, которое было преобразовано в псевдослучайное.

К генераторам псевдослучайных чисел можно отнести и HASH - функции, отличие от генераторов псевдослучайных чисел заключается в том, что обратного алгоритма для получения исходного числа не существует, например, многие знакомы или слышали про алгоритм MD5, а также есть такие популярные алгоритмы, как MurMur3 и WangHash.

Я покажу генерацию псевдослучайных чисел на примере алгоритма Парка - Миллера, математическое выражение таково: I(j+1)=a*I(j)(mod m). Это математическое выражение я упростил до I= (seed*a) mod m, в котором seed - это исходное число, которое будет преобразовано в число в диапазоне от 0 до m. Есть два значения числа а, которые используются в генераторе Парка - Миллера, это 48271 или число 65537, использовать можно любое на своё усмотрение. При генерации нескольких чисел, seed всегда является предыдущим сгенерированным числом.

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

Давайте напишем процедуру генерации псевдослучайных чисел и получим псевдослучайную строку на экране:

Код: Выделить всё

.model	tiny
.286
code	segment
org	100h

start:

mov cx, 80d
lea di, msg

write_array:

push 30h							;минимальное число  } диапазон
push 122d							;максимальное число } чисел
call random

mov byte ptr[di], al
inc di

loop write_array

mov ah, 9d
lea dx, msg
int 21h

mov ax, 4c00h
int 21h

msg	db	81d dup(24h)

;--------------------------------------
;Generate random numbers
;Input(Stack):
;-Minimal number in range(0-65535);
;-Maximum number in range(0-65535);
;Out:
;-Number in ax

random	proc	uses bp dx bx

mov bp, sp

mov ax, word ptr ss:[bp+8]			;максимальное число в заданном диапазоне 
mov m, ax					;записать в переменную m

mov ax, strt						

cmp ax, -1d					;проверить seed, если не равен -1
jnz randomize					;то начать преобразование

push ds						;если равен -1, то получить число
push 40h					;из области памяти BIOS
pop ds
mov ax, word ptr ds:[006Ch]
pop ds
mov strt, ax

randomize:

mov bx, a					;(a * seed)/m
mul bx
xor dx, dx
mov bx, m
div bx
mov strt, dx					;записать полученное число в переменную strt, это будет seed 
						;для последующих вызовов процедуры
cmp dx, ss:[bp+10]				;сравнить с минимальным числом в заданном диапазоне
jb randomize					если полученное число меньше, то повторить преобразование

mov ax, dx

ret 4

a		dw	48271
m		dw	0
strt		dw	-1d

random	endp

code	ends
end	start
Результат работы программы:
random_string.PNG
random_string.PNG (25.85 КБ) 141 просмотр
Получилось не очень случайно, так как выражение упрощено, давайте уберём из алгоритма "запоминание" числа seed и добавим в программу задержку, которая будет позволять изменить счётчику времени значение:

Код: Выделить всё

.model  tiny
.286
code    segment
org     100h

start:

mov cx, 80d
lea di, msg

write_array:

push 30h
push 122d
call random

mov byte ptr[di], al
inc di

call delay						;Процедура задержки

loop write_array

mov ah, 9d
lea dx, msg
int 21h

mov ax, 4c00h
int 21h

msg     db      81d dup(24h)

delay   proc    uses ds ax bx

push 40h                                                        
pop ds
mov ax, word ptr ds:[006Ch]

delay_:

push 40h                                                        
pop ds
mov bx, word ptr ds:[006Ch]

cmp al, bl
jz delay_

ret

delay   endp

;--------------------------------------
;Generate random numbers
;Input(Stack):
;-Minimal number in range(0-65535);
;-Maximum number in range(0-65535);
;Out:
;-Number in ax

random  proc    uses bp dx bx

mov bp, sp

mov ax, word ptr ss:[bp+8]                            ;максимальное число в заданном диапазоне 
mov m, ax                                             ;записать в переменную m

get_num:

push ds                                               ;если равен -1, то получить число
push 40h                                              ;из области памяти BIOS
pop ds
mov ax, word ptr ds:[006Ch]
pop ds

randomize:

mov bx, a                                             ;(a * seed)/m
mul bx
xor dx, dx
mov bx, m
div bx

cmp dx, ss:[bp+10]                                    ;сравнить с минимальным числом в заданном диапазоне
jb get_num                                            ;если полученное число меньше, то 			 
                                                      ;повторить преобразование
						      ;получив новое число из области 
						      ;памяти BIOS							

mov ax, dx

ret 4

a               dw      48271
m               dw      0
strt            dw      -1d

random  endp

code    ends
end     start
Результат:
random_string2.PNG
random_string2.PNG (31.08 КБ) 141 просмотр
Как можно видеть, разнообразие чисел очень сильно выросло, но мы пожертвовали временем выполнения программы, теперь программа выполняется гораздо дольше.

Это простой алгоритм генерации псевдослучайных чисел, есть много других алгоритмов, все они отличаются, вы можете использовать любой, который будет подходить под ваши задачи.

Была использована версия компилятора MASM 6.11 в контексте операционной системы MS DOS 6.22!

Спасибо за внимание!
С уважением, push0ret!
Ответить

Вернуться в «Системное программирование»