Еще один генератор случайных чисел на Ассемблере
В закромах Родины нашлась реализация еще одного генератора случайных чисел. Он более громоздкий, чем минимальный генератор Парка-Миллера, использует операции с плавающей точкой и кольцевой буфер, но результаты выдает гораздо лучше. Кроме большого кода ему также требуется больше места и в сегменте данных:Code (Assembler) : Убрать нумерацию
- section '.data' data readable writeable
- ; Данные для генератора случайных чисел
- JJ = 10 ; lag 1
- KK = 17 ; lag 2, size of circular buffer
- R1 = 19 ; rotate count
- R2 = 27 ; rotate count
- randp1 dt 1.5 ; used for conversion to float
- dw 0 ; alignment
- p1 dd 0 ; pointer in circular buffer
- p2 dd 0 ; pointer in circular buffer
- randbuf dd (2*KK) dup(?) ; circular buffer
Code (Assembler) : Убрать нумерацию
- ; Инициализация генератора случайных чисел
- invoke GetTickCount
- stdcall WRandomInit,eax
- ...
Code (Assembler) : Убрать нумерацию
- ; Получить случайное число
- stdcall WRandom
- ; В регистрах EDX:EAX случайное число
- ...
- ; Получить случайное число от 1000 до 100000
- stdcall WIRandom,1000,100000
- ; В регистре EAX случайное число
- ...
Code (Assembler) : Убрать нумерацию
- ;---------------------------------------------
- ; Получить случайное число
- ; stdcall WRandom
- ; на выходе EDX:EAX - случайное число
- ;---------------------------------------------
- proc WRandom
- stdcall WBRandom
- or edx, 80000000h
- mov dword [randp1],eax
- mov dword [randp1+4],edx
- fld1
- fld [randp1]
- ret
- endp
- ;---------------------------------------------
- ; Получить случайное число в нужном интервале
- ; stdcall WIRandom,min,max
- ; на выходе EAX - случайное число
- ; EAX=80000000h - ошибка
- ;---------------------------------------------
- proc WIRandom rmin:dword,rmax:dword
- push ebx
- stdcall WBRandom
- ; Проверить корректность задания границ, MIN<MAX
- mov ebx,[rmax]
- sub ebx,[rmin]
- js .WIRandom_1
- inc ebx
- mov ecx,edx
- mul ebx
- mov eax,ecx
- mov ecx,edx
- mul ebx
- add eax,ecx
- adc edx,[rmin]
- mov eax,edx
- pop ebx
- ret
- .WIRandom_1:
- mov eax,80000000h
- pop ebx
- ret
- endp
- ;---------------------------------------------
- ; Инициализация генератора случайных чисел
- ; stdcall WRandomInit,seed
- ;---------------------------------------------
- proc WRandomInit seed:dword
- mov eax,[seed]
- xor ecx,ecx
- .WRandomInit_1:
- imul eax,2891336453
- inc eax
- mov [randbuf+ecx*4],eax
- inc ecx
- cmp ecx,KK*2
- JB .WRandomInit_1
- fld1
- fstp [randp1]
- mov [p1],0
- mov [p2],JJ*8
- stdcall WBRandom
- push edi
- mov edi,30
- .WRandomInit_2:
- stdcall WBRandom
- dec edi
- jnz .WRandomInit_2
- pop edi
- ret
- endp
- ;---------------------------------------------
- ; Вспомогательная процедура генератора
- ; В пользовательском не вызывается
- ;---------------------------------------------
- proc WBRandom
- push ebx
- mov ebx, [p1]
- mov ecx, [p2]
- mov edx, [randbuf+ebx]
- mov eax, [randbuf+ebx+4]
- rol edx, R1
- rol eax, R2
- add edx, [randbuf+ecx]
- add eax, [randbuf+ecx+4]
- mov [randbuf+ebx], eax
- mov [randbuf+ebx+4], edx
- sub ebx, 8
- jnc .WBRandom_1
- mov ebx, (KK-1)*8
- .WBRandom_1:
- sub ecx, 8
- jnc .WBRandom_2
- mov ecx, (KK-1)*8
- .WBRandom_2:
- mov [p1], ebx
- mov [p2], ecx
- pop ebx
- ret
- endp
Просмотров: 11500 | Комментариев: 10
Метки: Assembler, генератор ПСЧ
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Grey
(01.10.2015 в 16:40):
СЛЧИС() и другая по мелким делам устраивают. Иногда (я так и не понял при каких обстоятельствах) они дают повтор последовательности один в один. На vscript, штатная Rnd() вообще 100% повтор дает при новом запуске, а СЛЧИС() имхо на ее основе построена. Мы тут модель вероятностную в екселе сделали, чисел больше 100 000 плюс еще другие формулы, она повторы дает, может глюк какой. В общем выпала из доверия.
ManHunter
(01.10.2015 в 15:54):
Чем не устроили штатные =СЛЧИС() или =СЛУЧМЕЖДУ(1;100) ?
GetTickCount используется для инициализации ГПСЧ, то есть должна вызываться только один раз и обязательно где-то за пределами функции получения случайного числа. Да и заменить ее нечем, в винде не предусмотрено системных функций для получения случайных значений. Под MS-DOS была изумительная по лаконичности команда для получения случайного байта "in al,40h", а тут увы.
GetTickCount используется для инициализации ГПСЧ, то есть должна вызываться только один раз и обязательно где-то за пределами функции получения случайного числа. Да и заменить ее нечем, в винде не предусмотрено системных функций для получения случайных значений. Под MS-DOS была изумительная по лаконичности команда для получения случайного байта "in al,40h", а тут увы.
Grey
(01.10.2015 в 15:32):
Приклеил я эту функцию к Excel. Вызываю ее в ячейках, пока вызываешь в рукопашку - все путем. Поле протягивания дает одинаковые значения, вот копия с листа:
-2094149727
690108166
-702905294
-1496552323
464573972
1424549589 - тут началось протягивание
1114009017
1114009017
1114009017
1114009017
Я так понимаю это из за GetTickCount, чем ее заменить?
-2094149727
690108166
-702905294
-1496552323
464573972
1424549589 - тут началось протягивание
1114009017
1114009017
1114009017
1114009017
Я так понимаю это из за GetTickCount, чем ее заменить?
ManHunter
(12.12.2011 в 14:36):
Как зависит генерация от мощности компьютера? Не пиши ерунду.
Старк
(12.12.2011 в 14:34):
Этот генератор на мощном компьютере одно и тоже число выдавать не будет?
Fedor666
(02.06.2011 в 22:02):
Где, интересно знать, результаты тестов этого чуда? Ent? Deadhard :)
4RESTER
(27.10.2010 в 01:36):
Классический приличный RNG -- Mersenne Twister.
serega386
(20.09.2010 в 20:36):
proc WRandom
stdcall WBRandom
or edx, 80000000h
mov dword [randp1],eax
mov dword [randp1+4],edx
>>> fld1
>>> fld [randp1]
ret
endp
>>> для чего эти команды?
stdcall WBRandom
or edx, 80000000h
mov dword [randp1],eax
mov dword [randp1+4],edx
>>> fld1
>>> fld [randp1]
ret
endp
>>> для чего эти команды?
ManHunter
(17.05.2010 в 10:26):
Я его тестил на больших числах, там он конечно рулит.
Zummenix
(17.05.2010 в 09:41):
100 проходов, числа в диапазоне от 1 до 100:
62,30,63,53,66,41,67,11,61,4,85,28,65,73,10,83,4,6,86,32,43,25,62,54,3 6,64,60,69,97,79,43,13,56,68,64,93,23,14,94,28,72,60,8,65,52,7,62,53,4 6,17,53,83,24,45,13,65,48,60,71,44,27,70,39,9,22,24,24,56,80,93,32,55, 82,95,80,21,35,94,38,89,48,69,31,80,43,77,65,81,27,22,56,36,31,3,96,43 ,45,26,87,20
Очень даже неплохо, но некоторые числа повторяются, а некоторых вообще нет :)
62,30,63,53,66,41,67,11,61,4,85,28,65,73,10,83,4,6,86,32,43,25,62,54,3 6,64,60,69,97,79,43,13,56,68,64,93,23,14,94,28,72,60,8,65,52,7,62,53,4 6,17,53,83,24,45,13,65,48,60,71,44,27,70,39,9,22,24,24,56,80,93,32,55, 82,95,80,21,35,94,38,89,48,69,31,80,43,77,65,81,27,22,56,36,31,3,96,43 ,45,26,87,20
Очень даже неплохо, но некоторые числа повторяются, а некоторых вообще нет :)
Добавить комментарий
Заполните форму для добавления комментария