Как затравить для генерации случайных чисел?
Он не генерирует предполагаемую случайность.
Я подумал, что если начать с начального числа, например, $66, и запоминание двух последних младших битов и ror даст мне следующее случайное число и так далее, но оно показывает только $B3 и не меняется вообще.
Как я должен кормить? Строка над случайным отображает число на portc, так как я хочу, чтобы два числа отображались друг за другом.
Я использую только AVR Studio 4 для Atmega 8535 на 1 МГц.
> ;Program to random numbers on port C
>
> ;Stack and Stack Pointer Addresses .equ SPH =$3E
> ;High Byte Stack Pointer Address .equ SPL =$3D
> ;Low Byte Stack Pointer Address
>
> .equ RAMEND =$25F ;Stack Address
>
> ;Port Addresses
>
> .equ PORTC =$15 ;Port C Output Address
>
> .equ DDRC =$14 ;Port C Data Direction Register
> Address
>
> .equ numberoneddr=DDRC
>
> .equ numberoneport=portc
>
> .equ numbertwoddr=DDRC
>
> .equ numbertwoport=portc
>
> .equ delayCount=21
>
> .equ random1 =$66
>
> ;Register Definitions
>
> .def numberone =r1 ;Register to store data pointed
> to by Z
>
> .def numbertwo =r2
>
> .def temp =r16 ;Temporary storage register
>
>
>
> reset:
>
> ; initialize stack pointer. Done automatically at reset on many AVRs
>
> ldi temp, low (RAMEND)
>
> out spl, temp
>
> ldi temp, high (RAMEND)
>
> out sph, temp
>
>
>
>
> ;port initialisation
>
> ldi temp,$FF
>
> out numberoneddr,temp
>
> out numberoneport,temp
>
> out numbertwoddr,temp
>
> out numbertwoport,temp
>
>
>
> ;Program Initialisation
>
> ldi temp,$66
>
> rcall random
>
> mov numberone, temp
>
> out numberoneport,numberone
>
> rcall random
>
> mov numbertwo, temp
>
> out numberoneport,numbertwo
>
>
>
>
> random: mov r19,temp
>
> ldi r17, 0x01
>
> eor r19,r17
>
> ror r19
>
> mov temp,r19
>
> ret
>
>
>
> delay:
> clr r20
>
> clr r21
>
> ldi r22, delayCount
>
> loopDelay:
>
> dec r20
>
> brne loopDelay
>
> dec r21
>
> brne loopDelay
>
> dec r22
>
> brne loopDelay
>
> ret
1 ответ
После некоторого поиска в моих древних архивах исходного кода asm, я нашел это для платформы x86 MSDOS NASM, которую использовал в те дни:
;.rnd ;al=rnd num <0,ah>;
.rnd: pusha
mov cx,ax
.rnd0: mov bx,[cs:.rnddat]
mov ax,[cs:.rndtim]
xor al,bh
add ah,bh
rcr ax,3
xor al,bl
rcl ax,2
.rnd2: cmp al,ch
jbe .rnde
sub al,ch
or ch,ch
jnz .rnd2
sub al,al
.rnde: mov ah,bl
mov [cs:.rnddat],ax
or al,1
xor ax,[fs:046Ch]
add [cs:.rndtim],ax
popa
mov al,[cs:.rnddat]
ret
.rnddat:db 0,0
.rndtim:dw 0
Идея состоит в том, чтобы некоторый сохраненный номер выполнял некоторые базовые операции ALU, такие как +,*,/,<<,>>,&,^
но убедитесь, что насыщение не происходит и обычно происходит обмен H,L
некоторой ценности, чтобы держать случайность в узде. Так что перенесите это на ваш ассемблер, но я настоятельно рекомендую закодировать его и сначала попробовать на ПК, чтобы убедиться, что случайность подходит для вашей задачи.
Кстати, вы также можете использовать программную память или любое содержимое ПЗУ в качестве основы для случайности... это также использует внутренний блок RTC, поэтому вы должны пропустить эту часть или добавить таймер или просто перебрать кучу непустых данных.
[0000:046C] are 4 Bytes master clock count (long integer) 0 = midnight and increments until a 24 hour equiv.
Я нашел еще более старую демоверсию под названием NoSignal (с 1997 года в TASM), в которой есть rnd:
.386P
IDEAL
MODEL TINY
CODESEG
STARTUPCODE
main: mov ax,19 ;320*200*256
int 16
push 0A000h ;Video segment
pop es ;keyboard test,speaker delay v si=256
l0: ror ax,cl ;rnd...ax
add ax,di
stosw ;plot...
loop r1 ;speaker delay...
mov cx,si
out 61h,al
r1: or di,di
jnz l0
push ax
mov ah,1 ;test keyboard
int 16h
pop ax
jz l0
ende: sub ax,ax ;turn off speaker and exit
out 61h,al
int 16h
mov ax,3
int 16
ret
END
Он наполняет экран и динамик белым шумом, как будто в аналоговом телевизоре отсутствует антенный кабель. Эта версия длиной 44 байта, псевдослучайный генератор начинается с метки l0:
ax
является сгенерированным числом (а также предыдущим сгенерированным числом, таким как вы, темп)di
увеличивается (что-то вроде реального времени)...cl
уменьшается
так что, если я смотрю на это правильно, этого должно быть достаточно:
rnd:ror ax,cl ;rnd...ax
add ax,di
inc di
dec cl
ret
и добавить push/pop
сохранить регистры / значения, если это необходимо. Если вам нужно что-то более сложное, используйте простую арифметику по модулю.
[edit1] простой генератор C++ псевдослучайных данных
WORD rnd_d0=0x66; // these are seed numbers if not selected right then the randomness is not good
WORD rnd_d1=0x5A; // these give fairly good results
WORD rnd_d2=0xC3;
WORD rnd()
{
rnd_d0^=rnd_d1|rnd_d2; // xor
rnd_d1*=rnd_d2; // mul
rnd_d2+=rnd_d1; // add
rnd_d0=(rnd_d0<<8)|(rnd_d0>>8); // 8bit halves swap
return rnd_d0;
}
Вышеуказанные случайные генераторы были настроены на время среды DOS или специальное использование. Это не... случайность такая:
когда я использую его для заполнения окна изображения NoSignal, результат будет следующим:
а тут Gif анимация:
Код заполнения NoSignal выглядит так:
for (int y=0;y<ys;y++)
for (int x=0;x<xs;x++)
pyx[y][x]=0x00010101*int(rnd()>>8);
Так просто высоко 8bit
от 16bit
псевдослучайное число используется умножение просто преобразует это 8bit
число до серого цвета.
xs,ys
это размер изображенияpyx
прямой указатель изображения на его линии
Не меняйте начальные числа без надлежащего тестирования на ПК
Неправильно подобранные семена не приводят к случайности. Если вы хотите безопасно посеять (без тестирования), то посеять с предоставленными константами, а затем вызвать rnd()
столько раз, сколько у вас новое число семян. Разрушил это прямо сейчас, так что могут быть лучшие семена для этого, это только первые, которые я нашел, которые дают довольно хорошие результаты
Эти семена тоже хороши:
WORD rnd_d0=0x37A6;
WORD rnd_d1=0x377A;
WORD rnd_d2=0x3BC3;