How to seed to generate random numbers?

Solution 1:

After some searching through ancient asm source code archives of mine I found this for x86 MSDOS NASM platform I was using back in the days:

;.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

The idea is to have some stored number do some basic ALU operations like +,*,/,<<,>>,&,^ but ensure that no saturation occurs and usually swap of H,L of some value to keep the randomness in check. So port this to your asm but I strongly recommend to code it and try on PC first to see if the randomness is OK for your task.

BTW you can use also the program memory or any ROM content as base for randomness ... this is also exploiting the internal RTC block so you have to omit that part or add a timer or just loop through bunch of non empty data instead.

[0000:046C] are 4 Bytes master clock count (long integer) 0 = midnight and increments until a 24 hour equiv.

I found even older demo of mine called NoSignal (from 1997 in TASM) which have rnd inside:

    .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

It fill screen and speaker with white noise as if no antenna cable in analog TV. This version is 44 Bytes long, pseudo random generator starts at label l0:

  • ax is the generated number (and also the prevvious generated number like you temp)
  • di is incrementing (something like actual time)...
  • cl is decrementing

so if I look at it right it should be enough:

    rnd:ror ax,cl       ;rnd...ax
        add ax,di
        inc di
        dec cl
        ret

and add push/pop store the registers/values if needed. If you need something more sophisticated then use modulo prime arithmetics.

[edit1] simple C++ pseudo random generator

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;
    }

The above random generators was tighted to DOS environment time or special usage. This one is not ... the randomness is like this:

randomness graph

when I use it to fill NoSignal image window the result is this:

NoSignal

and here Gif animation:

NoSignal 320x240x3

The NoSignal fill code is as this:

 for (int y=0;y<ys;y++)
  for (int x=0;x<xs;x++)
   pyx[y][x]=0x00010101*int(rnd()>>8);

So just high 8bit from the 16bit pseudo random number is used the multiplication just converts this 8bit number to gray-scale color.

  • xs,ys is image size
  • pyx is the direct image pointer to its lines

Do not change the seed numbers without proper testing with this on PC

Wrongly selected seeds leads to no randomness at all. If you want to safely seed (without testing) then seed with provided constants and then call rnd() as much times as the new seed number of yours is. Busted this right now so there may be better seeds for this, these are just the first ones I found that gives fairly good results

These seeds are also good:

    WORD rnd_d0=0x37A6;
    WORD rnd_d1=0x377A;
    WORD rnd_d2=0x3BC3;