Pseudo random numbers / DOS / memory, etc....




Hi

I am a newbie, and I have made a program that generates some pseudo
random numbers, and print how many times each number come out.

I have two problems;

1. I am not sure the dynamic memory allocation is correct. I sometimes
get errors, sometimes not. Specially the free-mem part could be wrong, I
think. Is it correct what I do - pushing the address returned in ax by
function 48h/int21h and popping it to es in function 49h/int21h?

2. I have made my own implementation of "X = (XA+C) mod M", a Linear
Congruential Generator, but it doesn't really work well. The could very
well be something very wrong, I am only a newbie... ;-) and it is first
time I ever use dwords, so ... well, ... ;-)

I use some code from Tom Swans book about TASM to write strings, get
commandline parameters, etc, so just ignore that. Fell free to comment on
any part of the code, but I hope also to get some tips on the two issues
- memory and the fact that get_random4 is with some numbers.

And, it is written for a 8086 class computer running ms-dos 3.3, so
that's why I don't use 32 bit registers, etc.

Okay, the code:

=========== code start ================================

%TITLE "rs7.asm"

IDEAL
MODEL small
STACK 256

NUMTESTS = 10000

DATASEG
exCode DB 0
str_syntax DB ??FILENAME, "min max", 0
str_error1 DB "Error freeing unused mem", 0
str_error2 DB "Error allocating mem", 0
str_error3 DB "Error freeing allocated mem", 0
str_result DB 10 DUP(0)

UDATASEG
rand_result DW ?
rand_min DW ?
rand_max DW ?

CODESEG

;----> From PARAMS.OBJ
EXTRN ParamCount:Proc, GetParams:Proc, GetOneParam:Proc

EXTRN AscToBin:Proc, NumToAscii:Proc
EXTRN NewLine:Proc, StrWrite:Proc

;----> From RAND4.OBJ
EXTRN seed_random4:proc, get_random4:proc


;=========================================================================
Start:

;-------------------------------------------------------------------------
;----> release unused memory
;-------------------------------------------------------------------------

mov bx, es
mov ax, ss
sub ax, bx

mov cx, sp ;convert SP to paragraphs
shr cx, 4
inc cx
add ax, cx ;<- and then add here

mov bx, ax ;Release unused memory
mov ah, 4Ah
int 21h
jnc @@L1

mov di, offset str_error1
call StrWrite
jmp Exit

;-------------------------------------------------------------------------
;---->
;-------------------------------------------------------------------------

@@L1:
mov ax, @data ; Set ax to data segment
mov es, ax ; Set es to data segment
call GetParams ; Get parameters with ds = PSP
; ds is set from getparams

;-------------------------------------------------------------------------
;----> get cmdline parameters
;-------------------------------------------------------------------------

call ParamCount ; Get number of parameters
cmp dx, 2
je @@L3

mov di, offset str_syntax
call StrWrite
jmp Exit
@@L3:
xor cx, cx
call GetOneParam
call AscToBin
mov [rand_min], ax
inc cx

call GetOneParam
call AscToBin
mov [rand_max], ax

inc [rand_max]


;-------------------------------------------------------------------------
;----> find diff between min and max
;-------------------------------------------------------------------------

mov bx, [rand_max]
sub bx, [rand_min] ; number of words to allocate
shr bx, 3 ; number of paragraphs to allocate
inc bx

;-------------------------------------------------------------------------
;----> allocate memory
;-------------------------------------------------------------------------

mov ah, 48h ; size in bx
int 21h
jnc @@L5

mov di, offset str_error2
call StrWrite
jmp Exit

@@L5:

mov si, ax ; address of allocated memory
mov di, ax
push ax ; save - pop when freeing mem

;-------------------------------------------------------------------------
;----> clear allocated mem
;-------------------------------------------------------------------------

mov ax, 0
shl bx, 4
mov cx, bx
rep stosw ; write to es:di


;-------------------------------------------------------------------------
;----> start generating random numbers
;-------------------------------------------------------------------------

mov cx, NUMTESTS
call seed_random4

@@L10:
push cx
mov bx, [rand_max]
mov cx, [rand_min]

call get_random4

mov bx, dx
sub bx, [rand_min]
shl bx, 1

inc [word bx + si]
pop cx

loop @@L10


;-------------------------------------------------------------------------
;----> Write result to screen
;-------------------------------------------------------------------------

mov cx, [rand_max]
sub cx, [rand_min]
xor bx, bx

@@L20:
mov ax, [word bx + si]
push bx
push cx
mov bx, 10 ; prepare for NumToAscii
mov cx, 1
mov di, offset str_result
call NumToAscii
call StrWrite ; write to screen
call NewLine
pop cx
pop bx
add bx, 2
loop @@L20


;-------------------------------------------------------------------------
;----> free allocated memory
;-------------------------------------------------------------------------

mov ah, 49h
pop dx
mov es, dx
int 21h
jnc Exit

mov di, offset str_error3
call StrWrite


;-------------------------------------------------------------------------
;
;-------------------------------------------------------------------------
Exit:
mov ah, 04Ch ; DOS function: Exit program
mov al, [exCode] ; Return exit code value
int 21h ; Call DOS. Terminate program


END Start ; End of program / entry point


=============== code end ===================================


================ code start ===================================

%TITLE "rand4.asm"
IDEAL
MODEL small

DATASEG
num_a DD 1103515245
num_c DW 12345

UDATASEG

dd_result DD ?
rand_seed4 DW ?


CODESEG

PUBLIC seed_random4, get_random4

;------------------------------------------------------------------------
;
; GET_RANDOM
;
; x = (xa + c) mod 32768
;
; expect: bx = max
; cx = min
;
; return: dx = result
;
;------------------------------------------------------------------------

PROC get_random4

@@L10:
push cx
push bx

mov ax, [word num_a + 2] ; high word
mul [rand_seed4]

mov [word dd_result + 2], dx ; high word of result
mov [word dd_result], ax ; low word

mov ax, [word num_a] ; low word
mul [rand_seed4]

add [word dd_result + 2], dx ; add high word of result
add [word dd_result], ax ; add low word of result
adc [word dd_result + 2], 0 ; add carry

mov ax, [num_c]
add [word dd_result], ax ; + c

and [word dd_result], 7FFFh ; mod 32768

mov ax, [word dd_result]

or ax, ax
jnz @@L20
call seed_random4
jmp @@L10

@@L20:
mov [rand_seed4], ax ; 0 <= x < 32768

pop bx ; max
pop cx ; min

xor dx, dx ;
div bx
cmp dx, cx

jb @@L10 ; dx must be larger than min

@@L99:

ret

ENDP get_random4

;------------------------------------------------------------------------
;
; SEED_RANDOM
;
; return: seed in ax
;------------------------------------------------------------------------

PROC seed_random4

push bx
push cx
push dx
@@L10:
mov ah, 2Ch ;
int 21h ;

or dx, dx
jz @@L10

mov [rand_seed4], dx

pop dx
pop cx
pop bx

@@L99:
ret

ENDP seed_random4

END

============ code end ==================================



--
Thomas Jensen, Denmark
.